Advertisement
ZoriaRPG

BK Raycaster

Sep 9th, 2017
234
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 11.29 KB | None | 0 0
  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.         }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement