Raycasting Library

A relatively robust raycasting library with billboard sprites + collision detection!

There’s a suite of examples ranging in difficulty, including a “full demo” game utilizing all the features. You’re free to use any of the code in any example, or build directly off any of them.

The maximum map size is 16x16 and is stored in memory. Because of this, maps are flexible and can be generated or loaded from either program memory or the FX chip (or even eeprom?). Sprites and tiles are also 16x16 pixels and supports up to 256 of both. Sprites and tiles currently can only be loaded from program memory. If you need sprites loaded from the FX chip, I might be able to make a modification to support that, though it would most likely decrease performance a bit. If you need tiles loaded from the FX chip, that might also be possible but might decrease performance more, though I’m not sure until we try it.

The raycaster by default runs at about 30fps fullscreen and can run up to 40fps if you reduce the view width. Sprites have some impact which increases the more the sprite fills up the screen. If a sprite fills up the whole screen, you can generally expect about half the performance, since it has to draw both walls and the sprite. For high performance, it’s recommended to decrease the render width or height and use the screen real-estate for something else.

Here’s the first compiled example program, more are posted later in the thread:

basic_tilesonly.ino.hex (43.6 KB)

Normal controls this time, with A being a “flashlight” to show off that you can change the light level on the fly now.

If you plan on making anything, let me know! I still haven’t decided what game I want to make, figured in the meantime I’d make it easier on myself and make the library easier to use.

12 Likes

Wow this is incredibly performant and with the falloff like doom!

I realized the other game that did this before was circulated on a japanese website and never posted here:

http://blog.livedoor.jp/cobinee/archives/1908280.html

2 Likes

Thank you! I guess maybe you haven’t been following the 3D maze thread? It’s the same one from there, I just turned it into a library.

And ah, I’ll have to try it sometime!

OK couldn’t help myself, second example is committed showing that the map is dynamic (warning: sound):

place_blocks.ino.hex (46.8 KB)

Edit: might as well increase view distance since it’s an empty room (and a good part to the example).

6 Likes

LOL no not every post no. #embarrass

1 Like

Holy mackerel!

The amount this has improved in performance & features since first proof of concept seven days ago is incredible!

I’m still way too early in my learning journey to attempt anything using this library but I can recognise the effort and care put into this. One day…! (And until then, I can’t wait to see what else people make with this)

2 Likes

Finally we’ve got Minecraft for the Arduboy.

2 Likes

A bit of Flatland Minecraft, but quite indeed!

2 Likes

Holy cow! Lol this is amazing, why is this so amazing?

Just needs pickaxe and damage animation for destruction :slight_smile:

And maybe a creeper or two

2 Likes

glad to see new stuff like this still coming out, this is awesome!

2 Likes

Added a new example to show off sprites and bounding boxes, this one really edged out a lot of the weird junk in the library. I still wouldn’t call the library stable yet, just be aware if you use it that I might change a lot still (and I’m still looking for performance improvements):

basic_sprites.ino.hex (46.2 KB)

Note that it’s hard to go above 16 sprites. Although the raycast library will (probably) handle it, there’s not a lot of memory to work with, and each sprite needs information like the position/current frame/etc and it quickly takes up a lot of space. Plus bounding boxes…

Anyway, the example is https://github.com/randomouscrap98/arduboy_raycast/tree/main/examples/basic_sprites but even the examples are bound to change as the library changes. This one shows off that if you make the bounds of the walls obvious, you can create more interesting spaces than just “open ceiling darkness”. I’ve increased the light intensity and made the room smaller so the shading never goes to black, and that way I could have a white ceiling and “carpet”

The raycaster isn’t really made to go fullscreen like this, and the performance suffers. This example can run wonderfully at 30fps if you add the menu on the right like in 3D maze. I’ll keep working on the performance though

Edit: these examples are doing their job; fixed a bug with the chandelier “dropping” (precision issues)

6 Likes

Can’t wait for the Mission Impossible x Minecraft Arduboy game

2 Likes

I just gotta ask… would it be possible to stream the textures from the external memory, and the map data for that matter?

1 Like

The map, probably, as long as you load the local area into memory (but it would require changes to some position based data types in the library). Or if you’re fine with 16x16 “sub areas”, you can absolutely load them from external memory, since it’s just part of the “loading screen” (not that it’d take long enough to see). You might be able to get away with sprites if you’re clever, but tile textures… I’m not sure. Someone is free to try, but judging from my reading of the fx threads, it’s just too many cycles per wall stripe. But maybe?

Basically, of all the things you could put in external memory, the tile textures are I think the least likely. Maps themselves are the most likely and immediately supported right now if you limit each subarea to 16x16

Edit: I wouldn’t say any of them are impossible, youd just not be able to approach the same performance. But idk, maybe I’ll try and see.

Edit 2: I guess I don’t have a lot of experience with how much game logic takes up on device, but I think it’d still be possible to make quite a robust game even if all the tiles are stored in program memory. The example programs are only about 17KiB, even with a 1KiB wasteful background image (most background images can be easily generated or tiled (or put on the FX chip)), the loop unrolling which takes up 1.2KiB, and not removing the USB stack, which is like 2.7KiB. Remove all that (though note that removing loop unrolling is a hit of like 20% performance) and you get about 12KiB for the baseline raycaster. Maybe with a full 256 tile sheet (8KiB) that doesn’t leave enough space but… I don’t know. If someone has a crazy idea and wants to make a massive game that won’t fit on device, just let me know and I can look into some kind of caching solution. Tiles are 32 bytes; I could reserve 32 bytes on the stack for wall draw calls and only load tile data from the FX chip when the wall stripe is for a different tile than the previous, greatly reducing the cost (though if you have like 16 different tiles on screen idk…)

1 Like

Don’t mind me I’m just very curious about all of this, as we established in the live stream - even drawing masked sprites is a little above my level.

Added a couple more examples, and labelled them by their “group” (so group 2 builds on 1, 3 on 2, etc). And added a “full game” demo that shows off I think all the features of the raycast library. I think some of these features are better implemented custom in your own games, but we’ll see. If it turns out I’m just wasting memory and program space for these default implementations, I might add ways to selectively disable, for instance, the bounding box system.

Example level 4: collect all the coins! Ignoring maze generation, it’s about 300 lines, not too bad!

4_demo_collectcoins.ino.hex (53.7 KB)

Example code: https://github.com/randomouscrap98/arduboy_raycast/tree/main/examples/4_demo_collectcoins

If you do end up using any of the examples or trying to make a game, let me know if you need help!

4 Likes

Almost finished game ) Just add timer
I wonder if it is possible to combine Raycasting and ArduboyG technology )

1 Like

I thought about it, but I got lazy lol.


So, you remember the original demo from the 3D maze room? Last I left it, it was running at 35fps, but dropped significantly around sprites. I’ve been trying out some optimizations I had in mind and it now runs near 45fps:

recording_20230924052759

This also means the sprite demo from before, the one with the chandelier, can run at 30fps now instead of a rough 25:

recording_20230924053129

IDK how noticeable it is but it definitely impacts all the demos quite a lot, nearly 20%. I might be able to get a bit more performance out of this new method using assembly but we’ll see. I won’t be updating all the hex files I post here as performance improvements are made (it’s a lot of work) so if you play those, just know they probably run faster now with the latest library.

Edit: at this point, more time is spent calculating the ONE division per stripe that’s left in the code than actually rendering the whole scene. Sprites are a bit of a tossup because they need a lot anytime they’re on screen.

4 Likes

Wow! Add 4 ghosts and you have a 3d pacman on Arduboy :wink:

3 Likes

rewrote the new texture stepping method in assembly, reduced the code output size by 100-200 bytes and increased performance again by another 5%. wish it were more but oh well. i might write up a topic on it to get some feedback and see if there are new ideas sometime.

i still have so much wrapped up in that one division it’s doing. i wonder if there’s anything i can do about that…

1 Like