Jump to content
IGNORED

Lava: raycasting, kind of


scrottie

Recommended Posts

Hi everyone,

I've been lurking for a long time but thought I'd actually out myself since people were talking about raycasting with and without the ARM coprocessor. I had the idea a few years back to try to exactly that, and make a first person perspective Joust style game. This is where it's at right now:

http://youtu.be/xbH6sZp0_kc

Okay, technically, it isn't raycasting, althought it would be fun to attempt exactly that: during the display kernel, look up the fractional value of the angle that the that scan line's ray is shooting off at (platforms are up-down, not left-right like walls, which is a better fit for the hardware, as you all know), trace a ray off but stepping one unit out and the fractal amount up or down, count the number of steps, and make that piece of platform that wide. To do that, it would probably several scanlines to actually figure out how wide (far away) of a line to draw next depending on how many boxes it iterated through before giving up looking for a wall/platform. That also assumes no rotation so that it is going only straight ahead plus up and down a little each step (depending on which scan line it is drawing).

Anyway, that's what I didn't do (but maybe should have). I decided (perhaps wrongly) that that would be too slow, and the platforms should have good Y resolution (single scanline, preferably), and I could optimize for sparseness by drawing platforms from near to far away until I can out of CPU to render them, then just stop. Drawing platform by platform instead of scanline by scanline requires a frame buffer. Actually, honestly, my first idea was "I wonder if I used a framebuffer if I could render 3D stuff in it during vblank", which is pricesely what I've done.

The frame buffer is composed of all of the 128 bytes of RAM that aren't allocated for the player's X/Y position, players fractional X/Y position, X/Y velocity, enemy X/Y position, enemy fractional X/Y position, enemy X/Y velocity, and a few temps that get heavily reused through the code, a byte to remember the calling routine to use in place of a single level of return stack, and five bytes used during rendering. In total, rendering requires 7 bytes. That leaves 107 bytes for the frame buffer, which means that the viewport is 107 lines high.

Each line of frame buffer includes 5 bits for how wide that piece of platform is (distintance dictates how wide platforms get drawn, so really width doubles as the Z-buffer when rendering platforms during vblank) and three bits of color information for that platform. If the color bits are %000....., then the kernel branches to logic that updates enemy sprite pattern (GRP0) data instead of platform data (PF* and CULUBK). It glitches a bit by starting drawing platforms late when the enemy is just on the very top/start of a platform by not drawing right away. Enemies are drawn into the frame buffer the same way the platforms are, using Z-buffering (looking at what's there and not drawing the thing unless it's closer than the thing already there). Enemy sprite pattern updates are drawn individual so near by enemies can have enemy pattern updates interspersed in the frame buffer with platform width updates.

Platform rendering works like so:

* Clear the framebuffer
* Start at the end of the nearest platform in the level that the plat can actually see, looping over each further away platform until vblank time runs out (it's glitching right now by not checking for enough time remaining on the timer somewhere; I have to tweak those constantly)
* For each platform, loop from the farthest away Z value to the closest one, drawing each line (subject to Z buffering rules)
* If there's a gap between the last (horizontal) line drawn and this one, fill in the gap, again, using Z buffer rules

When computing distance, it uses a pre-computed arctangent table, indexed by the most significant 4 bits of Y and most significant 4 bits of Z.

Rendering has to at various points check how much time is left on the timer and just bail to wait for the start of drawing when it gets low on time. There's a macro for that. It also checks to see if it's out of time before varoius video control signals but resumes rendering afterwards, using one byte to keep track of where it's at in video signaling.

That's a much more traditional 3D rendering setup (sans any sort of rotation) than ray casting. It's also really just rendering 2D: Y (up-down) and Z (depth) with no X (side to side).

Right now, collision detection with platforms (hitting it in from, from the bottom, or landing on it) is there but collision with the enemy and any game rules aren't there yet. There's no title screen or music. I have 12 extra cycles in the kernel to play with and the kernel runs every lane (though it can take one of two different paths). Assembled game uses ROM up to $fcad. Level definitions are compact. There's only one level and no win condition or score.

Hopping between platforms kind of feels like a game of "the floor is made of lava", so I kind of want to call it that... even though I haven't actually added Joust's lava yet. I'm thinking that adding "ground effect" to flight (where you get a lot more lift when you're near the ground, like airplanes in real life experience) and otherwise have flight be very weak could add to that effect, where if you don't kind of platformer it between platforms, you risk falling into the lava.

Code is here:

https://github.com/scrottie/2600lava

Bin is here:

http://slowass.net/~scott/tmp/newbies.bin

Feedback welcome!

newbies.bin

Edited by scrottie
  • Like 1
Link to comment
Share on other sites

Are you whom SpiceWare is writing the ARM tutorials for in his Blog?

 

A new gameplay engine you are making (that looks like one of those cool demos) is very exciting!

I'd love to play with stuff the bus with an ARM, or an FPGA. Maybe my next effort will revolve around that.

 

I've got some simple shading going on the platforms, but this demo (I forget which I grabbed that screenshot from) has way better shading, and texturing. I'd love to steal that, but they've got two colors going on the same line and I'd need three, and enemy birds might wind up in PF*, which wouldn't be all bad since then they could potentially be much larger. Not sure how I'd juggle that. Stuff people do blows me away.

post-17952-0-71760900-1425171592_thumb.png

Edited by scrottie
Link to comment
Share on other sites

Nice demo. It's a very interesting approach. I wonder how it would look if you reduced the vertical resolution to 96 lines and drew each line twice to fill out the screen. Maybe that would be possible if you moved more of the processing to the kernel.

Thanks!

 

