ZoriaRPG

Zelda Classic Raycaster

Oct 1st, 2018
106
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. /////////////////////////////////////////////////////
  2. /////// Raycasting Engine Script, version 0.2 ///////
  3. /////// by blue_knight                        ///////
  4. /////////////////////////////////////////////////////
  5. /////////////////////////////////////////////////////
  6. // This is a fun little script
  7. // that renders the current screens in first person
  8. // using raycasting and column rendering.
  9. // X, Y is on the horizontal plane.
  10. // Z is up in 3D space.
  11. // This script has no set limits, except the map limit
  12. // 16x8 screens.
  13. /////////////////////////////////////////////////////
  14.  
  15. const int scrWidth  = 256;
  16. const int scrHeight = 176;
  17.  
  18. ffc script Raycaster
  19. {
  20.     /////////////////////////////
  21.     // startX     : start X position in virtual space.
  22.     // startY     : start Y position in virtual space.
  23.     // BackgroundTiles : Tile index for the background.
  24.     /////////////////////////////
  25.     void run(int startX, int startY, int BackgroundTiles)
  26.     {
  27.         //use virtual coordinates for Link's position.
  28.         //since he is not displayed, we don't bother keeping local coordinates, so Link's position is forced to the center.
  29.         float camPos_X = startX;
  30.         float camPos_Y = startY;
  31.         float camDir_X;
  32.         float camDir_Y;
  33.         float camYaw = 0;
  34.         float moveSpeed = 1.0;
  35.         float playerRadius = 16;
  36.        
  37.         //ginormous array...
  38.         int map_combo[1024];    //holds the 32x32 area centered on the camera.
  39.         int map_left_x=0;
  40.         int map_left_y=0;
  41.        
  42.         int map_cenX = 0;
  43.         int map_cenY = 0;
  44.        
  45.         int curScreen = Game->GetCurScreen();
  46.         int curMap = Game->GetCurMap();
  47.    
  48.         while (true)
  49.         {
  50.             //update the movement.
  51.             if ( Link->InputLeft )
  52.                 camYaw-=2;
  53.             else if ( Link->InputRight )
  54.                 camYaw+=2;
  55.                
  56.             if (camYaw < 0 )
  57.                 camYaw += 360;
  58.             else if ( camYaw >= 360 )
  59.                 camYaw -= 360;
  60.            
  61.             camDir_X = Cos(camYaw);
  62.             camDir_Y = Sin(camYaw);
  63.            
  64.             float newPosX = camPos_X;
  65.             float newPosY = camPos_Y;
  66.             float travelDirX;
  67.             float travelDirY;
  68.             bool bCollisionNeeded = false;
  69.             if ( Link->InputUp )
  70.             {
  71.                 newPosX = newPosX + camDir_X*moveSpeed;
  72.                 newPosY = newPosY + camDir_Y*moveSpeed;
  73.                 bCollisionNeeded = true;
  74.                
  75.                 travelDirX = camDir_X;
  76.                 travelDirY = camDir_Y;
  77.             }
  78.             else if ( Link->InputDown )
  79.             {
  80.                 newPosX = newPosX - camDir_X*moveSpeed;
  81.                 newPosY = newPosY - camDir_Y*moveSpeed;
  82.                 bCollisionNeeded = true;
  83.                
  84.                 travelDirX = -camDir_X;
  85.                 travelDirY = -camDir_Y;
  86.             }
  87.            
  88.             //Super basic collision for now.
  89.             //If we're intersecting a solid combo after moving, we revert the move.
  90.             //note that we actually check ahead in the direction of travel so we don't get too close to
  91.             //the wall.
  92.             if ( bCollisionNeeded )
  93.             {
  94.                 if ( ComboSolid( Floor(newPosX+travelDirX*playerRadius), Floor(newPosY+travelDirY*playerRadius), curMap, curScreen ) )
  95.                 {
  96.                     newPosX = camPos_X;
  97.                     newPosY = camPos_Y;
  98.                 }
  99.             }
  100.             camPos_X = newPosX;
  101.             camPos_Y = newPosY;
  102.            
  103.             //Read the area around the camera into an array
  104.             //whenever we change cells.
  105.             //This way we don't have to call GetComboFromTileIndex() or Game->GetComboData()
  106.             //up to 16 times per ray.
  107.             //This improves our performance by 40% or more.
  108.             int mx = camPos_X>>4;
  109.             int my = camPos_Y>>4;
  110.             if ( mx != map_cenX || my != map_cenY )
  111.             {
  112.                 map_cenX = mx;
  113.                 map_cenY = my;
  114.                 map_left_x = Max(mx-16,0);
  115.                 map_left_y = Max(my-16,0);
  116.                 for (int y=0; y<32; y++)
  117.                 {
  118.                     int yy = y+map_left_y;
  119.                     for (int x=0; x<32; x++)
  120.                     {
  121.                         int xx = x+map_left_x;
  122.                         map_combo[y*32+x] = GetComboFromTileIndex(xx, yy, curMap, curScreen);
  123.                     }
  124.                 }
  125.             }
  126.            
  127.             //Finally draw the world.
  128.             DrawWorld( camDir_X, camDir_Y, camPos_X, camPos_Y, BackgroundTiles, map_combo, map_left_x, map_left_y );
  129.            
  130.             DisableInput();
  131.            
  132.             Waitframe();
  133.         }
  134.     }
  135.    
  136.     void DisableInput()
  137.     {
  138.         Link->X = 128;
  139.         Link->Y = 88;
  140.         Link->InputLeft = false;
  141.         Link->InputRight = false;
  142.         Link->InputUp = false;
  143.         Link->InputDown = false;
  144.         Link->InputA = false;
  145.         Link->InputB = false;
  146.         Link->InputL = false;
  147.         Link->InputR = false;
  148.         Link->InputStart = false;
  149.         Link->InputEx1 = false;
  150.         Link->InputEx2 = false;
  151.         Link->InputEx3 = false;
  152.         Link->InputEx4 = false;
  153.     }
  154.    
  155.     bool ComboSolid(int x, int y, int map, int curScr)
  156.     {
  157.         bool solid = false;
  158.        
  159.         int cx = (x>>4)&15;
  160.         int cy = (y>>4)%11;
  161.        
  162.         int scr = curScr;
  163.         scr += ( x>>8 );
  164.         scr += ( Floor(y/176)<<4 );
  165.        
  166.         int s = Game->GetComboSolid( map, scr, (cy<<4)+cx );
  167.         if ( s != 0 )
  168.             solid = true;
  169.            
  170.         return solid;
  171.     }
  172.    
  173.     int GetComboFromTileIndex(int tx, int ty, int map, int curScr)
  174.     {
  175.         int cx = tx&15;
  176.         int cy = ty%11;
  177.        
  178.         int scr = curScr;
  179.         scr += ( tx>>4 );
  180.         scr += ( Floor(ty/11)<<4 );
  181.        
  182.         return Game->GetComboData( map, scr, (cy<<4)+cx );
  183.     }
  184.        
  185.     //draw the "3D" world.
  186.     void DrawWorld(float camDirX, float camDirY, float cX, float cY, int BackgroundTiles, int map_combo, int map_left_x, int map_left_y)
  187.     {
  188.         float cenY = scrHeight*0.5;
  189.        
  190.         //This camera has no pitch, though looking up and down can be faked later.
  191.         //Anyway, the camera plane is perpendicular to the camera direction,
  192.         //so a simple 2D "perp product" is good enough [i.e. P(x,y) = (-Dy,Dx)]
  193.         float planeX = -camDirY;
  194.         float planeY =  camDirX;
  195.                
  196.         //we do raycasting in "map space", where each tile = 1 unit.
  197.         float camX = cX/16;
  198.         float camY = cY/16;
  199.        
  200.         int mapX = Floor(camX);
  201.         int mapY = Floor(camY);
  202.        
  203.         //maximum extents, 8x8 screens for now.
  204.         int maxTileX = map_left_x+32;
  205.         int maxTileY = map_left_y+32;
  206.        
  207.         //maximum number of raycasting steps. Setting this lower
  208.         //will improve performance, setting it higher allows more distant walls to be rendered.
  209.         int MAX_STEPS = 16;
  210.        
  211.         //Draw the background.
  212.         Screen->DrawTile(1, 0, 0, BackgroundTiles, 1, 11, 0, 256, 176, 0, 0, 0, 0, false, 128);
  213.                
  214.         //Note that we're pixel doubling for performance, later this should be an option
  215.         //for people with fast computers.
  216.         for (int x=0; x<scrWidth; x+=2)
  217.         {
  218.             int mx = mapX;
  219.             int my = mapY;
  220.            
  221.             //compute the screen ray from the x position and camera paramters.
  222.             float sx = (2 * x/scrWidth) - 1;
  223.             float rayDirX = camDirX + planeX*sx;
  224.             float rayDirY = camDirY + planeY*sx;
  225.            
  226.             //compute the DDA parameters, will detail in some documentation later.
  227.             float rXX = rayDirX*rayDirX;
  228.             float rYY = rayDirY*rayDirY;
  229.            
  230.             float deltaDistX = 32767;
  231.             float deltaDistY = 32767;
  232.             if ( rXX != 0 ) deltaDistX = Sqrt( 1.0 + rYY/rXX );
  233.             if ( rYY != 0 ) deltaDistY = Sqrt( 1.0 + rXX/rYY );
  234.        
  235.             int stepX;
  236.             int stepY;
  237.             float sideDistX;
  238.             float sideDistY;
  239.             if ( rayDirX < 0 )
  240.             { stepX = -1; sideDistX = (camX - mx) * deltaDistX; }
  241.             else
  242.             { stepX = 1; sideDistX = (mx + 1.0 - camX)*deltaDistX; }
  243.            
  244.             if ( rayDirY < 0 )
  245.             { stepY = -1; sideDistY = (camY - my)*deltaDistY; }
  246.             else
  247.             { stepY = 1; sideDistY = (my + 1.0 - camY)*deltaDistY; }
  248.            
  249.             //now that we have the DDA parameters, actually walk the ray and find the closest intersecting wall.
  250.             int hit = 0;
  251.             int iter = 0;
  252.             int side;
  253.             while (hit == 0 && iter < MAX_STEPS)
  254.             {
  255.                 if ( sideDistX < sideDistY )
  256.                 {
  257.                     sideDistX += deltaDistX;
  258.                     mx += stepX;
  259.                     side = 0;
  260.                     if ( mx < map_left_x || mx >= maxTileX )
  261.                         break;
  262.                 }
  263.                 else
  264.                 {
  265.                     sideDistY += deltaDistY;
  266.                     my += stepY;
  267.                     side = 1;
  268.                     if ( my < map_left_y || my >= maxTileY )
  269.                         break;
  270.                 }
  271.                 hit = map_combo[ ((my-map_left_y)<<5)+(mx-map_left_x) ];
  272.                 iter++;
  273.             }
  274.            
  275.             //if we've hit something we figure out the column to render.
  276.             if ( hit )
  277.             {
  278.                 float wallDist;
  279.                 int u;
  280.                 //compute the distance to the wall and the texture coordinate.
  281.                 if ( side == 0 )
  282.                 {
  283.                     wallDist = (mx - camX + (1 - stepX)*0.5 ) / rayDirX;
  284.                     u = camY + rayDirY*wallDist;
  285.                 }
  286.                 else
  287.                 {
  288.                     wallDist = (my - camY + (1 - stepY)*0.5 ) / rayDirY;
  289.                     u = camX + rayDirX*wallDist;
  290.                 }
  291.                 //we use 16x16 tiles for textures.
  292.                 u = Floor( u*16 )&15;
  293.                
  294.                 //compute the wall height.
  295.                 wallDist = Abs(wallDist);
  296.                 float height = 256.0 / wallDist;
  297.                
  298.                 //compute the column dimensions.
  299.                 int y0 = Floor(cenY - height*0.5);
  300.                 int y1 = Floor(cenY + height*0.5);
  301.                
  302.                 if ( y0 < -96 ) y0 = -96;
  303.                 if ( y1 > 240 ) y1 = 240;
  304.                
  305.                 //shading depends on the "side" (so some faces are darker then others)
  306.                 //and the distance.
  307.                 int shading = Floor(wallDist/2) + side;
  308.                 if ( shading > 7 ) shading = 7;
  309.                 //textures are hard to author for this, but we compute the final tile we need for this column based on
  310.                 //the texture coordinate and shading.
  311.                 int tile = Game->ComboTile(hit) + u+(shading*20);
  312.  
  313.                 //Quad() doesn't work well here, but DrawTile() does since we're rendering a screen aligned quad.
  314.                 Screen->DrawTile(1, x, y0, tile, 1, 1, 0, 2, (y1-y0), 0, 0, 0, 0, false, 128);
  315.             }
  316.         }
  317.     }
  318. }
RAW Paste Data

Adblocker detected! Please consider disabling it...

We've detected AdBlock Plus or some other adblocking software preventing Pastebin.com from fully loading.

We don't have any obnoxious sound, or popup ads, we actively block these annoying types of ads!

Please add Pastebin.com to your ad blocker whitelist or disable your adblocking software.

×