98 comments

[ 4.3 ms ] story [ 216 ms ] thread
This is excellent. Sokol is so very elegant compared to alternatives.
Between this, Elden Ring, and my rediscovery of FFXIV, I now firmly believe there's a global conspiracy to stop me from doing a single minute of work.
Hi, have you meet Wordle? :)
But Wordle takes what 15 minutes of your day?
(comment deleted)
Not even for the average HN user.
It's not just Wordle proper, though, it's all the variants...Nerdle, Worldle, Heardle, Dordle/Quordle/Octordle/etc...
I was doing it daily for a while. For some reason the acquisition news made me stop, or maybe it was just the timing. Maybe it's time to get back into the zone.
Hi, have you meet Semantle? :)
(comment deleted)
Wow, this is neat.
Cool project!

Was this inspired by Golf with Your Friends? I've been playing that a fair bit, it's pretty fun and good value.

looks like it doesn't (yet?) have networking support. my fiancée plays GFW almost daily after it was on sale recently, it's a fantastic casual to play both with friends or with strangers online, pretty chill community
After spending my career working in higher level languages, I'm always impressed by what people can do with languages like C. It's not just for drivers anymore.
Once upon a time such kind of games used to be done in C, after being done several years in Assembly, hardly anything to be amazed.
It used to be the norm to write games in C. In fact it used to be the norm to write them in assembly, C was seen as a higher level abstraction that sped up games development once upon a time.
There's a good Diablo 1 "making of" video, the lead developer talks about learning C while coding the game in assembly. I'll try to find it.
Yeah, I'm pretty sure most game devs of that era were doing something similar. It seems that once games went 3D, it was too impractical to do assembly anymore. So basically a lot of early PS1/N64/Saturn games were likely some pretty rough C code if I had to guess.
It's less that but that the C tooling matured to the point where it was actually good enough to use. Particularly in terms of good enough output. Tight loops and often called functions were and sometimes still are (in SIMD terms) written in assembly so they could be hand optimized.

More exotic hardware also relied on the vendors providing a C compiler and the quality there could vary wildly.

It was never just for drivers. Most of what you use in high-level languages is just syntactical sugar for things that might take three lines in C instead of one line in your usual language.
Three uncorrelated lines, two of which take a buffer, length pair which is also uncorrelated, calling something with undefined behavior if the buffer and length aren't the correct pairing.

But yes.

(comment deleted)
Any recommendations to learn to build cross-platform games like this?

I work on frontend projects day-to-day. I'd love to build a simple cross-platform game in C/Zig/C++ for some variety and to learn lower-level programming.

I've looked at Handmade Hero in the past but its specific to Windows at the moment.

Handmade Hero gives good advice how to modularize to make a game portable. For many things you want to achieve, you can have the platform call the game instead of the other way around. Essentially it's (asynchronous) event driven architecture which enforces modularization.

Think of a system as shipping data packets around, then it should be much easier to see how to swap out the platform parts.

This might be obvious, but one of the key activities is to minimize platform-dependent code so that most of the game logic is portable and shared across all platforms. So no Win32-isms or Cocoa-isms or <unistd.h> littered all over your game.

One way (out of many) to do this is have a cross-platform interface for each non-portable thing, with separate platform-specific implementation files that you swap in depending on which platform build you're doing. For example, if your game has sound, you'll probably have a platform-independent sound.h the rest of the game calls into, and then sound_windows.c, sound_linux.c, sound_mac.c, etc. files that contain the platform-specific implementations of those functions. Repeat for graphics, input, and other things that cannot be done (or you don't want to do) in a portable way.

Another thing is the game loop. Back in the DOS days, when you were the only thing running on the system, you implement main() did something like:

    while (game_running) { do_everything(); }
Modern platforms expect to be in the driver seat, and will instead call into your code, so this turns into something like:

    function windows_call_me_please() {
        do_everything();
    }
Obviously this is a simplification, and there is a lot more to it, but hopefully it answers some basic questions.
Bonus points for the suggestion of using module_platform.c instead of #ifdef spaghetti.
Also choosing a base platform agnostic framework like SDL which has a lot of the OS interactions (keyboard & mouse) already abstracted away for you gets you pretty far on the cross-platform road.
It's all about the libraries. Use Sokol and Dear Imgui and you'll be cross platform.
It’s 99% due to nostalgia but look at chocolate doom. It’s a tightly coded 2.5D game. There’s TONS of documentation on how it works. Recreating the engine in a familiar language and playing the WADs of you childhood is fun. But if you want 3d with OpenGL maybe look at quake. That’s how I learned GL.
Read everything on James Hague's "programming in the twenty first century", but start with "Living Inside Your Own Black Box":

https://prog21.dadgum.com/66.html

Libraries can be helpful. But at the baseline, what you have to solve is the problem of adjusting your dependency load such that adding new target platforms is a matter of rewriting small details, which means taking a language-designer's view of your system and saying "OK, if I need to automate the rewrite, then I need a compilation mechanism". Sometimes you have to change asset formats or runtime I/O mechanisms, but you can select what layer of the design you are aiming to standardize and go from there. e.g. records of chess games have a few defined formats. They don't need to track the assets used to draw the board, or the account information of the players.

If what you want is all of it: every pixel and frame of output the same, all input devices treated identically across all environments, then you'll gravitate towards a VM type of design, like Another World, Z-Machine or SCUMM, to name three well-known examples of such a design.

This is excellent. Can I suggest a couple of improvements?

1. Maybe have a "par" for each hole.

2. Be able to better see the layout of multi-level holes, i.e. the ones with slopes.

Other than that this is a really nice lunchtime distraction.

Loved it, and would concur that having a better sense of what the hole looks like from above before the shot (or being able to click to see the hole from above like a map) would be awesome. But, I loved playing it. And, I sucked.
I'm only now realizing how insanely erotic my last comment was....
Seems really great, I played all the way through. Here's a couple low-hanging QOL suggestions:

* Use right-click for the camera control, rather than left-click away from the ball. It's unnerving to have the camera change while you're trying to line up a shot.

* Show a shot counter, and assign each hole a par.

* Slightly tune down the friction. I had the ball stop dead on slopes a couple of times, and it stopped way earlier than I expected on slower shots.

Nice.

Perhaps a level generator based on some ascii art or something would be nice.

That way more people could add levels in merge requests. Or even add a level loader where you can import a list of those levels.

I'd love to hear more about the lightmapping interpolation for moving objects. I wonder what kinds of efficiencies the author had to find to make it performant.
I tried to analyze the running app with the Firefox dev console, but the GitHub hosted page said there were no sources!

Browsing the Sokol Github, it looks like it's compiling to web assembly. I'm not very familiar with web assembly, how does one normally debug it?

(comment deleted)
With the sokol libs as platform abstraction it works quite well to develop and debug a native build in a regular C/C++ IDE and then only cross-compile to WASM. Most bugs are platform agnostic and would also happen in the native build. For the rare case that problems only happen in the WASM build, regular printf-debugging usually works well enough, or in case of WebGL specific problems there will be validation errors on the JS console from the browser's WebGL implementation).

(disclaimer: sokol author)

I haven't tried it but Chrome dev tools supports debugging C++ compiled to WASM with DWARF debug symbols.
Just to be clear, folks, this isn’t my project. I saw this in /r/programming and it looked interesting, so I thought I’d share with you guys.
Impressive to see C being able to create x-plat 3D games that run in Browser + popular Desktop + Mobile OS's.

Typically there's big companies with large dev teams working on accomplishing such a feat & this project does it with with a 50 year old language and a handful of libs

What's the TLDR on how to compile the C code to run in the browser?
Emscripten. If you use something like SDL porting is trivial.

Working on a project to port a 20 plus year old c/cpp code base to the web. The tooling was like 98% there but I've had to upstream a few fixes or find a workaround every now and then.

Good on you man. If I got an email that said “opportunity: port 20+ cpp app to web” I would chuckle and close that sucker real quick. Modern cpp I maybe can deal with. That 90s stuff is real bad.
It's actually a purely voluntary endeavor. I'm attempting to port a game engine called Zelda Classic to the web. So far, so good!
Not to diminish the value of their efforts, welcome to the days of 16 bit game programming, naturally minus the browser part.

Plenty of retrogaming stuff to learn from.

(comment deleted)
Cross-platform except for MacOS

https://github.com/mgerdes/Open-Golf/issues/3

(comment deleted)
Builds and runs well in Asahi Linux :) Frame rate isn't great without GPU support, but totally playable.
Absolutely crazy that Asahi Linux beats MacOS on even one silly datapoint of compatibility lol. Open source is sick.
TBF, the only reason why macOS isn't currently supported seems to be some minor build system details (e.g. the toplevel CMakeLists.txt file has explicit support for Windows, Linux, Android, iOS and Emscripten, but not macOS).
They seem to have a build script for "OSX" but maybe it's just incomplete / work-in-progress? It uses glfw, which I know for sure still runs on Mac because I use it in my own cross-platform graphics projects.
Web Inspector on Safari showing failure: "Worker load was blocked by Cross-Origin-Embedder-Policy"
Works fine on MacOS on Chrome, just not Safari.
Looks like that issue has now fixed by the author
It's great, but the hole is too wide.

The ball shouldn't go in easily if you hit too hard.

Very nice simple golf game. Refreshing on mobile where there's nothing but the game :)
Odd. I couldn't get it to work on Edge, Chrome, or Firefox on Android.
Kind of looks like neverball/neverputt (https://neverball.org/).
Neverball also has a browser version that's compiled directly from the C code. (Shameless plug, I'm one of the developers.)

https://neverball.github.io/

It is remarkable to me that, once I’m in full screen mode and into a level, I can’t tell that this isn’t the desktop version. All the same crispness and responsiveness is there. I probably knew in my mind that this is possible these days, but every bit of muscle memory I apply here is telling me that Wasm, Emscripten, etc have become quite good, in a way that an unfamiliar game couldn’t tell me.

Thanks for giving me an easier way to share this good old game with friends!

Are you the same Penwielder who made Penwielders Scrapbook (a Neverball level)? I seem to have an uncanny memory of usernames from the old Neverball forum. Anyway, your name inspired me to find that level and add it to the in-game downloads.
How many changes to the C code are required for this sort of thing?
That depends on the code. Neverball has acquired a high level of portability thanks in large part to SDL2 and OpenGL (ES). So compiling to Emscripten was mostly about rearranging the pieces that were already there. My original patch was surprisingly small. (https://github.com/Neverball/neverball/commit/517c93b7bcf63f...) I would say I spent more time on integration with browser APIs, so it would behave and feel more like a web app.
Would be nice if some of this stuff were part of the toolchain/stdlib so it would be closer to a simple recompile.
Lots of fun. Then I got to level 12... :)
Level 20, but wish there were more. The fun ones were trying to skip most of the course from the tee. Throw a leaderboard on there and no one's going to be working.

Great work, awesome orchestration of cross platform libs.

I think the game not having an online component is one of its charms. Simplicity in nature and execution is the obvious goal.

Have you seen the leaderboards of any online game lately? They usually get wrecked by cheaters and defeat the whole purpose.

waiting for the first post that says this should have been written in rust
I'm waiting for the "programming language in the title = clickbait" crowd
They only show up when said language is rust.
Why "Works best with Chrome?" It works fine for me in Firefox.