10 ms·
Show HN: Space Invaders in C
- hoseja 7y agoToo bad that for a lot of newer games, the source will never be released. We need abandonware Indiana Jones.
- jacquesm 7y agoIt's not like the source for this one was released, this is a re-enactment rather than the original source. But back then the software was compact enough to allow reverse engineering to the point that you could re-implement it faithfully.
- loadzero 7y agoAuthor here. This is a bit of a love letter to Space Invaders, and video games in general. I started working on this as a simple emulation project, to rekindle my own passion in low level video game hacking, but then realized with a bit of care I could take it further. So, this is not a simple clone of the game, but rather a painstaking recreation of the source code in clean, readable C code. I wanted to make something nice that would last a while, as a tribute to the original, and hopefully function a bit like a rosetta stone for future audiences. Enjoy.
- tombert 7y agoI have to ask an honest question (as someone who is interested in emulation and old-game restoration as a whole): why C? Did you consider a newer hacker-news-friendly language like D or Rust? (my usual disclaimer: I'm not asking this passive aggressively, I'm genuinely interested in the answer to this).
- mrfredward 7y agoI'm obviously not the author, but I can think of a good reason not to use rust. The project works exactly as the original and recreates the memory state byte for byte, so like the original it has different tasks running at once that are reading and writing to shared memory. Rust's borrow check exists to prevent this sort of thing, because it is so hard to do it correctly or prove it is correct once you have done it. So to use rust, the author would have needed to either totally re-architect Space Invaders, or write the whole thing in ugly, non-idiomatic rust. Rust simply doesn't let you do the things assembly and C programmers did all the time in 1978 (and with the complexity of our software now and the extra computing power, that's usually for the better). C, on the other hand, has at times been described as "portable assembly," which makes it a good choice for someone wanting to stay true to the original program flow.
- loadzero 7y agoThis is a good answer, and does reflect a good chunk of the reason for picking C. Dealing with such low level tasks is what the language was made for. The other big reason I used C, is that it is more of a lingua franca than something more modern, and will make the code more accessible to a wider audience.
- pcwalton 7y ago> Rust simply doesn't let you do the things assembly and C programmers did all the time in 1978 (and with the complexity of our software now and the extra computing power, that's usually for the better). Rust does let you do those things. You could run this repo through c2rust and get a working Rust program. It'll be ugly Rust code, though.
- KibbutzDalia 7y agoHere come the Rust Invaders!
- _sbrk 7y agoI'm a hacker-news reader and I use C on a daily basis. Seems pretty friendly to me. Every language has a problem that it is good at solving, and some languages express the underlying idea more clearly than others. In this case, the author has done a bang-up job picking a common, everyday language to solve the problem.
- fortran77 7y agoWell, it wouldn't have been "Space Invaders in C" if he had used Rust.
- CamperBob2 7y agoLooking through your code, the text character set seems to be coming from the original ROM image. Is that correct? What I thought was interesting was that the glyphs appear 100% identical to the original Apple II character set, down to the pixel. Was there some kind of unexplored connection between Space Invaders and Apple, back in the day?
- loadzero 7y agoYes, it is coming from the ROM. Well spotted, it looks like you are right. A quick glance here https://computerarcheology.com/Arcade/SpaceInvaders/Code.html#text-character-sprites https://computerarcheology.com/Arcade/SpaceInvaders/Code.htm... and here https://www.fontzip.com/apple-ii-screen-typeface https://www.fontzip.com/apple-ii-screen-typeface Shows a distinct similarity.
- guiambros 7y agoAmazing work, thank you for sharing! The amount of detail is prey impressive. How hard would it be to port the sound as well?
- loadzero 7y agoGood question. The sound is a hardware component (synth circuit) that I haven't looked into much, because it's essentially outside the game code. si78c is faithfully sending all the right bits to the right port, but the hardware component would have to be emulated to get it going. The relevant code could most likely be borrowed from MAME.
- tyingq 7y agoProbably this and the corresponding cpp file: https://github.com/mamedev/mame/blob/master/src/devices/sound/sn76477.h https://github.com/mamedev/mame/blob/master/src/devices/soun... Emulates the TI SN76477 sound chip.
- theunamedguy 7y agoExcellent work! Clean C is underrated nowadays.
- FullyFunctional 7y agoI love it. Thanks for doing this. How long did it take you? How did you verify the memory accuracy? It sounds like you co-simulated your implementation with the emulation?
- loadzero 7y agoYes, I ran with the original in lockstep and confirmed the same reads and writes were occurring.
- loadzero 7y agoIt felt like it took forever. But about 200 hours all up, over a few months.
- matsemann 7y agoI'd like to read more about this setup!
- loadzero 7y agoYeah, there's probably a good article or two in that. Cliff notes: It's basically an extension of the Dual CPU setup mentioned in http://www.gtoal.com/sbt/ http://www.gtoal.com/sbt/ In that article, Graham Toal discusses a hack where you can bootstrap a new emulator core from an existing one by making a custom emulator that drives both cores at the same time. After each clock tick, you check the states of both processors for divergence and halt with the diff if there is one.
- jonny383 7y agoHats off, very cool!!! I have always dreamed of building a classic ROM to C transpiler for native, portable, future-proof(ish) binary builds (just like this).
- i_am_not_elon 7y agoBoth the project and the writeup are awesome, Jason! Thank you for sharing - I enjoyed it!
- thenewnewguy 7y agoSomewhat off-topic rant, but why do websites display long videos as GIFs? Is there some size or compatibility benefit? Because it's really annoying to not be able to pause or rewind these GIFs that take the place of where a video would usually be. Also, get an HTTPS certificate friend, it's 2019. Dreamhost provides LE certs literally for free.
- app4soft 7y ago> but why do websites display long videos as GIFs? Because for GIF playback no need any video player plug-in in browser.
- thenewnewguy 7y agohttps://caniuse.com/#feat=video https://caniuse.com/#feat=video
- kick 7y agoFirefox already has the video player control interface for gifs; you just have to right-click. HTTPS is unnecessary for this site.
- thenewnewguy 7y ago> Firefox already has the video player control interface for gifs; you just have to right-click. And do what? I'm using (latest stable) FF but nothing in the right click menu seems to allow me to control playback. > HTTPS is unnecessary for this site. A: HTTPS prevents your website from being defaced B: I care about protecting the privacy of which websites and web pages I visit - even if you don't C: The website hosts the author's PGP key
- gwd 7y agoD: The more internet data is encrypted, the less encrypted data stands out. I.e., if you only encrypt data when it's important nobody listen, everyone can tell when you're doing something you don't want anyone to hear. If you encrypt data all the time, nobody can tell "secret" from "normal".
- app4soft 7y ago> as long as they support ucontext and SDL2 Why not SDL1.x? It would be more portable, What about Symbian support?[0] [0] http://anotherguest.se/ http://anotherguest.se/
- jacquesm 7y agoInteresting metrics, you'd expect C to do a lot better in the line-count department than assembly. I tried building it on Ubuntu, if you follow the instructions the SDL library include files will end up in a directory called SDL so you have to include SDL/SDL.h and even then the build fails with lots of SDL related definitions missing (SDL_Window for instance). That's because you really should be doing sudo apt-get install libsdl2-dev Then change the include file line to #include <SDL2/SDL.h> and type: make The roms can be found here: http://www.freevintagegames.com/MAME/invaders.php http://www.freevintagegames.com/MAME/invaders.php After downloading you'll have to rename the files because the names will all be uppercase: cd inv1 mv INVADERS.E invaders.e mv INVADERS.F invaders.f mv INVADERS.G invaders.g mv INVADERS.H invaders.h cd .. Now the game should work: ./bin/si78c Some minor nitpicks about the code: - bracket your ifs and place the starting { on the same line as if/while, or one day you'll sit there staring at the screen for 8 hours trying to figure out why your code no longer works due to an accidentally deleted line. So: while (num < 64) { int has = SDL_PollEvent(&event_buffer[num]); if (!has) break; num++; } becomes: while (num < 64) { if (SDL_PollEvent(&event_buffer[num])) { break; } num++; } Neat project!
- loadzero 7y agoThanks for pulling the code and trying it out, jacquesm! That kind of feedback is gold. I have updated the README with the correct Ubuntu package details. I think the issue with the includes is likely to do with having both SDL1 and 2 installed, and the slightly dirty way I am pulling in the header (so it works on Mac too). I will have a bit of a think about how best to resolve that issue, likely needs some ifdefing.
- pvg 7y agoyou'd expect C to do a lot better in the line-count department You would but it's worth keeping in mind this implementation is constrained by closely following the structure and logic of the original. It's like writing C but being told exactly what state you have to maintain (and where), down to the bit, in advance. It really is a 'hardware simulator' where the spec and input handed to you is the sequence of memory states (and a few other bits) of the original machine.
- joosters 7y agoA build process of ‘make 2>/dev/null’ is an ominous sign for any project...
- deleted 7y ago[deleted]
- nikconwell 7y agoGreat write up, thanks. I was intrigued by the "tilt" keymapping on the last line of your posting. https://computerarcheology.com/Arcade/SpaceInvaders/ https://computerarcheology.com/Arcade/SpaceInvaders/ notes: > In the early eighties you would have found the Space Invaders cabinet in an arcade right next to the pinball machines. So a "tilt" switch, like you would find in a pinball machine, would not have seemed as strange as it does today. If you shake, slap, or otherwise physically abuse an SI cabinet you will get a TILT message and your game will end.
- LegitShady 7y agoPlease don't use code blocks for quotes it breaks line wrapping on mobile.
- computerex 7y agoIt seems to break line wrappings, period. The breaking doesn't appear to be mobile specific, the quote appears as a single line on my laptop.
- remarkEon 7y agoIncidentally I’ve never seen this implementation come out in a friendly way. Might be good just to turn it off tbh.
- LegitShady 7y agoNoted.
- microcolonel 7y agoWhen somebody who isn't pg learns ARC, maybe they will fix the URL parser, and add standard quote syntax.
- kick 7y agoHN stopped releasing source ages ago. There's a community-maintained fork, but the site we're currently using is opaque.
- Tepix 7y agoIf you like this kind of thing, there's also a faithful re-implementation of the original Elite game, with (readable) source code. Quoting Wikipedia: "... around 1999 Christian Pinder developed Elite: The New Kind as a modern PC port of the original BBC Micro version. He achieved a faithful port by reverse-engineering the original assembly written BBC Micro version and recreating a platform neutral C code variant from it, but at David Braben's request this version was withdrawn from distribution in 2003. In September 2014, on Elite's 30th birthday, Ian Bell blessed Elite: The New Kind and re-released it for free on his website. Since then, Elite: The New Kind is also distributed again in version 1.1 by Christian Pinder; a source code mirror is hosted on GitHub." Link: https://github.com/fesh0r/newkind https://github.com/fesh0r/newkind
- cptnapalm 7y agoThere's a crash bug in the source: when the local star is to be rendered, the game crashes because it tried to explode the star. There are a couple of forks that solve that rather glaring issue, however I don't recall if they're in a playable state themselves.
- Tepix 7y agoI see. I noticed that the source code repository contains version 1.0 but the latest binary version is 1.1.
- jimws 7y agoThis is an awesome project with awesome write up. I miss the days of pixelated console games. The constrained environment led to so much creativity. Are there any new games like this being written anymore?
- speps 7y agoCheck out the PICO-8 ecosystem: https://www.lexaloffle.com/pico-8.php https://www.lexaloffle.com/pico-8.php
- jonathanzufi 7y agoThis is magnificent. Thank you for doing this.
- bachmeier 7y agoIs this open source? I don't see a license with the code, but maybe I missed it.
- loadzero 7y agoIt most likely will be, I have not decided upon a license yet.
- ddtaylor 7y ago> Error code: MOZILLA_PKIX_ERROR_SELF_SIGNED_CERT Not accessible where HTTPS is required here is a mirror that has SSL https://archive.is/E6y37 https://archive.is/E6y37
- deleted 7y ago[deleted]
- ianai 7y agoOh I really appreciate having a neat, complicated C program to explore and learn from! Could this be done for Galaga? That’s my personal favorite.
- loadzero 7y agoLooks like someone is doing it: https://github.com/neiderm/arcade/ https://github.com/neiderm/arcade/ Don't know if it's finished though - Galaga would be about 10 times harder to do than this project.
- ZeroGravitas 7y agoThe white invaders on a black background was iconic in my childhood, so I was kind of blown away when I first saw a real arcade machine with the painted backdrop and the screen reflected over it with a half silvered mirror (or whatever crazy tech they used in those days).
- donpdonp 7y agoThank you for posting this! Me too! I was at a local arcade and came across a real/original spaceinvader cabinet and I was floored at how much of the experience is not captured by an emulator on a laptop. The silvered screen layer is very eye catching and the sound - so much bass really adds to the experience of the dropping invaders.
- zoomablemind 7y agoNice job! Such a pleasure to read a clean C code. BTW, in case anyone tries to build it on Ubuntu 14.04 x86 with gcc, you'd need `-std=gnu99 -D_GNU_SOURCE` flags, otherwise it barks about stack_t in ucontext.
- veganjay 7y agoThanks for posting this - I also needed this flag on Ubuntu 16.04 64-bit
- vagab0nd 7y agoStory time: I wrote an 8080 emulator to play the Space Invaders. I implemented just enough instructions so I could play the game. Problem was, the game's title screen would show, but after a few seconds, it would immediately jump back to the beginning. First I thought "oh I must have implemented an instruction wrong". So I re-checked all the instructions, read through the Intel 8080 programming manual multiple times. I did find a few errors related to the carry flag, but fixing them didn't change anything. I then started to actually debug the game code. This was significantly harder than I'd expected. Since the game was in assembly, it was not obvious what each instruction did. What I had to do was pretty much annotate each and every instruction, along with all the memory locations. E.g. address 0xABCD is for player score, 0xCDEF is for player position, instruction X is for drawing the bunker, etc. It was truly a pain, but it paid off. So the game had an interrupt handler registered to the display refresh signal. And I finally realized the game was constantly interrupted when it was not supposed to. Turns out I had forgotten to disable the signal when entering the handler. I fixed it, and it ran perfectly.
- avip 7y agoWas able to build for alpine, but I get a segfault on running.
- arrakeen 7y agosee also Cannonball, which I discovered recently—a reimplementation and improvement of OutRun https://github.com/djyt/cannonball https://github.com/djyt/cannonball
- rootVIII 7y agoreally cool