
A first-person engine in 265 lines of JS - hunterloftis
http://www.playfuljs.com/a-first-person-engine-in-265-lines/
======
devindotcom
Heh, reminds me of kkrieger - a first person shooter in 100KB for a scene
demo.

[https://www.scene.org/file.php?file=%2Fparties%2F2004%2Fbrea...](https://www.scene.org/file.php?file=%2Fparties%2F2004%2Fbreakpoint04%2F96kgame%2Fkkrieger-
beta.zip&fileinfo)

~~~
timpark
If you missed it a couple of weeks ago, this article about its creation was
really interesting: [http://fgiesen.wordpress.com/2012/04/08/metaprogramming-
for-...](http://fgiesen.wordpress.com/2012/04/08/metaprogramming-for-madmen/)

( Thread:
[https://news.ycombinator.com/item?id=7739599](https://news.ycombinator.com/item?id=7739599)
)

~~~
Myrmornis
It's really interesting but would someone mind explaining why they have to
keep this code under some size limit?

~~~
ANTSANTS
[https://en.wikipedia.org/wiki/Demoscene](https://en.wikipedia.org/wiki/Demoscene)

~~~
Myrmornis
Cool, thanks, looks like that's what I was missing.

------
pervycreeper
This demo unfortunately uses an incorrect perspective transformation. There is
no reason to go to trig if you represent the camera plane as a vector, and
step along it one pixel at a time, and allowing the wall height to vary
linearly in the distance to the _camera vector_ (taking lines to lines). In
addition to being correct[1], it has the added benefit of being faster if
implemented well.

My (admittedly n00bish and embarrassing) attempt at doing the same thing is
here:
[https://github.com/pervycreeper/game1/blob/master/main.cpp](https://github.com/pervycreeper/game1/blob/master/main.cpp)

[1] in the sense that lines map to lines, as in most photography, Renaissance
and later painting, and most computer graphics

~~~
hunterloftis
I'm not sure I'm convinced, as finding the cosine does in fact find the linear
distance from the camera plane to the intersection. This is, as far as I have
seen, the standard implementation, eg:
[http://www.permadi.com/tutorial/raycast/rayc8.html#FINDING](http://www.permadi.com/tutorial/raycast/rayc8.html#FINDING)
DISTANCE TO WALLS

However, I would love to see your proposed solution demonstrated. Would you
care to fork the raycaster and compute the results with an alternative method?

~~~
pervycreeper
My implementation above complies, but I can send you binaries if you need
them. Be forewarned that I neglected to implement atmosphere. Here's a
screenshot [http://i.imgur.com/7LJocjS.jpg](http://i.imgur.com/7LJocjS.jpg)

~~~
hunterloftis
I'm less interested in seeing binary output and more interested in
understanding the principles behind what you're saying. The wikipedia page you
mentioned:
[http://en.wikipedia.org/wiki/3D_projection#Diagram](http://en.wikipedia.org/wiki/3D_projection#Diagram)

...appears to be describing exactly how this example works, right down to the
diagram:

[http://www.playfuljs.com/images/raycaster-
distance.png](http://www.playfuljs.com/images/raycaster-distance.png)

I'd be happy to update this article with an improved method once I understand
it.

~~~
Torn
I'd love to see an updated version and a 'before and after' shot

------
roryokane
It is very interesting to me that you need to multiply the distance-to-wall by
the cosine of the angle to transform the image from fisheye to normal. It
makes me wonder, why is it that our eye in real life sees straight lines as
straight, the way this demo renders the image?

To illustrate the question, see
[https://en.wikipedia.org/wiki/File:Panotools5618.jpg](https://en.wikipedia.org/wiki/File:Panotools5618.jpg)
– why do we see the world as in the bottom image instead of in the top one?
After all, our eye really is at different distances from different parts of a
straight wall, so it sounds logical that we would see the fisheye effect
describe in the article. Is the rectilinearity of the image we see caused by
the shape of the lens in our eye, or by post-processing in our brain?

~~~
bitL
I was trying to crack exactly the same problem a decade ago - I was very
frustrated by "classical" perspective distortions (such as looking up and down
at a very tall pole, you notice in 3D projection the projected width at a
given height changes depending on the pitch angle, which is counter-intuitive
as your eye doesn't do that). I searched for answers, read Denis Zorin's
disertation from Caltech, various different camera models etc. After one talk
with a neurosurgeon he mentioned that those "perspective distortions" are
perceived often by patients after a brain surgery and as the brain heals the
normal undistorted picture begins to emerge. I am still curious if there is a
more realistic mathematic formula that would allow us to have exactly the same
perspective projection in 3D graphics as we have with our eyes. Anyone knows
any recent research on this subject?

~~~
TheZenPsycho
this is the perspective projection that we have with our eyes: spherical
projection. detail here:
[http://www.treeshark.com/treeblog/?p=301](http://www.treeshark.com/treeblog/?p=301)

At any given moment we're only looking at a very small slice of that larger
spherical panorama. Our brains are constantly constructing a coherent 3d
model, with the help of various schematic constraints, such as expectations
about straight lines being straight.

We _perceive_ straight lines. but that's not what we _see_. But the curvature
is usually so slight that it is very difficult to see.

------
tst
As someone with no experience in computer graphics it's always insane to see
demos like this. Especially using just around 250 lines of javascript. Really
impressive.

Also on the topic, the demo scene stuff is mind blowing, too. [0]

[0]: [http://awards.scene.org/awards.php](http://awards.scene.org/awards.php)

~~~
masterj
The nice thing about this implementation is that the code is very clear and
easy to follow. You could easily make it much shorter if that were the goal.

~~~
huskyr
Exactly. I think that's wonderful about this example, it's not just 250 lines
of heavily compressed code, it's readable and clean.

------
s-macke
My raycast engine in Javascript needs a few more lines and works a little bit
different, but gives also impressive results I think :) .

[http://simulationcorner.net/index.php?page=comanche](http://simulationcorner.net/index.php?page=comanche)

~~~
pascalo
Love that you referenced Comanche ... my favorite helicopter game ever. Nice
work on the JS side also!

~~~
s-macke
The graphics were impressive, but the gameplay never touched me. Comanche 3
was much better.

------
riquito
Cool. It reminded me of a similar work published by Opera some years ago

[http://dev.opera.com/articles/3d-games-with-canvas-and-
rayca...](http://dev.opera.com/articles/3d-games-with-canvas-and-raycasting-
part-1/)

woa! it was 2008, time sure pass by.

------
smrq
> Rain is simulated with a bunch of very short walls in random places.

This made me laugh. I would have never thought of that way of doing it, but
before I knew how it was implemented, I didn't even notice! That's a pretty
good approximation!

------
callumprentice
Great work. I had a huge amount of fun converting your last article (terrain
renderer in a tiny number of JS) to WebGL and that was only fun because of
your clean, easy to understand code. Thanks for sharing.

\--Callum

------
mazak
I'm really surprised that it's 265 and not 256... I mean, there's got to be a
good reason not to make it a round number, right? I'm mind blown anyways...

~~~
hunterloftis
Was shooting for 256 but went over to implement touch events ;)

~~~
mazak
Well I guess that's the downfall of the touch screen era

~~~
Roedou
The downfall is that you an add a complete secondary interface in 9 lines of
code?

------
aaron-lebo
That's really impressive.

I've seen some people suggest that voxels are like sprites for 3d programming
(as far as sheer simplicity goes), but this strikes even more so as that. How
does this compare to using actual 3d/voxels? Can you still have interesting
physics or do you miss out on a lot?

~~~
hunterloftis
Thanks! As with most software decisions, raycasters involve a tradeoff. They
are related to voxels in that they impose constraints on what can be rendered.
Voxels render grids in 3 dimensions while raycasters (typically) render them
in 2.

For this reason, you can generally build a raycaster faster and simpler than
either voxels or meshes, but there will be things you can't do. Rotation on
the x axis is tricky, for example.

It's probably best to think of physics in a raycaster as the same sort of
physics you could apply in a top-down 2D game.

------
darkstalker
It runs really slow for me, like 1 FPS. Firefox 29 on Linux.

~~~
hunterloftis
Interesting. Does FF 29 on linux perhaps have purely software graphics? It
runs much faster than 1 fps on iphones and most androids, 60 fps on modern
desktops in safari/chrome, and 30 fps on FF / osx.

~~~
jgillich
I get terrible FPS with Firefox on Windows as well (Intel Haswell graphics).

------
eignerchris_
This is so great. Very straightforward explanation of raycasting. Looking
forward to playing with!

------
rukke
A raycaster in 254b on the C64

[https://plus.google.com/108984290462000253857/posts/MxWQwo14...](https://plus.google.com/108984290462000253857/posts/MxWQwo14GNS)

------
thinkersilver
Raycasting brings back memories! I remember poring through raycasting
techniques to make my Wolf and Doom clones as a teenager. When I was almost
done I demoed this for a group of friends at our school's computer club and
boy were they were impressed up until the point the clipping algorithm failed
and objects stopped disappearing when they fell out of the players field of
view. Was teased for months after that. ... .

------
matheusbn
Nice demo! But one note, I don't know about DaggerFall but Duke Nukem 3D does
NOT uses Raycasting to draw walls.

DN3D uses sectors (Convex Polygon) to store room's lines (or walls), and draws
those lines using player's FOV (Field Of View).

When those sectors are connected with others sectors, it's called portal. This
is used to sort only the sectors that is inside the player's FOV.

~~~
thedevopsguy
Didn't games like Duke Nukem 3d, post-Doom, Wolf games use what was called a
scanline algorithm? Drawing the lines in the players FOV as you just stated
and then using a clipping algorithm to keep unwanted information out. I think
raycasting would be a type of scanline algorithm, but the technique is less
primitive since your not using a proper 3d engine. It's a long time since I
programmed games like this so am now a bit fuzzy on the specifics.

------
pearjuice
I feel very pathetic from this. You could have given me 265K lines and I
wouldn't have figured it out.

~~~
jiggy2011
Pretty sure the author followed this tutorial.
[http://lodev.org/cgtutor/raycasting.html](http://lodev.org/cgtutor/raycasting.html)

------
olegbl
I remember being amazed how simple raycasting was when I wrote a similar
(though much simpler) engine in Java for a high school project. The "engine"
itself was like ~200 lines of code in just 2 or 3 functions. Raycasting is a
really clever technology. Cool demo!

------
cwyers
I know that the arrow keys have actual arrows on them, but so many modern
games have trained us to use WASD to navigate, that if you're going to insist
upon the arrow keys for navigation, you should probably mention this somewhere
before the link to the demo.

~~~
hunterloftis
done!

------
Cieplak
Reminds me of
[http://www.p01.org/releases/20_lines_Castle_Wolfenstein/](http://www.p01.org/releases/20_lines_Castle_Wolfenstein/)

------
Hortinstein
this is incredible. I remember doing something in C in openGL with triple the
line count and not nearly as impressive results during a bachelor computer
graphics class. This would have been a much more interesting lab.

Thanks for the great work, i can't wait to play around with this!

------
elnate
What's the difference between ray casting and ray tracing?

~~~
Drakim
Wikipedia gives a pretty good breakdown of the two terms:

[http://en.wikipedia.org/wiki/Ray_tracing_(graphics)](http://en.wikipedia.org/wiki/Ray_tracing_\(graphics\))

[http://en.wikipedia.org/wiki/Ray_casting](http://en.wikipedia.org/wiki/Ray_casting)

------
Kiro
Why do you need to use Uint8Array and not just a normal array?

~~~
hunterloftis
I (mistakenly) thought it would access faster. In looking for benchmarks to
link you to, I found out that's a false assumption. So - no reason to at all
:)

------
mobiuscog
And it even manages to include Google Analytics !

------
chandrew
Wow.

------
passfree
Awesome!

------
JulienSchmidt
<rant about no. of lines being a completely useless metric> <jquery in 1 line>

