Hey there.
I found a really simple raycasting demo today. It's a sample for CodeTanks "Brain Damage" And because "Brain Damage" also uses lua it only took 5 minutes to port it to Löve It's not the next Wolfenstein 3D but it shows the basics of the raycasting technique. Have fun with this demo. Change some parameters, make a maze out of it or try to render textures to the walls If you're done with that, add enemies. And doors. And german shepherds
Updated!
* Added FPS Counter
* Keydetection now in update() function -> walking smooth now
Raycasting Demo (like Wolfenstein3D, just veery basic)
Raycasting Demo (like Wolfenstein3D, just veery basic)
- Attachments
-
- LoveRaycastingDemo.love
- (3.09 KiB) Downloaded 682 times
Last edited by Gerrit on Fri Apr 10, 2009 10:41 am, edited 1 time in total.
Re: Raycasting Demo (like Wolfenstein3D, just veery basic)
This is pretty awesome nice work!
Re: Raycasting Demo (like Wolfenstein3D, just veery basic)
Good demo. I'd recommend moving the code out of function keypressed and into the update routine instead, so people don't have to keep tapping the buttons to go. Gives an idea of just how fast this engine really goes.
We don't borrow, we don't read, we don't rent, we don't lease, we take the minds!
Re: Raycasting Demo (like Wolfenstein3D, just veery basic)
Ya, this was the last thing I did last night before bedtime I updated it now. Runs smooth with 60fps most of the time if you're not drawing too many walls at once.Xcmd wrote:Good demo. I'd recommend moving the code out of function keypressed and into the update routine instead, so people don't have to keep tapping the buttons to go. Gives an idea of just how fast this engine really goes.
Re: Raycasting Demo (like Wolfenstein3D, just veery basic)
in this thread i posted basicly the same thing (im sure the script is organized different) but has some borked up texture mapping too
enjoy
enjoy
- TechnoCat
- Inner party member
- Posts: 1612
- Joined: Thu Jul 30, 2009 12:31 am
- Location: Milwaukee, WI
- Contact:
Re: Raycasting Demo (like Wolfenstein3D, just veery basic)
I mangled it to an ugly version of 0.6.1
- Attachments
-
- raycast.love
- 0.6.1
- (2.43 KiB) Downloaded 275 times
- Jasoco
- Inner party member
- Posts: 3727
- Joined: Mon Jun 22, 2009 9:35 am
- Location: Pennsylvania, USA
- Contact:
Re: Raycasting Demo (like Wolfenstein3D, just veery basic)
I'm sad it runs so slow if you try to up the "resolution". I guess all those math calculations really take their toll. Weird that the JavaScript/Canvas version of these Wolfenstein engines runs so much faster.
- Robin
- The Omniscient
- Posts: 6506
- Joined: Fri Feb 20, 2009 4:29 pm
- Location: The Netherlands
- Contact:
Re: Raycasting Demo (like Wolfenstein3D, just veery basic)
I guess they are much more optimized.Jasoco wrote:I'm sad it runs so slow if you try to up the "resolution". I guess all those math calculations really take their toll. Weird that the JavaScript/Canvas version of these Wolfenstein engines runs so much faster.
Help us help you: attach a .love.
- Jasoco
- Inner party member
- Posts: 3727
- Joined: Mon Jun 22, 2009 9:35 am
- Location: Pennsylvania, USA
- Contact:
Re: Raycasting Demo (like Wolfenstein3D, just veery basic)
Nope. They work the same basic way. Raycasting at a certain number of columns per frame. Somehow the JavaScript version runs faster, yet Löve is faster than JavaScript at pretty much everything else. Could it be that Lua/Löve has slightly slower math calculations that don't really show up as a difference until you're calling them many many times?Robin wrote:I guess they are much more optimized.Jasoco wrote:I'm sad it runs so slow if you try to up the "resolution". I guess all those math calculations really take their toll. Weird that the JavaScript/Canvas version of these Wolfenstein engines runs so much faster.
Compare the code for both engines:
JavaScript:
Code: Select all
var pixelWidth=2;
function changeResolution(){
var detail = document.getElementById('hilow').options.selectedIndex;
pixelWidth = [8,4,2,1][detail];
samples = [50,100,200,400][detail];
drawCanvas();
}
var map;
var canvas;
var overlay;
//variables initiated at the bottom of the code...
var pic=[];
for (var i=0; i<4; i++) pic[i]=new Image(), pic[i].src='wall'+i+'.gif';
var pi=Math.PI;
var total=0;
Number.prototype.range=function(){
return (this+2*pi)%(2*pi);
}
Number.prototype.roundC=function(){
return Math.round(this*100)/100;
}
var total=0;
var samples=200;
var arena=[];
arena[0]=[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]
arena[1]=[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]
arena[2]=[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]
arena[3]=[1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]
arena[4]=[1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]
arena[5]=[1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]
arena[6]=[1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]
arena[7]=[1,1,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]
arena[8]=[1,1,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]
arena[9]=[1,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]
arena[10]=[1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]
arena[11]=[1,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]
arena[12]=[1,1,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]
arena[13]=[1,1,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]
arena[14]=[1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]
arena[15]=[1,1,1,1,1,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]
arena[16]=[1,1,1,1,1,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]
arena[17]=[1,1,1,1,1,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]
arena[18]=[1,1,1,1,1,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]
arena[19]=[1,1,1,1,1,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]
arena[20]=[1,1,1,1,1,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]
arena[21]=[1,1,1,1,1,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]
arena[22]=[1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]
arena[23]=[1,1,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]
arena[24]=[1,1,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]
arena[25]=[1,1,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]
arena[26]=[1,1,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1]
arena[27]=[1,1,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1]
arena[28]=[1,1,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1]
arena[29]=[1,1,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,1,1,1,1,1,0,0,0,1,1,1,1,1,1,1,1,1,1]
arena[30]=[1,1,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,1,1,1,1]
arena[31]=[1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,0,0,0,1,1,0,1,1,1,1,1,1,1]
arena[32]=[1,1,1,1,1,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,1,1,1,1,1,1,1,1,0,0,0,1,0,0,0,0,0,0,0,0,1]
arena[33]=[1,1,1,1,1,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1]
arena[34]=[1,0,0,0,1,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,1,1,1,1,1,1,1,1,0,0,0,1,0,0,0,0,0,0,0,0,1]
arena[35]=[1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1]
arena[36]=[1,0,0,0,1,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]
arena[37]=[1,1,1,1,1,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]
arena[38]=[1,1,1,1,1,0,0,0,0,0,1,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]
arena[39]=[1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]
arena[40]=[1,1,1,1,1,0,0,0,0,0,1,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]
arena[41]=[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]
arena[42]=[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]
arena[43]=[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]
arena[44]=[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]
arena[45]=[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]
arena[46]=[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]
arena[47]=[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]
arena[48]=[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]
arena[49]=[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]
arena[50]=[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]
arena[51]=[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]
arena[52]=[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]
var playerPos=[51,30.5]; // x,y (from top left)
var playerDir=Math.PI; // theta, facing right=0=2pi
var playerPosZ=1;
var key=[0,0,0,0,0]; // left, right, up, down
var playerVelY=0;
var face=[];
var bit=[];
function wallDistance(theta){
var dist=[];
var x = playerPos[0], y = playerPos[1];
var deltaX, deltaY;
var distX, distY;
var stepX, stepY;
var mapX, mapY
var atX=Math.floor(x), atY=Math.floor(y);
for (var i=0; i<samples; i++) {
theta+=pi/(3*samples)+2*pi;
theta%=2*pi;
mapX = atX, mapY = atY;
deltaX=1/Math.cos(theta);
deltaY=1/Math.sin(theta);
if (deltaX>0) {
stepX = 1;
distX = (mapX + 1 - x) * deltaX;
}
else {
stepX = -1;
distX = (x - mapX) * (deltaX*=-1);
}
if (deltaY>0) {
stepY = 1;
distY = (mapY + 1 - y) * deltaY;
}
else {
stepY = -1;
distY = (y - mapY) * (deltaY*=-1);
}
while (true) {
if (distX < distY) {
mapX += stepX;
if (arena[mapX][mapY]) {
dist[i]=distX;
face[i]=2+stepX;
bit[i]=(y+distX/deltaY*stepY)%1 || 0;
break;
}
distX += deltaX;
}
else {
mapY += stepY;
if (arena[mapX][mapY]) {
dist[i]=distY;
face[i]=1+stepY;
bit[i]=(x+distY/deltaX*stepX)%1 || 0;
break;
}
distY += deltaY;
}
}
}
return dist;
}
function drawCanvas(){
map.clearRect(0,0,106,106);
map.fillStyle="#3366CC";
map.arc(playerPos[0]*2, playerPos[1]*2, 2, 0, 2*pi, true);
map.fill();
map.beginPath();
map.moveTo(2*playerPos[0], 2*playerPos[1]);
canvas.clearRect(0,0, 400, 300);
var theta = playerDir-pi/6;
var dist=wallDistance(theta);
var c;
for (var i=0; i<samples; i++) {
theta+=pi/(3*samples);
var d2=dist[i];
var d=d2*Math.cos(theta-playerDir);
var z=1-playerPosZ/2;
var h=300/d;
canvas.drawImage(pic[face[i]], bit[i]*63, 0, 1, 64, i*pixelWidth, 150-h*z, pixelWidth, h)
map.lineTo(playerPos[0]*2+Math.cos(theta)*d2*2, playerPos[1]*2+Math.sin(theta)*d2*2);
}
map.fillStyle="#FF0000"
map.fill();
}
function nearWall(x,y){
var xx,yy;
if (isNaN(x)) x=playerPos[0];
if (isNaN(y)) y=playerPos[1];
for (var i=-0.1; i<=0.1; i+=0.2) {
xx=Math.floor(x+i)
for (var j=-0.1; j<=0.1; j+=0.2) {
yy=Math.floor(y+j);
if (arena[xx][yy]) return true;
}
}
return false;
}
function wobbleGun(){
var mag=playerVelY;
overlay.style.backgroundPosition=(10+Math.cos(total/6.23)*mag*50)+"px "+(10+Math.cos(total/5)*mag*50)+"px";
}
var jumpCycle=0;
function update(){
total++;
var change=false;
if (jumpCycle) {
jumpCycle--;
change=true;
playerPosZ = 1 + jumpCycle*(20-jumpCycle)/110;
}
else if (key[4]) jumpCycle=20;
if (key[0]) {
if (!key[1]) {
playerDir-=0.07; //left
change=true;
}
}
else if (key[1]) {
playerDir+=0.07; //right
change=true;
}
if (change) {
playerDir+=2*pi;
playerDir%=2*pi;
document.getElementById("sky").style.backgroundPosition=Math.floor(-playerDir/(2*pi)*2400)+"px 0";
}
if (key[2] && !key[3]) {
if (playerVelY<0.2) playerVelY += 0.04;
}
else if (key[3] && !key[2]) {
if (playerVelY>-0.2) playerVelY -= 0.04;
}
else {
if (playerVelY<-0.02) playerVelY += 0.015;
else if (playerVelY>0.02) playerVelY -= 0.015;
else playerVelY=0;
}
if (playerVelY!=0) {
var oldX=playerPos[0];;
var oldY=playerPos[1];
var newX=oldX+Math.cos(playerDir)*playerVelY;
var newY=oldY+Math.sin(playerDir)*playerVelY;
if (!nearWall(newX, oldY)) {
playerPos[0]=newX;
oldX=newX;
change=true;
}
if (!nearWall(oldX, newY)) {
playerPos[1]=newY;
change=true;
}
}
if (playerVelY) wobbleGun();
if (change) drawCanvas();
}
function changeKey(which, to){
switch (which){
case 65:case 37: key[0]=to; break; // left
case 87: case 38: key[2]=to; break; // up
case 68: case 39: key[1]=to; break; // right
case 83: case 40: key[3]=to; break;// down
case 32: key[4]=to; break; // space bar;
case 17: key[5]=to; break; // ctrl
}
}
document.onkeydown=function(e){changeKey((e||window.event).keyCode, 1);}
document.onkeyup=function(e){changeKey((e||window.event).keyCode, 0);}
function initUnderMap(){
var underMap=document.getElementById("underMap").getContext("2d");
underMap.fillStyle="#FFF";
underMap.fillRect(0,0, 200, 200);
underMap.fillStyle="#444";
for (var i=0; i<arena.length; i++) {
for (var j=0; j<arena[i].length; j++) {
if (arena[i][j]) underMap.fillRect(i*2, j*2, 2, 2);
}
}
}
window.onload=function(){
map=document.getElementById("map").getContext("2d");
canvas=document.getElementById("canvas").getContext("2d");
overlay=document.getElementById("overlay");
document.getElementById("sky").style.backgroundPosition=Math.floor(-playerDir/(2*pi)*2400)+"px 0";
drawCanvas();
initUnderMap();
setInterval(update, 35);
}
Code: Select all
function love.load()
love.graphics.setMode( 640, 480, false, true, 0 )
config = { }
config.width = 640 -- width of window
config.height = 480 -- height of window
config.fov = 60 -- field of view (degrees)
config.sliver_width = 4 -- thickness of each wall sliver (pixels)
config.ray_resolution = 0.02 -- lower number = higher resolution = more accurate = more CPU
config.wall_zoom = 320 -- how much to zoom the walls, play with to see results
config.player_speed = 0.1 -- how fast the player moves forward
config.player_turn = 2 -- how fast the player turns
config.fish_eye = false -- should the engine remove the "fish eye" side effect?
-- don't change this stuff
config.sliver_width = math.floor(config.sliver_width + 0.5)
config.slivers_per_screen = math.ceil(config.width / config.sliver_width)
config.ang_per_sliver = config.fov / config.slivers_per_screen
config.cy = math.floor(config.height / 2)
map = {
width = 11, -- width of map
height = 11, -- height of map
start = {2.5, 2.5}, -- x, y cell to start in
startang = 90, -- what direction to face in
-- map data... 1-9 are colored walls, 0 is no wall
{1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1},
{3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4},
{4, 0, 0, 0, 0, 0, 7, 8, 7, 0, 3},
{3, 0, 5, 0, 0, 0, 8, 9, 8, 0, 4},
{4, 0, 6, 0, 0, 0, 7, 0, 7, 0, 3},
{3, 0, 5, 0, 0, 0, 8, 0, 8, 0, 4},
{4, 0, 6, 5, 6, 0, 7, 0, 7, 0, 3},
{3, 0, 0, 0, 0, 0, 8, 0, 0, 0, 4},
{4, 0, 6, 0, 3, 0, 7, 8, 7, 0, 3},
{3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4},
{1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1},
}
color = { }
player = { }
player.x = map.start[1]
player.y = map.start[2]
player.ang = map.startang
end
function love.draw()
local sx = 0
local ang = player.ang - (config.fov / 2)
local ray_len
local col
local height
local start_wall
-- start from the left side, and cast a ray for each sliver
for s = 0, config.slivers_per_screen do
-- cast the ray
ray_len, col = cast_ray(player.x, player.y, ang)
if (not config.fish_eye) then
-- remove the fish eye side effect
ray_len = ray_len * math.cos((player.ang - ang) * math.pi / 180)
end
-- calculate height of wall
height = math.floor(config.wall_zoom / ray_len)
start_wall = math.floor(config.cy - height / 2)
-- clip wall to screen
if (start_wall < 0) then
height = height + start_wall
start_wall = 0
else
-- wall isn't too high, so draw sky
love.graphics.setColor( 200, 200, 255 )
love.graphics.rectangle( "fill", sx, 0, config.sliver_width, start_wall )
end
if (start_wall + height > config.height) then
height = config.height - start_wall
else
-- wall isn't too long, so draw floor
love.graphics.setColor( 63, 63, 0 )
love.graphics.rectangle( "fill", sx, start_wall + height, config.sliver_width, config.height - start_wall - height )
end
-- draw the wall
love.graphics.setColor( 255, 0, 255 )
love.graphics.rectangle( "fill", sx, start_wall, config.sliver_width, height )
-- increase our sliver position
sx = sx + config.sliver_width
-- increase our sliver angle
ang = ang + config.ang_per_sliver
end
love.graphics.setColor( 0, 0, 0 )
love.graphics.print("FPS: " .. love.timer.getFPS(), 50, 50)
end
function love.update( dt )
local ox = player.x
local oy = player.y
if ( love.keyboard.isDown( "up" ) ) then
-- move player forward
player.x = player.x + math.cos(player.ang * math.pi / 180) * config.player_speed
player.y = player.y + math.sin(player.ang * math.pi / 180) * config.player_speed
elseif ( love.keyboard.isDown( "down" ) ) then
-- move player backwards
player.x = player.x - math.cos(player.ang * math.pi / 180) * config.player_speed
player.y = player.y - math.sin(player.ang * math.pi / 180) * config.player_speed
end
if ( love.keyboard.isDown( "right" ) ) then
player.ang = (player.ang + config.player_turn) % 360
elseif ( love.keyboard.isDown( "left" ) ) then
player.ang = (player.ang + 360 - config.player_turn) % 360
end
-- clip the player to the walls
if (get_map(player.x, player.y) ~= 0) then
player.x = ox
player.y = oy
end
end
-- gets the wall color of the map, with bounds checking
function get_map(x, y)
x = math.floor(x)
y = math.floor(y)
if (x < 1 or y < 1 or x > map.width or y > map.height) then
return 1
end
return map[y][x]
end
-- casts a ray starting at (x, y), pointing at ang direction...
-- returns the distance the ray travelled until it hit a wall, and the wall's color
function cast_ray(x, y, ang)
local dist = 0
local col = 1
local dx = math.cos(ang * math.pi / 180) * config.ray_resolution
local dy = math.sin(ang * math.pi / 180) * config.ray_resolution
repeat
x = x + dx -- travel
y = y + dy
dist = dist + config.ray_resolution -- track distance travelled
col = get_map(x, y)
if (col ~= 0) then -- is map location still blank?
break -- no? so we hit a wall... stop casting
end
until (false)
-- return the distance travelled, and the color of the wall that finally stopped our ray
return dist, col
end
I mean look at the DOOM-style engine clone I posted in the other thread which does even more than the much more simple Wolfenstein-style engine (i.e. different height floors and ceilings, textures on the floors, sprites, doors...) and is still super fast.
It's so weird really. Something is causing the bottleneck slowdown.
- Robin
- The Omniscient
- Posts: 6506
- Joined: Fri Feb 20, 2009 4:29 pm
- Location: The Netherlands
- Contact:
Re: Raycasting Demo (like Wolfenstein3D, just veery basic)
Perhaps the double table lookups for math functions?
math.cos translates to: getglobal 'math', getdotted 'cos' while cos translates to: getlocal 0 (or something like that, and assuming cos is a local)
Also repeat ... until was slow, wasn't it?
math.cos translates to: getglobal 'math', getdotted 'cos' while cos translates to: getlocal 0 (or something like that, and assuming cos is a local)
Also repeat ... until was slow, wasn't it?
Help us help you: attach a .love.
Who is online
Users browsing this forum: No registered users and 2 guests