Yeah, as I continue to steal memory away from the "frame buffer", that becomes more and more necessary. Adding a second enemy will take away another six bytes, unless I do something to reduce the memory that each enemy uses (eg only use 4 bits each for fractional position and momentum in Y and Z). Not to mention if I want a score or objective (that needs to be tracked) of any type.

 

The middle of the screen needs more resolution than the top and bottom, so I've also thought about using two different display kernels that doubled lines on only the top 1/3rd and bottom 1/3rd, and having warped arctan etc tables to compensate, but the thought of all of that extra work kind of stresses me out.

Edited by scrottie
Link to comment
Share on other sites

Great stuff, looks very promising! And I second ZackAttack, I think two-line kernels look perfectly fine. But as you said yourself, I guess you'll be forced to do that anyway during further development.

I've got some simple shading going on the platforms, but this demo (I forget which I grabbed that screenshot from)

 

That's my demo TIM1T (here). :)

has way better shading, and texturing. I'd love to steal that, but they've got two colors going on the same line and I'd need three, and enemy birds might wind up in PF*, which wouldn't be all bad since then they could potentially be much larger. Not sure how I'd juggle that. Stuff people do blows me away.


Comparing games to demos is not fair to you game programmers. We demo guys can cut more corners and avoid troublesome situations, which for game programmers is way harder to do because they have to allow more freedom to the players.

 

For example, in my second demo Ascend (here), I have another fake raycasting-like effect (the first effect after the title screen), several 3D boxes rotating around themselves and each other. But note that I don't have smaller boxes in front of larger boxes, and thus avoid having to display more than one color per scanline...

 

Anyway. I'm really looking forward to your progress!

 

  • Like 1
Link to comment
Share on other sites

Feedback welcome!

Neat!

 

 

Are you whom SpiceWare is writing the ARM tutorials for in his Blog?

No/Yes

 

no in that I didn't start the tutorial specifically for scrottie

 

yes in that I'm not really writing it for just one person - I would have handled it via Private Message if that were the case

Edited by SpiceWare
  • Like 1
Link to comment
Share on other sites

Scrottie, did you do a lecture of programming the Atari 2600 and post it on you tube? I can't seem to find it. If it was you, I enjoyed it very much.

Yeah: https://www.youtube.com/watch?v=Ulcq0pVlQ1c It was a YAPC (Yet Another Perl Conference) talk last year. I was unhappy about how it came out. I kind go deer-in-headlights and forgot a bunch of important background and I wasn't very organized. I also completely forget that data projectors take a minute to sync to video, and I'm used to just mashing buttons on my de-modulator to get VGA output from the (hacked on) composite from the 2600. Failing to get video from the 2600 up flustered me. The buttons on the thing cycle between cable input, composite input, s-video input, etc. If I had brought the remote, I could have just pushed the right button and waited for video to come up. I'm pretty happy about the unit testing 6502 machine code stuff though. I think that made debugging a lot easier for me. One of the unit tests for example makes sure that when it renders a platform, it starts and ends where it's supposed to on the screen. Another makes sure that the filling logic worked and there are no gaps. Another makes sure that things rendered in front of other things actually work, and another that platform rendered behind other platforms don't show up at all, and then it tests cases where one platform partially obscures another. So I can instantly find out if a change broke the code. I didn't have to test collision detection in-game at all, because I able to verify it with the unit tests first. Then when I did test it in game, it worked. The files name 01_this and 02_ that in the github repo are the tests.

Edited by scrottie
Link to comment
Share on other sites

No/Yes

 

no in that I didn't start the tutorial specifically for scrottie

 

yes in that I'm not really writing it for just one person - I would have handled it via Private Message if that were the case

Thanks =)

 

Yeah, just for me. I've been begging and begging for years. Wouldn't leave him alone, really.

Link to comment
Share on other sites

Great stuff, looks very promising! And I second ZackAttack, I think two-line kernels look perfectly fine. But as you said yourself, I guess you'll be forced to do that anyway during further development.

 

 

That's my demo TIM1T (here). :)

 

....

 

For example, in my second demo Ascend (here), I have another fake raycasting-like effect (the first effect after the title screen), several 3D boxes rotating around themselves and each other. But note that I don't have smaller boxes in front of larger boxes, and thus avoid having to display more than one color per scanline...

 

 

 

Thanks for the link! I try to watch every 2600 demo I can but I missed that one for some reason. They're both extremely excellent demos. When dealing with few pixels, animation becomes so important. I'm seeing people take sprite animation to high art in other threads. So much fun to watch that unfold.

 

Whether one piece of platform would ever appear in front of another was definitely something I all thought about. Like your boxes, they all have to be the same width (before perspective rendering) so that a smaller one never winds up in front of a larger one.

Link to comment
Share on other sites

Dispute the technical difficulties it was still an informative lecture. I recognized your demo when you posted it here. When I'm ready to tackle assembly I may contact you for advise.

I've only looked at bAtari Basic a bit. I read through https://github.com/e-cooper/Atari2600-Portal for example. This person did a mini version of Portal for the 2600. That would be fun to just to sit there and start adding levels and features to. Turrets, momentum translation, etc.

 

AtariBASIC for the 600XL was my first programming language. I got started doing assembly just mixing in a bit with my BASIC games. AtariBASIC let you do a lot of stuff (often very slowly, which at least isn't a problem for bAtari BASIC... in Atari BASIC, all numbers are floats, and the float library was not optimized for speed at all, for example) but in order to do a vblank handler or hblank handler, you had to do assembly. So for me, at first, it was just inserting tiny little routines. Moving a player between scanlines required assembly, for example. I think that was a good way to learn. So now I'm curious if bAtari BASIC lets you do that.

 

Anyway, I'm happy to share what I know.

Edited by scrottie
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...