From e17a94bffc2846214ace127a224531b8aef66b4f Mon Sep 17 00:00:00 2001 From: Martin Haye Date: Sun, 13 Oct 2013 14:54:38 -0700 Subject: [PATCH] Ported Javascript sprite code from http://dev.opera.com/articles/view/3d-games-with-canvas-and-raycasting-part-2/ --- .../src/raycast/javascript/intcast.htm | 61 ++- .../virtual/src/raycast/javascript/intcast.js | 487 ++++++++++++------ .../src/raycast/javascript/sprites/armor.png | Bin 0 -> 1233 bytes .../src/raycast/javascript/sprites/lamp.png | Bin 0 -> 407 bytes .../raycast/javascript/sprites/plantgreen.png | Bin 0 -> 1000 bytes .../javascript/sprites/tablechairs.png | Bin 0 -> 715 bytes .../raycast/javascript/{ => walls}/walls.png | Bin .../src/raycast/javascript/walls/walls_1.png | Bin 0 -> 2423 bytes .../src/raycast/javascript/walls/walls_2.png | Bin 0 -> 1920 bytes .../src/raycast/javascript/walls/walls_3.png | Bin 0 -> 3043 bytes .../src/raycast/javascript/walls/walls_4.png | Bin 0 -> 1205 bytes 11 files changed, 357 insertions(+), 191 deletions(-) create mode 100755 Platform/Apple/virtual/src/raycast/javascript/sprites/armor.png create mode 100755 Platform/Apple/virtual/src/raycast/javascript/sprites/lamp.png create mode 100755 Platform/Apple/virtual/src/raycast/javascript/sprites/plantgreen.png create mode 100755 Platform/Apple/virtual/src/raycast/javascript/sprites/tablechairs.png rename Platform/Apple/virtual/src/raycast/javascript/{ => walls}/walls.png (100%) create mode 100755 Platform/Apple/virtual/src/raycast/javascript/walls/walls_1.png create mode 100755 Platform/Apple/virtual/src/raycast/javascript/walls/walls_2.png create mode 100755 Platform/Apple/virtual/src/raycast/javascript/walls/walls_3.png create mode 100755 Platform/Apple/virtual/src/raycast/javascript/walls/walls_4.png diff --git a/Platform/Apple/virtual/src/raycast/javascript/intcast.htm b/Platform/Apple/virtual/src/raycast/javascript/intcast.htm index f351a09b..53ec2e87 100755 --- a/Platform/Apple/virtual/src/raycast/javascript/intcast.htm +++ b/Platform/Apple/virtual/src/raycast/javascript/intcast.htm @@ -2,12 +2,16 @@ JScript Lawless Legends Testbed @@ -62,5 +79,7 @@ +
+ \ No newline at end of file diff --git a/Platform/Apple/virtual/src/raycast/javascript/intcast.js b/Platform/Apple/virtual/src/raycast/javascript/intcast.js index b01acb8a..797707e9 100644 --- a/Platform/Apple/virtual/src/raycast/javascript/intcast.js +++ b/Platform/Apple/virtual/src/raycast/javascript/intcast.js @@ -1,4 +1,5 @@ +// just a few helper functions var $ = function(id) { return document.getElementById(id); }; var dc = function(tag) { return document.createElement(tag); }; @@ -19,9 +20,35 @@ var map = [ [1,2,3,3,3,2,2,1,2,4,2,2,2] ]; +var itemTypes = [ + { img : "sprites/tablechairs.png", block : true }, // 0 + { img : "sprites/armor.png", block : true }, // 1 + { img : "sprites/plantgreen.png", block : true }, // 2 + { img : "sprites/lamp.png", block : false } // 3 +]; + +var mapItems = [ + + // lamps in center area + {type:3, x:9, y:7}, + {type:3, x:15, y:7}, + + // lamps in bottom corridor + {type:3, x:5, y:12}, + {type:3, x:11, y:12}, + {type:3, x:11, y:12}, + + // tables in long bottom room + {type:0, x:10, y:10}, + {type:0, x:11, y:10}, + // lamps in long bottom room + {type:3, x:8, y:10}, + {type:3, x:11, y:10} +]; + // Player attributes [ref BigBlue2_10] var player = { - x : 11.0, // current x, y position + x : 7.0, // current x, y position y : 10.5, dir : 0, // the direction that the player is turning, either -1 for left or 1 for right. angleNum : 0, // the current angle of rotation @@ -32,7 +59,7 @@ var player = { var options = 0; -var debugRay = 0; /* Debugging info printed about this ray num, or null for none */ +var debugRay = null; /* Debugging info printed about this ray num, or null for none */ var maxAngleNum = 16; @@ -44,6 +71,8 @@ var miniMapScale = 8; var screenWidth = 504; var screenHeight = 512; +var showOverlay = true; + var stripWidth = 1; var fov = 45 * Math.PI / 180; @@ -55,6 +84,24 @@ var viewDist = (screenWidth/2) / Math.tan((fov / 2)); var twoPI = Math.PI * 2; var numTextures = 4; +var wallTextures = [ + "walls/walls_1.png", + "walls/walls_2.png", + "walls/walls_3.png", + "walls/walls_4.png" +]; + +var userAgent = navigator.userAgent.toLowerCase(); +var isGecko = userAgent.indexOf("gecko") != -1 && userAgent.indexOf("safari") == -1; + +// enable this to use a single image file containing all wall textures. This performs better in Firefox. Opera likes smaller images. +var useSingleTexture = isGecko; + +var screenStrips = []; +var overlay; + +var fps = 0; +var overlayText = ""; // Tables var precastData = []; @@ -72,40 +119,93 @@ function init() { initScreen(); initCast(); + initSprites(); drawMiniMap(); gameCycle(); + renderCycle(); } -var screenStrips = []; +var spriteMap; +var visibleSprites = []; +var oldVisibleSprites = []; -function initScreen() { +function initSprites() { + spriteMap = []; + for (var y=0;y cycleDelay) { + cycleDelay = Math.max(1, cycleDelay - (timeDelta - cycleDelay)) + } + + setTimeout(gameCycle, cycleDelay); + + lastGameCycleTime = now; +} + + +var lastRenderCycleTime = 0; + +function renderCycle() { + + updateMiniMap(); + + castRays(); + + // time since last rendering + var now = new Date().getTime(); + var timeDelta = now - lastRenderCycleTime; + var cycleDelay = 1000 / 30; + if (timeDelta > cycleDelay) { + cycleDelay = Math.max(1, cycleDelay - (timeDelta - cycleDelay)) + } + lastRenderCycleTime = now; + setTimeout(renderCycle, cycleDelay); + + fps = 1000 / timeDelta; + if (showOverlay) { + updateOverlay(); + } } // Set up data tables prior to rendering [ref BigBlue2_20] @@ -113,7 +213,6 @@ function initCast() { var i; - console.log("Initializing cast data."); precastData = []; for (var angleNum = 0; angleNum < maxAngleNum; angleNum++) { @@ -151,8 +250,6 @@ function initCast() tbl_pow2_w_w = []; for (i=0; i<256; i++) tbl_pow2_w_w[i] = ubyte((Math.pow(2, i / 255) - 1) * 255); - - console.log("Done."); } function prepCast(angleNum, x) @@ -162,11 +259,6 @@ function prepCast(angleNum, x) var dirX = Math.cos(angle); var dirY = Math.sin(angle); - if (x == 0) - console.log("angleNum=" + angleNum + - ", dirX=" + wordToHex(uword((dirX*64) & 0xFFFF)) + - ", dirY=" + wordToHex(uword((dirY*64) & 0xFFFF))); - // Compute the camera plane, which is perpendicular to the direction vector var planeX = -Math.sin(angle) * 0.5; var planeY = Math.cos(angle) * 0.5; @@ -258,6 +350,116 @@ function printTbl(arr) { console.log(line); } +function clearSprites() { + // clear the visible sprites array but keep a copy in oldVisibleSprites for later. + // also mark all the sprites as not visible so they can be added to visibleSprites again during raycasting. + oldVisibleSprites = []; + for (var i=0;i" + overlayText; + overlayText = ""; +} + + +function initScreen() { + + var screen = $("screen"); + + for (var i=0;i 0) - wallX = 1 - wallX; - break; - } - } - else { - sideDistY += deltaDistY; - mapY += stepY; - if (x == debugRay) { - console.log(" side1, mapX=" + mapX + ", mapY=" + mapY + - ", sideDistX=" + sideDistX.toString() + - ", sideDistY=" + sideDistY.toString()); - } - if (map[mapY][mapX] > 0) { - if (x == debugRay) - console.log(" hit side 1"); - perpWallDist = (mapY - rayPosY + (1 - stepY) / 2) / rayDirY; - wallX = (rayPosX + perpWallDist * rayDirX) % 1; - if (rayDirY < 0) - wallX = 1 - wallX; - break; - } - } - } - - perpWallDist = Math.abs(perpWallDist); - - if (perpWallDist == 0) - return { wallType:0, textureX:0, height:0 }; - - // Calculate height of line to draw on screen - var lineHeight = Math.abs(Math.floor(screenHeight / perpWallDist)); - - if (x == debugRay) { - console.debug(" perpWallDist=" + perpWallDist.toString() + - ", lineHeight=" + lineHeight.toString()); - } - - // Wrap it all in a nice package. - return { wallType:map[mapY][mapX], textureX:wallX, height:lineHeight }; + height: lineHeight, + xWallHit: bMapX, + yWallHit: bMapY }; } function drawStrip(stripIdx, lineData) @@ -820,19 +905,64 @@ function drawStrip(stripIdx, lineData) // it half way down the screen and then half the wall height back up. var top = Math.round((screenHeight - lineData.height) / 2); - strip.style.height = lineData.height+"px"; - strip.style.top = top+"px"; + var imgTop = 0; + + var styleHeight; + if (useSingleTexture) { + // then adjust the top placement according to which wall texture we need + imgTop = Math.floor(height * (lineData.wallType-1)); + var styleHeight = Math.floor(height * numTextures); + } else { + var styleSrc = wallTextures[lineData.wallType-1]; + if (strip.oldStyles.src != styleSrc) { + strip.src = styleSrc; + strip.oldStyles.src = styleSrc + } + var styleHeight = lineData.height; + } + + if (strip.oldStyles.height != styleHeight) { + strip.style.height = styleHeight + "px"; + strip.oldStyles.height = styleHeight + } - strip.img.style.height = Math.floor(lineData.height * numTextures) + "px"; - strip.img.style.width = Math.floor(width*2) +"px"; - strip.img.style.top = -Math.floor(lineData.height * (lineData.wallType-1)) + "px"; - var texX = Math.round(lineData.textureX*width); - if (texX > width - stripWidth) texX = width - stripWidth; + //texX += (wallIsShaded ? width : 0); - strip.img.style.left = -texX + "px"; + var styleWidth = Math.floor(width*2); + if (strip.oldStyles.width != styleWidth) { + strip.style.width = styleWidth +"px"; + strip.oldStyles.width = styleWidth; + } + + var styleTop = top - imgTop; + if (strip.oldStyles.top != styleTop) { + strip.style.top = styleTop + "px"; + strip.oldStyles.top = styleTop; + } + + var styleLeft = stripIdx*stripWidth - texX; + if (strip.oldStyles.left != styleLeft) { + strip.style.left = styleLeft + "px"; + strip.oldStyles.left = styleLeft; + } + + var styleClip = "rect(" + imgTop + ", " + (texX + stripWidth) + ", " + (imgTop + lineData.height) + ", " + texX + ")"; + if (strip.oldStyles.clip != styleClip) { + strip.style.clip = styleClip; + strip.oldStyles.clip = styleClip; + } + + var dwx = lineData.xWallHit - player.x; + var dwy = lineData.yWallHit - player.y; + + var wallDist = dwx*dwx + dwy*dwy; + strip.style.zIndex = -Math.floor(wallDist*1000); + + if (stripIdx == debugRay) + console.log("wallDist=" + wallDist + ", zIndex=" + (-Math.floor(wallDist*1000))); } function move() { @@ -862,8 +992,18 @@ function isBlocking(x,y) { if (y < 0 || y >= mapHeight || x < 0 || x >= mapWidth) return true; + var ix = Math.floor(x); + var iy = Math.floor(y); + // return true if the map block is not 0, ie. if there is a blocking wall. - return (map[Math.floor(y)][Math.floor(x)] != 0); + if (map[iy][ix] != 0) + return true; + + if (spriteMap[iy][ix] && spriteMap[iy][ix].block) + return true; + + return false; + } function updateMiniMap() { @@ -922,14 +1062,21 @@ function drawMiniMap() { var wall = map[y][x]; if (wall > 0) { // if there is a wall block at this (x,y) ... - ctx.fillStyle = "rgb(200,200,200)"; ctx.fillRect( // ... then draw a block on the minimap x * miniMapScale, y * miniMapScale, miniMapScale,miniMapScale ); + } + if (spriteMap[y][x]) { + ctx.fillStyle = "rgb(100,200,100)"; + ctx.fillRect( + x * miniMapScale + miniMapScale*0.25, + y * miniMapScale + miniMapScale*0.25, + miniMapScale*0.5,miniMapScale*0.5 + ); } } } diff --git a/Platform/Apple/virtual/src/raycast/javascript/sprites/armor.png b/Platform/Apple/virtual/src/raycast/javascript/sprites/armor.png new file mode 100755 index 0000000000000000000000000000000000000000..64cb7938fd0ca55615dc973fb41110fd8f2bc41f GIT binary patch literal 1233 zcma)6{ZrC+0RA9~Mqp^mQ=}8Yj3%YILYrh?5erv2GFrNFQi?InB-8Q*1(&OA*2)qo zX?>?+zLf18r8+ZvU$(_RRL8B1H1MVNX^{gk8sV9(w2Ja^AMch7H6nJ{i0nMfr9 z0LZZde!Rnx4|Kyj^jurXONaU7#3bZw&PvNUup?UnqEfSVO6akfJ9bIpB|B2{_uiIp z9i>v?22l)<$$(A=5)wdZDL@b~JPZs5pwYBL*a<**c=!VVdV722ayf*M&1RREm#3zt zibNuTK+w?8pjN9Pg6MQQNTZjqWePb%3Kfc#as zK*`%A;2mv|_F==34Es1BWux~3sCFB*LYhWjNsPvr$6Tmg<`n9Ih{w*z*b1VyLW)gY zdx#6+9^=#WpISe^aB5#fRm3A>uIl0BC3h)9Vg!oF^Oni8&)oaAZc$18@JzOzZkXY$$9ztI7C2?O_VP2Igw#5*fxmwQCuEAe=J$)qk z%n;UjVNU1Qf*w7RF?hpCnhV@reeK?tzD3MVH}RXVI)W>2 zX=wodIGMhvKrxT9*FPi9X||EEhm~BBV9**~vuYZGj{kyhCEO3ed*4}$RYeDuHMs~F zC4O^zRngJupM+fVwf687gnKJI)s{|X<(outHW;YL^P48Q`4sj2zWzBG9oHH|yCO8WekoYSuz*`Xsd>(( zP0lynqbwcdX(P`+a17M5HG+e`a<1;y`W^!4E}lDK*C?5Cc%#QeK2;fz#2G&pJu>bb zJM1>7`b~VF!atkrBdp!Bp2#8N)(7*Iw?CSDVz={&;v{Q&vnrWZeJG^NV?6+uwa?G^ zi=#pjTKB{Q3T0J`m&tvkG4a;S>8vW3GXcxf3jLoJty%057GzFgHcT~<(3Yl;okl#6 za1UJFb(g^JYB0)Cc82U#OMhcASw5jyN@PI(^UVb@^H-2uNOXe|O*R7k_qMmfBzxm$ i{avq&)hTb+DRE%!z>7JUtEc_L1H{I}@mqM}Z~g;nw@9S` literal 0 HcmV?d00001 diff --git a/Platform/Apple/virtual/src/raycast/javascript/sprites/lamp.png b/Platform/Apple/virtual/src/raycast/javascript/sprites/lamp.png new file mode 100755 index 0000000000000000000000000000000000000000..1771b1ab64b633d9c9e0305c4f0379eacc069530 GIT binary patch literal 407 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!BuiW)N`mv#O3D+9QW+dm@{>{( zJaZG%Q-e|yQz{EjrrH1%g#`G7xc2n))YR0>m@#9;iWLoiYFJVjSY|LVJYZn>!@yF* zz;c3t;SIx|KRZ|=7+5wiuyio&`LpB3pBpSo7+4AzQc_Y_d>9y3FtF?astNh?XU?BL zfBKHs1aeuv2bwQa666>BA2(nS-}LA@P~ApP7srr_TW>C%6lzxBX?S=cjd9D4tLxtX zpLcZaIh?V0{EI8HdxEkV-$|NZGR!W&|Ht!r2$7{( zJaZG%Q-e|yQz{EjrrH1%O$+b|ab+oBU~ynziC|z@!N72Zfu)8a~2-7|ZrOOz=eK(I%#R80(=%1|1%#RR zHRwN(XD||+Aa#l1`Hx+`Gn))A+C}aV$f)4E^fCN`tHWYZvl!NuZ&MvY+%&iyo`14u zmx`8bmXqO>iFbMZ*grP&wdsWGaTemeriU4&OGM{s<<40y7ZAi0#?;2_@Al!i$6F4; zYo|O#k{dVe6vz-Ng*$00yq?p6>$3dmLUad&Jx;7^*+vHRIzp zMn#SgFO%L0YZ=uY6&5b$ICel_0jKWu*i`~rE477m3ne?Qb(nBuBn1R{uXcWMnUTls z!BqqKd;k7Tce8K}aueOMeue0qU2M-eST1Z(GV@!!cEKlI`*4Sosb+|EXyJ1G88%y_| zSuV7@GRpCvK|nqrq{&z`;Oby?|2^~?S(#tsuV zPRQS0dGC4p=NuUU{@;skh|E4)v~kXP@y|JCMO=kN6?4)h{p)^NA7d)lKYjSI_NC($ z5BBZ2?W1;DwSWF&jwdxw{u=V!*w3W%#dOD0jo&A#Q#d|6&VTUgcDBK1wK+FCC;y&q z-ypgE{( zJaZG%Q-e|yQz{EjrrH1%RRs8ixX$rmc#^|V;-it{p|T}}!NS5K#75@N3#C&8j2K<7k_kB5iHAE0Rr3|k6Z_EdOu zFfd%WaG|HC=TC>if)tw-84hpWy!jIoW1%BbP*5;q#*906?(`k6VX~RQ0@R~X666>B zpE$sv&!^>%a1R1Gx$mrYrffOWJt74@BZmv@$%5~_smy!zyBxv;4XXa zEHUO|`OUOID%iLdnqDMvG=1kuel;!*+vA*)_>UHTQ$x{~WTSHN`^hF>#oGc0Cgd0oyi zCHz&SfEmMz3?{)^!Khy=SYA(OW)^6>`Kl<6wQ0(Ebr9@Pb~SIxXJlhAeE8e9 Tc1;}*D5ZG1`njxgN@xNAYgaq3 literal 0 HcmV?d00001 diff --git a/Platform/Apple/virtual/src/raycast/javascript/walls.png b/Platform/Apple/virtual/src/raycast/javascript/walls/walls.png similarity index 100% rename from Platform/Apple/virtual/src/raycast/javascript/walls.png rename to Platform/Apple/virtual/src/raycast/javascript/walls/walls.png diff --git a/Platform/Apple/virtual/src/raycast/javascript/walls/walls_1.png b/Platform/Apple/virtual/src/raycast/javascript/walls/walls_1.png new file mode 100755 index 0000000000000000000000000000000000000000..3ffa775228a58b32ba71c7c43f382f319588f280 GIT binary patch literal 2423 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 literal 0 HcmV?d00001 diff --git a/Platform/Apple/virtual/src/raycast/javascript/walls/walls_2.png b/Platform/Apple/virtual/src/raycast/javascript/walls/walls_2.png new file mode 100755 index 0000000000000000000000000000000000000000..3c485144daffa650c54f5f4a0589be0b151c67f8 GIT binary patch literal 1920 zcmV-`2Y>j9P)-cip5colQvsQc+e{$igw6z`p z_|{va&Uq+TsUI2EJ9NuG&ie*{(do^H`viCpRK>9T!rk(Z5p)1~TLCZ{^+pd66azeT zSS2tSCC30B<8u#n)QGEI7_0T4r1zw=PwToS1K>AT1%QwRKo~^=)TMlco|~GSsDM6m z44Xy?(6=h)Q3v_U!_CSX0N;=R1i;yRSONxM;uj(M)E>f!UUcH!AOZPCWhRw?jm#9Q z31D3tfWu%a0qvZb1mNMljqgSc0AOTp0NiC2dBX^WFNq$y1{5Hf4!RA{{{S!*K+zxo zF9=`*4qAXl1^{hpgevGHohtz(fcZls>Hz|vk5_Rt=Z3Gg4h6s_IH*9~i2pS=RIOuR zBY*_p72OE&0L@)YnI$RX!!&(z2Y@#I8vxq?8z`>>$;3~ikOjN}==cr5tC&dz{4WCx zhVQhuWGYb2z|Rc8i@}ftcm{Ped=UaS z)P=;Qg9LIZukUT&Ll&nL>e{@CT3oj0REt;v-diqvm}*%}Qr&RagX8j?1rP~fO=zCw z^DE2(hy=WCf*z(V0QGAt0$}SvUnpq5CxGwI13=dS0lpQuPOmv2mA{FHVp+Rn8w+KUpLr*0O%f~>zx98nZOPkNKFE=6^RrTV8f7S zm(2iJ1#M@P{f*vHfE`1gU3LRt6=b~j`re0Ys~Z%RN{LQ_Ecw*+8`)WfaNkbD7f zDggvCEnm9>;1CgcZ>zvffP{$1^18bKP650Cq}u>V0i0_o5&tMay$R6r0R^c40g%{Q zyx>`5{0<-yz3gEcl&|K7q2~M@V3nZMH5-5@GeDdINF#vRpaA44fb{^-k~^rNK4&H1 zQO~eyfU2N|SqZ>=4~dBc{o5qKXJR4%d7lK(#01G68?sj;jL$h0L@CrD+2e%NsS)Nd zr-BSc#^_HnqnVHluUvi9+TRT~lxhJ=G`;+J0{|M6O*vcj(cJ)m#;_^>3!pazaQ7t8 z+Xp~5sW$S@CqPeV380l?k5+nVry8bE>2bRE#Z<{V(( zoA8%X6d?3S+EjqUhqI7uq3_31_>RmWY!VeqO#$Uf*nr63G$ebGtI*QKcgwcNU83Sv zl+$&<{{bKuo_mcAARrnw0IOzS$Amohn#mpkzyXa%6wy>r9{w621OkXlsU`t6d={a4 z!Rs%87zuzrtxW=w&N>OsyBl6+M!Y|X1nBh%03>t@pr;U*nGx?#A_000rh*Rue<^_o zfMsD7AThD}dY6EAmlDVTD1}vk#Kfx64S+RzX#=sujg1h$8j^Xw*hggD*!^?K4L;m1|R_#)fE8w!Tu2wqN+Xs^eR~g;N6A*C_o^9jXrz>NP`>p zDp?2M-G%_z3(5RKcn4U!8_LPqJ3ur5S%iO{J7ai^!J78VvzP*8q;e%##L!otFVfq}8Hu`BeV!vFvaNl8RORCwCNS=*N5HVo5U zwiMg{|F;D|%5gH&ZO`dLwcY7Vc49)jfFKj{|9ryxl-JkEscwgTdmLL0x!mXduJk_f z>+Cu7v+A5@4{1-ooNoZjApTYWIIgh}HY?S}FMKuc~Ae**xVGjw};PkGP7 zz8~ZLwov_K0ywVM#V-f`)|S)u+Uoj40M+4L+j?7F@OJ_@XPx|V;%_K>?y-mUhX8`P z=A8X~Z$6OE6Mzk;@=M&d8R!AtoiEnz0FLAMh*OR9hy&<2fnQqhBhdrAJ6{aL0i5Sq zg<@S`)0v$Bj%YtcqUZon_)Vn)@CX68XRhKt|LF+(e~7Av03+YQ>+OUZ6) z0J3?Yjoyag!gm2)kFl4Mb3v^|xs`Wh2yzK!-uaqyn!pINamFej+pO?%fmcr;CR(qErl#Jssh+o zz@x6)RCNKS@!H$G;GF#Z#u#~MJVy%+l={-WJiq7x0Cr4?SE&+jkVp9m}}tM-wws7#B8^D< zgMmdFj6whm!m!F5_-UHuCllWHOC$n07%rI3Jf&}&)jJ-JN(HPI))SU%?S7eMAO|x6 zoOu%BY!O4AAO?U{?zdWAJ^^e>v1)n1Cx8nzyLZ6$%JnPS26Kq1KejMd!E zlz5)q&ZC*&ej5!+jA4tgSBm%mh4v+_WJe_va7l6APmN$TY(7x5; z7P?o4C#537Cq0^?g7F40PTIFx>}hyqcv2=$iLa&@?&b+FV1mdbm{yxX0IHRnJkXI4 zp@jM9xow?{2cKtS5)7|RR9=t4%T3)73Bj~%?-MM=t_uhegF{KcJNLRg;4UBl1|*mH zY)9Up=O6$yA0|Q2S1}PD<1Qco24sh$9v2AoIa`ka^ytjbV1^X}Yi9(&gvccl@H*mi zb|V59&6yw8-2;`4f>c2OOo%--q}hFfHML3rAetEa-KxY6a>dHGhJp})Yf}pYXM4jB z1|ThBl6@q4mMd1?7xW?lfTB^?V$CiO1OZqSb7z*UuOAxYK>*e-Kw3cV9!LUE?%J>- z%d+kj2LRnXVEqDMVQqQ90Q@ZO@F=uu0GKI1JYWDG1?~)$^37Ceh62D$d3yk?H`V(P zV%FqM{B}?jo2VJhxgEIrB!Gtp5bzNe^QUy1zcnY@r2yt~0`4Gyrw5q9Z~;2HOFjy| zmP$jjeW^Xd5C91g!C~e}QXvFQH8a$ZnOy9asC8r-Il+jr1?i)}gz=Wd zge?kz(NReTK%}=d7>W8}njnK+1F%K(#GKMcGj~2F0FhoV0w8f_f(&*I0DAnM_D3sW z-j!8oiOq1k>NEgUCmWRkJzxOn^8Ba^t2@v9oGC~;TD}3GI$?d#4Z#2e%}4oJB=2^N zi@Yqk03ZPXzgK6JKywcWz_SmoC-G9zk_!M(GO?*Votc*h1mM|{!9A^;3@rJzNo`JO zA+e3w-&m#w02xAAa?ggzLTNHE?XgR3QVWS~%s!Q;hX5J!(G1BAtzK4WD6rRNdV~Nf z#uT~3)q$$CDhW4glxETQ-pKAb_Sj925J13~B6qktP?ZKHAzI?RRX}K$N*}on51;@T za`eG6r9@zTs^Sd*LIeQ7;hKhmYAh7vMpOP8$N;M*?_sCj21XUpbfMasr z;-tta;ouZj)pyz&Tqp?-<13&D@&F&EVKknD^A;yXPl7>-hCiASLRB@Sv#*&b831!9 z?uNljO;!NHb#Eu|0u|}pCJV1@K9y0ZCW;K>zqFq*sL2XIn)i0XIt69~r9$fWRF+tV zcM^tty{3)AK@p<|G>52UA&IT*p>oQ5L-bChqq%0zn|5!jABsf)EcZj6O311t%%yye zKO72vSxrgjDfe+TC8SbrU3lMr&N82)nT3D^0Fr$vvef~Yndfe9exJnyO+=KUA{!h) z`eAo`A5TJ?{j9+1v>ZS?`7ouG%;f@Q=@bKC%3`R()%|QNEFY#!Ke#|yI%O;-j4A@F zaLOYAn8)XN{Wy_*yH49mX-Q+le~}^|=jW+kdrVU~VnUUb095tErj|c{G3hF8lM}8f zc{FVr5rCk6C;=`kr40sBX~LlfR989> z095$&HEl48=9;7h?@`@4L?{;@rRq-QvLpF^(V!@W#`PYl#pYfX!oBW8jC}L`R>-5hMZK*o|v_ z&>VoXoCEkE-?fSE*8k@Uh9ye%5WE4WufbF{c&z`A6%0$1utG4k1OzFt+kFnk3lZKw z>->3|azIPKP=2n??iZLRVf;KAmx_NXbFi#hc($3anofRvMDua9o3n+>$+9ZxYmxR# zA9|jhRiG`<;TY^_=_A(oT7>;v9~5c7AksTMVz!DMrTo5A{9GRx0CbuA^QoJ24Nonh z{M~wzt7PH}EvPnIrErB{TO2k=+g9xVbTaqsrY*Tb zuq_UoBj>d68-@K`7A}%Z-%J$JzqmlYH<#a(wA%xJ`5gG?C(P@+uXTU=^QRc!r1&`% lppS<1AJ2dN`2H^e1^`qLpSbZ7--G}F002ovPDHLkV1ln(f`$M9 literal 0 HcmV?d00001 diff --git a/Platform/Apple/virtual/src/raycast/javascript/walls/walls_4.png b/Platform/Apple/virtual/src/raycast/javascript/walls/walls_4.png new file mode 100755 index 0000000000000000000000000000000000000000..60023818a5478522e6b866c93122251cc80938ff GIT binary patch literal 1205 zcmV;m1WNmfP)uFQ8pWFMJGux7?4~vVLl@k z78WQV3|v4UBpnMqE*5=IKyLs51S&~HK~#9!)Y;o&qdE))P+i)Y-TwavpW>@zBtt^y z;n0@^n0Uo8*0zVfA0A&150Zz6K0N5-;qm$KAg;$Z|NUln^fU9ya!-9r_4uMcU*wK{ zW?otDX>XZJPx8lK{=o6MKd+BJE@zHc{R+yf<5Ib!UJ#<%lb?U+vwZH)>*J5gnd8;C zQeXXCDtBnRp#spF%K$$&KsJEhTn0GaYX-p40apNlWB|GY7%c_>b^s&*c?i%9AV-_v z-qA(#0)T7hPJq4!AS&OwHz!92zyNRy&iY#9K`=UoFR2SCgq zLxI{>f&;OG)l4LJ@Z;{utf zxLE?gDUdk8>|S00ux08EfGbmX04RM8Q;ayAiZO&9(2p~~&xGcNS`Ebvwc5lLpg%ZD zvlh(O|2cqv8-SMq!sk5j3Sc~+aATlg8~_&pdJ5qB;HLn|0O+-#HkkqRb$|o_ya3Pu zKpOzeh<10%ZOKe!ja27}b#dw6g$`Kw<&910;bY0SLFHQ4~nT79&Ok&>TPufDE8a zDx>t2w>Sq9pNK4=e4Yi^wNjFZ9AFlsS_*|DfKNmt$GXQ*wb#b0MC1W>WmNk*0B{Vz zF9W0|0=WQy?dsUBjN01lHb7T^tN^?Q&=o+x1Aqs}Lx7$Dc3}bs-~@nh5cW`b4Omvk znDbp3VOTO@2}&WrRl~V52_o4RFz34zfC+%if8z4MO#nGSoqQGmuc1_6Lg^a-wV~7l z+BY7t9Ib&(C}o)$MqM@3o=Uf&luUJcem>B#r@M0PFym>w*nH?*L5c!3c#| z@_+~M0N_^uu#v1S(N6$az<6@uCSEfOoB*~KxOG8WlUu-Cs>n>m90KGN$;eL5aVRwa zA4o7KV%ddKo@+zDLE%DS9?4Qb-8GE?^PVwKB7lx