Page 1 of 1

Simple raycasting - pseudo 3D

Posted: Sun May 20, 2012 9:29 am
by Arthes
Hello.
How to create the simple pseudo 3D scene with raycasting?
Any tutorials?
Thanks for replies.

Re: Simple raycasting - pseudo 3D

Posted: Sun May 20, 2012 10:49 am
by coffee
You will like read this thread viewtopic.php?f=4&t=6834. As always if you search forum first you get answers.

Re: Simple raycasting - pseudo 3D

Posted: Sun May 20, 2012 10:52 am
by richapple
Ooh yeah. You visited the right forum. Tutorials: permadi.com, lodev.org there are some other useful tutorials at lodev.org/cgtutor, opera dev site

Also, check out Jasoco's amazing game/example WolfenLöve 3D (?) I recommend to read the whole thread There's a lot of useful code snippets especially this one. edit oh snap. didn't notice coffee's post

There were older experiments. the attachment has gone, but the source is still present in this post. also, some cool links here

Re: Simple raycasting - pseudo 3D

Posted: Mon May 21, 2012 5:21 pm
by monkyyy
any pseudo 3d work that was more advance, like hexen level and not wolfsten?

Re: Simple raycasting - pseudo 3D

Posted: Mon May 21, 2012 9:04 pm
by Jasoco
Keep an eye on the forum for a while. I'm getting ready to rewrite my Raycasting engine and actually turn it into a game. I'll probably post either the new example if I make some progress, or the old code if I decide it'll be a while so people could see it. The original code was ported from JS to Lua by jfroco who took a JavaScript HTML example from the Opera Developer website and made it into a working engine. I just took it to the next level. And now the actual Wolfenstein has been ported 100% to JavaScript for its 20th anniversary so anyone can look at the code and try and make their own.

Basically the hardest part about making a 3D game like this is making sure objects on the screen appear in front or behind other things as well as walls. I solve it by placing all the wall strips (Which are the individual "rays") and objects (Which include items, scenery and enemies) in a table (Every single frame) and sort it by distance from the camera. (Every single frame) The Doors were the hardest part and they're still buggy. But I figured it out eventually by using a different method to cast a ray along each door, which was represented as a line that could be moved when the door opens or closes.

Enemy AI is pretty difficult too.

I'd been toying with Raycasting since my QBasic days. At one point I even found one example that actually had textured walls and ran pretty fast. but never had I seen an example that already included enemies and things on screen. Once you try to add those, you complicate things a bit more.

A game like DOOM is basically taking the methods shown by Wolfenstein and taking it to a new level. In DOOM you have sectors instead of a grid that either holds a wall, a door, a piece of scenery, a powerup or empty space which is much simpler. DOOM is harder because every frame the game has to 1) Figure out which sectors are within view, 2) trace a Ray to each and every single wall line within each sector in view of the camera, 3) add each wall strip to the pool with each "thing" and enemy and sort them by distance, 4) also draw the floors, which in my Wolf clone was the hardest part (Thanks to jfroco again) just for a single floor and ceiling. DOOM would be a lot harder since the method used wouldn't work for levels with multi-height floors.

Re: Simple raycasting - pseudo 3D

Posted: Wed May 23, 2012 2:44 am
by monkyyy
sooooo, "no" on having height, and complex moving walls w/o doing it myself :/

Re: Simple raycasting - pseudo 3D

Posted: Fri May 25, 2012 5:56 am
by Jasoco
It's going to be pretty hard. My floor method was based on having two canvases. One for the floor to be pre-drawn on, and another where the floor canvas would be drawn at an offset and rotation based on the player's location and direction, and then an array of quads representing each line of the floor to show cast out in a ~45º ray from the player's POV. It wasn't perfect, but it's fast. In order to do multiple heights using my method you'd literally have to have two canvases for each height level and many many many quads for each and every single floor height. And don't think I hadn't considered it.

See, in the older days the games would draw the floors one pixel at a time but it's extremely slow to iterate over that many pixels in a grid. Even if it's only a maximum of 320x100 pixels for the floor and for the ceiling. That's still 32,000 pixels to check per plane per frame. So it's out of the question. My method was a hack but it looks good enough that most users wouldn't notice.

I don't know how a game like Prelude to the Chambered (Notch's Ludum Dare game from a few months ago that was a 3D sort of game) did it, but I'm sure it took advantage of Java's built-in 3D image manipulation API's. Something Löve just doesn't have right now. I wish it did. If you watched Notch's screencast of him programming the game you can see just how much more advanced Java is at this stuff. I mean, there's no way Minecraft could ever be done in Löve right now. And DOOM would be almost impossible good enough. Wolfenstein is one thing. It's a shame too especially since even a DOOM style game can and has been programmed purely in JavaScript and HTML complete with multi-height floors and ceilings and textures.

I mean, the original Wolfenstein didn't even have textured floors (That came later in games like Blake Stone and other Wolf clones) and instead just used a solid color to represent the floor and ceiling. There wasn't even any depth shading either. The only sense of lighting that game gave is having walls for east and west be slightly darker than the north and south ones. My engine pushed it even further by having distance shading and floor textures.

Re: Simple raycasting - pseudo 3D

Posted: Mon May 28, 2012 4:59 am
by monkyyy
impossible? isnt there a way to draw a 2D image as a "quad" and then from there make a table of all objects needed, sorting by distance?

Re: Simple raycasting - pseudo 3D

Posted: Mon May 28, 2012 6:15 am
by Jasoco
monkyyy wrote:impossible? isnt there a way to draw a 2D image as a "quad" and then from there make a table of all objects needed, sorting by distance?
When I say impossible, I'm referring to making maps that aren't an easy-on-the-CPU grid. DOOM had maps that could contain any shape room, each room was made up of sectors, and each sector was made up of linedefs. Each map could have thousands of linedefs. Hundreds of sectors. The map creation utilities of the time had to use BSP to generate node maps which, to put it in laymans terms, split the map into smaller pieces that the game engine could then work with. i.e., each sector could tell the engine which other sectors it could "see" so the engine would only have to iterate over sectors and linedefs that were actually in view, but in order to do it, it took a lot of calculating beforehand.

In other words, you can't just loop through every single wall in the map to see if it's in view, that would cause so much slowdown, so you need to devise a method to tell which lines are within view quickly by creating a tree that lists what lines are visible from where and account for every sector.

Here's an example to make it easier...

Code: Select all

+---+
|   |
| C |
|   |
+---+---+---+
|   |   |   |
| B | A | D |
|   |   |   |
+---+---+---+
    |   |
    | E |
    |   |
    +---+
In this example, room A can see B, D and E. D can see A. E can see A. B can see A and C. C can see B. I guess if you were to create an engine that used rooms, you'd first check the sector (room) you're in, which might be A. Check its list of rooms it can see, figure out which of those rooms are in view and iterate over them. Say you can see B and E from A but not D. You check B and E. E can only see A so it stops. B can see C. But can YOU see C? So it checks if C is in view too by using the power of MATHS to check the angle of each corner of the sector to see if it's within your view. If so, it iterates over the rooms C can see. Which in this case is only B, which is already drawn. In the case of you standing in A, the game should now have a list of rooms you the player can see. A, B, C and E. It then iterates over the lines in each of these rooms and once again checks to see if you can see them. It also has to make sure to only iterate over walls that are shared (for instance the wall between A and B which in DOOM terms would be a passable linedef that has no texture) or ones that have no texture that can be seen (Remember that in DOOM, linedefs had three textures for each side. Upper, Lower and Middle. Middle would be the one you walk through if the wall is passable) Oh, and it also has to add every enemy and "thing" that the sector contains to another list that will later need to be looped through. This list is recreated every frame.

Now imagine that on a much larger map. With many many connected sectors. You're talking about a sector tree the size of a giant redwood. If you were to have a hundred sectors all in view, you'd be waiting for the engine to check every single one every frame.

Not to mention calculating all the enemies AI for all the enemies in the level, even ones that aren't on screen.

NOW, after the rendering is done, you ALSO have to have some good hit detection. If you ask me, this would actually be harder to figure out. Grid collision is as easy as if map[math.floor(player.x)][math.floor(player.y)].hit == true then which is why so many Indie 3D FPS games are Wolfenstein-style these days. (Google: "Gun Godz") But collision with arbitrary shapes is a bit harder. I guess if you incorporated the collision detection from Box2D it might help, but how slow are you going to get at this point?

Then when all is said and done, you still have to draw everything. Which includes every line for each wall (The amount would be equivalent or greater than the horizontal resolution you use) and every visible thing and enemy.

I'm not saying it's not possible. I mean, someone created a viable DOOM engine in JavaScript that ran pretty fast, it'll just be hard. Plus those people always seem to obfuscate their code and good luck converting such a large amount of JS to Lua.

And then remember that the floors and ceilings would be impossible in Löve as it is, and using my method would slow the game down even more.

I'll just stick to Wolfenstein engines for now. It's a good start. And it's retro.