Created
July 16, 2015 19:00
-
-
Save TerryCavanagh/c02fb300007645c1021d to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| -- raycast variables | |
| camerax = 0.0 cameray = 0.0 | |
| rayposx = 0.0 rayposy = 0.0 | |
| raydirx = 0.0 raydiry = 0.0 | |
| sidedistx = 0.0 sidedisty=0.0 | |
| deltadistx = 0.0 deltadisty=0.0 | |
| newdeltadistx = 0.0 newdeltadisty=0.0 | |
| perpwalldist = 0.0 | |
| distwall = 0.0 distplayer=0.0 | |
| currentdist = 0.0 | |
| currentfloorx = 0.0 | |
| currentfloory = 0.0 | |
| drawframe = 0 | |
| dodrawing = false | |
| transparentthisframe = false | |
| transparent_start = 0 | |
| transparent_end = 0 | |
| _4pi = 12.5663706143592 | |
| _2pi = 6.28318530717959 | |
| pi = 3.14159265358979 | |
| pi_2 = 1.5707963267949 | |
| pi_4 = 0.785398163397448 | |
| emptysquare = 0 | |
| check = 0 | |
| zbuffer = {} | |
| so = {} | |
| spritedistance = {} | |
| redrawstripe = {} | |
| sss = {} | |
| mapx = 0 mapy = 0 | |
| stepx = 0 stepy = 0 | |
| hit = 0 side = 0 | |
| rayheight = 0 | |
| drawstart = 0 drawend = 0 | |
| -- raycast coordinates | |
| posx = 0.0 posy = 0.0 | |
| dirx = 0.0 diry = 0.0 | |
| planex = 0.0 planey = 0.0 | |
| olddirx = 0.0 olddiry = 0.0 | |
| oldplanex = 0.0 oldplaney = 0.0 | |
| wallbuffer = 0.5 | |
| playerwallbuffer = 0.3 | |
| turnspeed = (_2pi)/360 | |
| movespeed = 0.15 | |
| showfloor = true | |
| showceiling = true | |
| uselighting = true | |
| ceilingcol = 0 | |
| floorcol = 0 | |
| w = 56 w2 = w*2 | |
| h = 48 h2 = h*2 | |
| xscale = 2 xdraw = 3 | |
| yscale = 2 ydraw = 1 ydrawfloor = 3 | |
| wallheight = (50/64)*h | |
| texwidth = 8 | |
| texheight = 8 | |
| function raycast_init() | |
| for i=0,129 do | |
| zbuffer[i+1] = 0 | |
| redrawstripe[i+1] = 0 | |
| sss[i+1] = 0 | |
| end | |
| end | |
| wallat = 0 | |
| function checkwall(xpos, ypos) | |
| wallat = mget(flr(xpos), flr(ypos)); | |
| if (blocks[wallat + 1].collidable) then | |
| return true | |
| end | |
| return false | |
| end | |
| function getwall(xpos, ypos) | |
| return mget(flr(xpos), flr(ypos)) | |
| end | |
| function rotate(angle) | |
| --both camera direction and camera plane must be rotated | |
| olddirx = dirx | |
| dirx = (dirx * cos(angle)) - (diry * sin(angle)) | |
| diry = (olddirx * sin(angle)) + (diry * cos(angle)) | |
| oldplanex = planex | |
| planex = (planex * cos(angle)) - (planey * sin(angle)) | |
| planey = (oldplanex * sin(angle)) + (planey * cos(angle)) | |
| end | |
| function storeolddir() | |
| olddirx = dirx | |
| olddiry = diry | |
| oldplanex = planex | |
| oldplaney = planey | |
| end | |
| function restoreolddir() | |
| dirx = olddirx | |
| diry = olddiry | |
| planex = oldplanex | |
| planey = oldplaney | |
| end | |
| function safesqrt(n) | |
| if(n<=0.01) then | |
| return 0.0 | |
| end | |
| return sqrt(n) | |
| end | |
| shootthrough = 0 | |
| function drawstripe(x, layer) | |
| shootthrough = 0 | |
| --calculate ray position and direction | |
| camerax = 2 * x / w - 1 --x-coordinate in camera space | |
| rayposx = posx | |
| rayposy = posy | |
| raydirx = dirx + (planex * camerax) | |
| raydiry = diry + (planey * camerax) | |
| --which box of the map we're in | |
| mapx = flr(rayposx) | |
| mapy = flr(rayposy) | |
| --length of ray from one x or y-side to next x or y-side | |
| newdeltadistx = safesqrt(1 + (raydiry * raydiry) / (raydirx * raydirx)) | |
| newdeltadisty = safesqrt(1 + (raydirx * raydirx) / (raydiry * raydiry)) | |
| if(newdeltadistx>=1) then | |
| deltadistx = newdeltadistx | |
| end | |
| if(newdeltadisty>=1) then | |
| deltadisty = newdeltadisty | |
| end | |
| hit = 0 --was there a wall hit? | |
| --calculate step and initial sidedist | |
| if (raydirx < 0) then | |
| stepx = -1 | |
| sidedistx = (rayposx - mapx) * deltadistx | |
| else | |
| stepx = 1 | |
| sidedistx = (mapx + 1.0 - rayposx) * deltadistx | |
| end | |
| if (raydiry < 0) then | |
| stepy = -1 | |
| sidedisty = (rayposy - mapy) * deltadisty | |
| else | |
| stepy = 1 | |
| sidedisty = (mapy + 1.0 - rayposy) * deltadisty | |
| end | |
| --perform dda | |
| raylength = 0 | |
| while (hit == 0) do | |
| --jump to next map square, or in x-direction, or in y-direction | |
| if (sidedistx <= sidedisty) then | |
| sidedistx = sidedistx + deltadistx | |
| mapx = mapx + stepx | |
| side = 0 | |
| else | |
| sidedisty = sidedisty + deltadisty | |
| mapy = mapy + stepy | |
| side = 1 | |
| end | |
| raylength = raylength + 1 | |
| if(raylength>=50) then hit=1 end | |
| --check if ray has hit a wall | |
| currentwall = mget(flr(mapx), flr(mapy)) | |
| if (blocks[currentwall+1].visible) then | |
| hit = 1 | |
| if(blocks[currentwall+1].transparent or mapget(flr(mapx), flr(mapy)) > 0) then | |
| if(layer == 0) then | |
| -- count the transparent collisions, go to the end | |
| hit = 0 | |
| shootthrough = shootthrough + 1 | |
| redrawstripe[x+1] = shootthrough | |
| if(transparentthisframe) then | |
| transparent_end = x | |
| else | |
| transparentthisframe = true | |
| transparent_start = x | |
| end | |
| else | |
| -- stop at the numbered wall | |
| hit = 0 | |
| shootthrough = shootthrough + 1 | |
| if(shootthrough == layer) then | |
| hit = 1 | |
| end | |
| end | |
| end | |
| if(blocks[currentwall+1].halfway) then | |
| if(hit == 1) then | |
| if(side == 0) then | |
| if (sidedistx <= sidedisty) then | |
| --ray shoots straight through, so definitely door | |
| rayposx = rayposx - (stepx/3) | |
| else | |
| -- take the smaller distance: the wall, or the door | |
| walldist = abs(((mapy+stepy) - rayposy + (1 - stepy) / 2) / raydiry) | |
| doordist = abs((mapx - (rayposx - (stepx/3)) + (1 - stepx) / 2) / raydirx) | |
| if(doordist<walldist) then | |
| side = 0 | |
| rayposx = rayposx - (stepx/3) | |
| else | |
| side = 1 | |
| mapy = mapy + stepy | |
| end | |
| end | |
| elseif(side == 1) then | |
| if (sidedistx <= sidedisty) then | |
| -- take the smaller distance: the wall, or the door | |
| walldist = abs(((mapx+stepx) - rayposx + (1 - stepx) / 2) / raydirx) | |
| doordist = abs((mapy - (rayposy - (stepy/3)) + (1 - stepy) / 2) / raydiry) | |
| if(doordist<walldist) then | |
| side = 1 | |
| rayposy = rayposy - (stepy/3) | |
| else | |
| side = 0 | |
| mapx = mapx + stepx | |
| end | |
| else | |
| --ray shoots straight through, so definitely door | |
| rayposy = rayposy - (stepy/3) | |
| end | |
| end | |
| end | |
| end | |
| end | |
| end | |
| --calculate distance of perpendicular ray (oblique distance will give fisheye effect!) | |
| if (side == 0) then | |
| perpwalldist = abs((mapx - rayposx + (1 - stepx) / 2) / raydirx) | |
| else | |
| perpwalldist = abs((mapy - rayposy + (1 - stepy) / 2) / raydiry) | |
| end | |
| --store walldistance in buffer for sprites later | |
| zbuffer[x+1] = perpwalldist | |
| --calculate height of line to draw on screen | |
| rayheight = abs(flr(wallheight / perpwalldist)) | |
| --calculate lowest and highest pixel to fill in current stripe | |
| drawstart = -(rayheight / 2) + (h / 2) | |
| if(drawstart < 0) then | |
| drawstart = 0 | |
| end | |
| drawend = rayheight / 2 + h / 2 | |
| if (drawend >= h) then | |
| drawend = h - 1 | |
| end | |
| dodrawing = true | |
| if(layer ~= 0) then | |
| if(sss[x+1] > drawend - drawstart) then | |
| dodrawing = false | |
| end | |
| end | |
| if(dodrawing) then | |
| --texturing calculations | |
| texnum = mget(mapx, mapy) | |
| --calculate value of wallx | |
| if (side == 1) then | |
| wallx = rayposx + ((mapy - rayposy + (1 - stepy) / 2) / raydiry) * raydirx | |
| else | |
| wallx = rayposy + ((mapx - rayposx + (1 - stepx) / 2) / raydirx) * raydiry | |
| end | |
| wallx = wallx - flr(wallx) | |
| --x coordinate on the texture | |
| texx = flr(wallx * blocks[texnum+1].tex_w) | |
| if(side == 0) then | |
| if (raydirx > 0) then | |
| texx = blocks[texnum+1].tex_w - texx - 1 | |
| end | |
| end | |
| if(side == 1) then | |
| if(raydiry < 0) then | |
| texx = blocks[texnum+1].tex_w - texx - 1 | |
| end | |
| end | |
| for y = drawstart,drawend do | |
| d = y - (h * 0.5) + (rayheight * 0.5) | |
| texy = ((d * blocks[texnum+1].tex_h) / rayheight) | |
| if (texy >= blocks[texnum+1].tex_h-1) then | |
| texy = blocks[texnum+1].tex_h-1 | |
| end | |
| if (blocks[texnum+1].door) then | |
| --Draw partial wall | |
| texy = texy + mapget(mapx, mapy) | |
| if(texy <= blocks[texnum+1].tex_h) then | |
| ci = sget(blocks[texnum+1].tex_x+texx,blocks[texnum+1].tex_y+texy) | |
| if(ci < 15) then | |
| if(uselighting) then ci = darker(ci, flr(perpwalldist-1.5+(glow/2))) end | |
| rectfill((x * xscale), (y * yscale), (x * xscale) + xdraw, (y * yscale) + ydraw, ci) | |
| end | |
| end | |
| else | |
| ci = sget(blocks[texnum+1].tex_x+texx,blocks[texnum+1].tex_y+texy) | |
| if(ci < 15) then | |
| if(uselighting) then ci = darker(ci, flr(perpwalldist-1.5+(glow/2))) end | |
| rectfill((x * xscale), (y * yscale), (x * xscale) + xdraw, (y * yscale) + ydraw, ci) | |
| end | |
| end | |
| end | |
| end | |
| end | |
| function drawfloorstripe(x) | |
| if(showfloor) then | |
| --floor casting | |
| floorxwall = 0.0 floorywall = 0.0 --x, y position of the floor texel at the bottom of the wall | |
| --4 different wall directions possible | |
| if(side == 0) then | |
| if(raydirx > 0) then | |
| floorxwall = mapx | |
| floorywall = mapy + wallx | |
| else | |
| floorxwall = mapx + 1.0 | |
| floorywall = mapy + wallx | |
| end | |
| end | |
| if(side == 1) then | |
| if(raydiry > 0) then | |
| floorxwall = mapx + wallx | |
| floorywall = mapy | |
| else | |
| floorxwall = mapx + wallx | |
| floorywall = mapy + 1.0 | |
| end | |
| end | |
| distwall = perpwalldist | |
| distplayer = 0.0 | |
| if (drawend < 0) then | |
| drawend = h -- becomes < 0 when the integer overflows | |
| end | |
| --draw the floor from drawend to the bottom of the screen | |
| for y = drawend + 1,h+1,2 do | |
| currentdist = h / (2.0 * y - h) -- you could make a small lookup table for this instead | |
| weight = (currentdist - distplayer) / (distwall - distplayer) | |
| currentfloorx = weight * floorxwall + (1.0 - weight) * posx | |
| currentfloory = weight * floorywall + (1.0 - weight) * posy | |
| floortexx = flr(currentfloorx * texwidth) % texwidth; | |
| floortexy = flr(currentfloory * texheight) % texheight; | |
| --floortexture = map.floorat(int(currentfloorx), int(currentfloory)); | |
| --ciellingtexture = map.ceilingat(int(currentfloorx), int(currentfloory)); | |
| floortexture = 0; | |
| ciellingtexture = 0; | |
| if(floortexture>-1) then | |
| ci = sget((floortexture*8)+floortexx,floortexy + 8) | |
| if(uselighting) then ci = darker(ci, flr(currentdist+0.5-glow/4)) end | |
| rectfill((x * xscale), (y * yscale), (x * xscale) + xdraw, (y * yscale) + ydrawfloor, ci) | |
| end | |
| if(showceiling) then | |
| if(ciellingtexture>-1) then | |
| ci = sget((ciellingtexture*8)+floortexx,floortexy + 8) | |
| if(uselighting) then ci = darker(ci, flr(currentdist+0.5-glow/4)) end | |
| rectfill((x * xscale), ((h-y) * yscale) - ydrawfloor + 1, (x * xscale) + xdraw, ((h-y) * yscale) + 1, ci) | |
| end | |
| end | |
| end | |
| end | |
| end | |
| function raycast() | |
| palt(0, false) | |
| palt(15, true) | |
| raylength = 0 | |
| texx = 0 texy = 0 d = 0 | |
| x = 0 y = 0 | |
| transparentthisframe = false | |
| transparent_start = 0 transparent_end = w | |
| for x = 0,w,2 do | |
| sss[x+1] = 0 sss[x+2] = 0 | |
| drawstripe(x, 0) | |
| drawfloorstripe(x) | |
| end | |
| -- sprite mapping | |
| for i=0,numentities do | |
| so[i+1] = i | |
| spritedistance[i+1] = ((posx - e[i+1].posx) * (posx - e[i+1].posx)) + ((posy - e[i+1].posy) * (posy - e[i+1].posy)) | |
| end | |
| combsort() | |
| for i=0,numentities do | |
| if(e[so[i+1]+1].active) then | |
| spritex = e[so[i+1]+1].posx - posx | |
| spritey = e[so[i+1]+1].posy - posy | |
| e[so[i+1]+1].insight = false | |
| invdet = 1.0 / (planex * diry - dirx * planey) | |
| transformx = invdet * (diry * spritex - dirx * spritey) | |
| transformy = invdet * (-planey * spritex + planex * spritey) | |
| spritescreenx = flr((w / 2) * (1 + transformx / transformy)) | |
| if(e[so[i+1]+1].position == "bottom") then | |
| udiv = 2 vdiv = 2 | |
| vmove = wallheight/2 | |
| elseif(e[so[i+1]+1].position == "top") then | |
| udiv = 2 vdiv = 2 | |
| vmove = -wallheight/2 | |
| elseif(e[so[i+1]+1].position == "center") then | |
| udiv = 2 vdiv = 2 | |
| vmove = 0.0 | |
| elseif(e[so[i+1]+1].position == "huge") then | |
| udiv = 0.5 vdiv = 0.5 | |
| vmove = -wallheight/2 | |
| else | |
| udiv = 1 vdiv = 1 | |
| vmove = 0.0 | |
| end | |
| --parameters for scaling and moving the sprites | |
| vmovescreen = flr(vmove / transformy) | |
| --calculate height of the sprite on screen | |
| spriteheight = abs(flr(h / (transformy))) / vdiv; | |
| --using "transformy" instead of the real distance prevents fisheye | |
| --calculate lowest and highest pixel to fill in current stripe | |
| drawstarty = -spriteheight / 2 + h / 2 + vmovescreen | |
| if(drawstarty < 0) then | |
| drawstarty = 0 | |
| end | |
| drawendy = spriteheight / 2 + h / 2 + vmovescreen | |
| if(drawendy >= h) then | |
| drawendy = h - 1 | |
| end | |
| --calculate width of the sprite | |
| spritewidth = abs(flr(64 / (transformy))) / udiv | |
| drawstartx = -spritewidth / 2 + spritescreenx | |
| if(drawstartx < 0) then | |
| drawstartx = 0 | |
| end | |
| drawendx = spritewidth / 2 + spritescreenx | |
| if(drawendx >= w) then | |
| drawendx = w - 1 | |
| end | |
| --loop through every vertical stripe of the sprite on screen | |
| if(dospritedraw(drawstartx, drawendx, drawstarty, drawendy, transformy)) then | |
| sspr(e[so[i+1]+1].tex_x,e[so[i+1]+1].tex_y,e[so[i+1]+1].tex_w,e[so[i+1]+1].tex_h,drawstartx*2,drawstarty*2,(drawendx - drawstartx)*2, (drawendy - drawstarty)*2) | |
| e[so[i+1]+1].insight = true | |
| else | |
| check = 0 | |
| for stripe = drawstartx,drawendx do | |
| texx = flr((stripe - ( -spritewidth / 2 + spritescreenx)) * (e[so[i+1]+1].tex_w) / spritewidth) | |
| if(texx > e[so[i+1]+1].tex_w-1) then texx = e[so[i+1]+1].tex_w-1 end | |
| if(transformy > 0 and stripe >= 0 and stripe < w and transformy < zbuffer[flr(stripe)+1]) then | |
| check = 1 --at least one stripe drawn | |
| sss[flr(stripe)+1] = drawendy - drawstarty,drawendy | |
| for y = drawstarty,drawendy do | |
| d = (y-vmovescreen) - ((h + spriteheight) * 0.5) | |
| texy = ((d * (e[so[i+1]+1].tex_h)) / spriteheight) | |
| if(texy>-1) then texy = -1 end | |
| ci = sget(e[so[i+1]+1].tex_x + texx,e[so[i+1]+1].tex_y + e[so[i+1]+1].tex_h + texy) | |
| if(ci < 15) then | |
| rectfill((stripe * xscale), (y * yscale), (stripe * xscale)+3, (y * yscale) + 1, ci) | |
| end | |
| end | |
| else | |
| end | |
| end | |
| if(check == 1) then e[so[i+1]+1].insight = true end | |
| end | |
| if(e[so[i+1]+1].insight) then | |
| if(abs(transformx)>1.5 or transformy<0) then | |
| e[so[i+1]+1].insight = false | |
| end | |
| end | |
| end | |
| end | |
| -- check for transparent walls | |
| if(transparentthisframe) then | |
| for x = transparent_start,transparent_end,2 do | |
| while(redrawstripe[x+1] > 0) do | |
| drawstripe(x, redrawstripe[x+1]) | |
| redrawstripe[x+1] = redrawstripe[x+1] - 1 | |
| end | |
| end | |
| end | |
| end | |
| function dospritedraw(sx, ex, sy, ey, ty) | |
| check = 0 | |
| if(ty>0 and sy>0 and ey<h and sx>0 and ex<w-1) then | |
| for stripe = sx,ex do | |
| sss[flr(stripe)+1] = ey - sy | |
| if(zbuffer[flr(stripe)+1]>0) then | |
| if(ty > zbuffer[flr(stripe)+1]) then | |
| check = 1 | |
| end | |
| end | |
| end | |
| else | |
| return false | |
| end | |
| if(check == 0) then | |
| return true | |
| end | |
| return false | |
| end | |
| function combsort() | |
| gap = numentities | |
| swapped = false | |
| loopcheck = false | |
| if(gap > 1) then loopcheck = true end | |
| if(swapped) then loopcheck = true end | |
| while (loopcheck == true) do | |
| --shrink factor 1.3 | |
| gap = (gap * 10) / 13 | |
| if (gap == 9) then gap = 11 end | |
| if (gap == 10) then gap = 11 end | |
| if (gap < 1) then gap = 1 end | |
| swapped = false | |
| for i = 0,numentities-gap do | |
| j = flr(i + gap) | |
| if (spritedistance[i+1] < spritedistance[j+1]) then | |
| tempn = spritedistance[i+1]; | |
| spritedistance[i+1] = spritedistance[j+1]; | |
| spritedistance[j+1] = tempn; | |
| tempi = so[i+1]; | |
| so[i+1] = so[j+1]; | |
| so[j+1] = tempi; | |
| swapped = true; | |
| end | |
| end | |
| loopcheck = false | |
| if(gap > 1) then loopcheck = true end | |
| if(swapped) then loopcheck = true end | |
| end | |
| end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment