Most of this code dates back to 1998, when I built a little 2 player Joust game to push the bounds of what you could do with Div (and at the time Layer) tags in the latest browsers such as IE4 and Netscape 3. Surprisingly, most of it still worked when I thawed it out recently, provided your browser knew about document.all.
Over the weekend, I brought it up to date a bit and introduced it to Socket.io. Thus far it hasn't seen more than a dozen players at a time, so I'm curious to see what happens when a bunch of folks jump in at once.
I'll stick around to answer questions (and likely post-mortem the bits that catch on fire).
It's probably obvious for people who already played the game, but a quick note mentioning 'the highest one win' would make things easier for newcomers.
I was a bit confused about how to fight, before checking the wikipedia page
If you can figure out a way to only send inputs for each player instead of their full state, it should significantly reduce network traffic and lag for each player-- right now it's sending ~1KB/frame!
Yeah, 700b for 20 players, and normally at least somebody does something every tick, so that will go out 30 times per second. It still only works out to 24kbps, so you might not need to upgrade the modem you had back when the original was in the arcades.
I tried only sending updates every 3rd tick, but even there I could notice the difference.
You're right that it'd be worth experimenting with sending keystrokes instead, and backing off the full resync to once/second or so.
Desync is possible with UDP protocols, where a dropped packet would mean lost inputs, but this uses websockets, which are reliable TCP connections, so just the list of inputs combined with a deterministic engine is sufficient.
They can arrive out of order so you still have to deal with rewinding an re'simulating' the whole sequence of moves since the skipped packet then dealing with resolving the client vs server when they disagree.
That doesn't change that TCP packets can arrive out of order does it? (It's been a while since my college networking class and it's not something I come into contact with in my job)
It can also be used to mutate hard game state (I wouldn't try it with dynamic, interpolated values like object position, angle, acceleration, or velocity.)
There are many other methods, some are more precise and compressible than others:
This is superb, addicting as hell, and now I have to force myself to stop because I have real work to do.
The game gets increasingly jittery as it gets busier. It might be worth writing some tests to simulate lots of players moving around so it's easier to tune the performance.
Glancing at the code, it looks like he's rendering everything via DOM elements. I think player sprites are positioned using the top/left properties; could potentially optimize by keeping those props constant and just updating `transform: translate(x,y)` instead...
That's a holdout from 1998. Can't go changing things up after all that time, can we?
I imagine today I would have built the whole thing in canvas. But it's cool how quick you can get something up and running if you let the browser do most of the work.
I just joined for a quick session - just wanted to say that this is really fun and very well done (especially for someone who has played Joust before). Thanks for sharing!
I remember making a CGI (that's an ancient, simple server backend for the young-ins) IM chat in 1996. It used the keep connection open trick present in HTTP 1.0 and a tiny bit of Netscape JS.
You know I've been playing this for a week now, and until reading your comment it had never occurred to me to put a volumeNode in the middle of the webaudio path.
It's a little confusing when the name doesn't get dimmed or disappears when the player gets knocked off the bird. It's almost as if it's the name of the birds only, and the players are entirely nameless ;-)
Awesome. I loved Joust as a kid and spent countless hours playing it. Unfortunately the physics don't work as well as in the original. When you hit another player, the bounce is missing (and the egg, but I guess that's not important).
Thank you, that was an awesome bit of 5 minutes of nostalgia. I know it must have taken you hours to build, and I could only get a few minutes to play, but it was worth your effort, and thank you for sharing it here.
We encountered an error when trying to load your application and your page could not be served. Check the logs for your application in the App Platform dashboard.
Yeah, shame I wasn't around when this got popular (I actually submitted it on Tuesday, but HN must have automatically resurrected it for a second try).
The whole thing is running on a $5 Digital Ocean Apps server (well, two actually, one in New York, one in Frankfurt so that I can get low latency here in France), so it's amazing that it survived as long as it did.
Had I known it was going to get this much love, I would have spun up a dozen more servers.
I played only the coin-op version as a kid, so I never played competitively with other humans (the two-player version is more cooperative than competitive). It's a very different game against humans!
A suggestion: when you kill someone, you receive the points that they had (min 1). Have each player's point total hover around their sprite. This would set a higher bounty on the better/luckier players and balance the gameplay a little.
Yeah, I had to add a Suicide Button (q) for that. It does spawn checking for players and platforms, but there must be a bug there, since you can still get stuck.
I remember when this came out. I had travel planned to NYC and made a stop at the install location to check it out. It was closed.
Fortunately, Portland got one at Ground Kontrol not long after. It was a lot of fun recruiting new people to try and fill in all 10 spots. It was pretty funny when a snail win got close and people started chanting “snail! Snail! Snail!”
I tried a tournament and had less fun. The game needed balancing and it took some time to get out there.
Still, very cool it evolved from a physical game.
Iirc, some valley-based startups bought some of the original cabinets. Anyone know which?
Amazing work. Childhood vibes were seriously kicking in while playing this. Now if only I could get my brother here to constantly yell at me to stop cheating it would really bring me back.
I just played on my pc and the only issue I encountered was a noticeable amount of lag.
Gravity is just a constant acceleration downward, so nothing special there.
I have the footstep sounds ready to go, but I found that I really needed to limit what sounds I played because they get overwhelming pretty quickly. There's now a pretty tight radius to the player for what gets played.
First cut was to have all 200 players' flapping sounds audible to everybody. That was suboptimal...
> We encountered an error when trying to load your application and your page could not be served. Check the logs for your application in the App Platform dashboard.
Yeah, mobile safari is annoying in that it doesn't allow fullscreen mode for anything except video. And that it doesn't always leave you in a consistent scroll state or with knowledge of how much screen is visible. So the left/right buttons drop off the screen unless you scroll it a bit before hitting start.
Came to say the same about the original iPhone SE. I thought it was because mine is a smaller model (most sites look weird on it these days). But now I guess that's not the reason.
Wow, what a throwback. Haven't played it in 30+ years but was surprised to find myself trying old tactics immediately. (Too bad "ceiling" bouncing doesn't work, or maybe it's just the lag.)
Very cool! Bug: sometimes my ostrich would stop walking. I could even press the arrow key pointing the opposite direction. The sprite would change to face the new direction but keep moving in the old direction.
Thank you! Joust was a sort of second-tier video game back in the day and I felt it never got quite the love it deserved. I bought the Sony PSP solely for its implementation. This is wonderful.
I had a lot of fun, but there's a big incentive to hit idle players. I would suggest making players intangible until receiving their first input on respawn.
Robotron got a fantastic port for the 2600 recently [0] (WIP). It supports twin-stick mode but that's pretty unusable on original Atari controllers without a special rig. Genesis controllers work on the 2600 and I've been trying to convince them to add a configuration like Smash TV did for NES (sideways controller in each hand, D-Pads only) but no one knows what I'm talking about. It was such a comfortable way to play twin-stick and with the Four Score you could even play 2 player.
How do I win in this game? You should include some instructions so that newcomers can enjoy the game instead of being confused. Also, I have a fast connection, yet I experience massive delays during the game. Great work though, thanks for making me try this game.
Over the weekend, I brought it up to date a bit and introduced it to Socket.io. Thus far it hasn't seen more than a dozen players at a time, so I'm curious to see what happens when a bunch of folks jump in at once.
I'll stick around to answer questions (and likely post-mortem the bits that catch on fire).