Advertisement
BlakPilar

C# Raycaster (Port)

Mar 22nd, 2012
112
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 13.64 KB | None | 0 0
  1. using System;
  2. using System.Drawing;
  3. using System.Windows.Forms;
  4.  
  5. namespace Raycast {
  6.     public class Raycaster : Form {
  7.         #region Map info
  8.         private const int MAPWIDTH  = 24;
  9.         private const int MAPHEIGHT = 24;
  10.         private int[,] worldMap = new int[MAPHEIGHT, MAPWIDTH] {
  11.             {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
  12.             {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
  13.             {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
  14.             {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
  15.             {1, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 0, 0, 0, 0, 3, 0, 3, 0, 3, 0, 0, 0, 1},
  16.             {1, 0, 0, 0, 0, 0, 2, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
  17.             {1, 0, 0, 0, 0, 0, 2, 0, 1, 0, 2, 0, 0, 0, 0, 3, 0, 4, 0, 3, 0, 0, 0, 1},
  18.             {1, 0, 0, 0, 0, 0, 2, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
  19.             {1, 0, 0, 0, 0, 0, 2, 2, 0, 2, 2, 0, 0, 0, 0, 3, 0, 3, 0, 3, 0, 0, 0, 1},
  20.             {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
  21.             {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
  22.             {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
  23.             {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
  24.             {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
  25.             {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
  26.             {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
  27.             {1, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
  28.             {1, 4, 0, 4, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
  29.             {1, 4, 0, 0, 0, 0, 5, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
  30.             {1, 4, 0, 4, 0, 0, 0, 0, 4, 0, 0, 0, 0, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 1},
  31.             {1, 4, 0, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 2, 0, 0, 0, 0, 3, 0, 0, 0, 0, 1},
  32.             {1, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 2, 3, 0, 0, 0, 2, 3, 0, 1},
  33.             {1, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 3, 0, 0, 0, 0, 2, 0, 0, 0, 0, 1},
  34.             {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
  35.         };
  36.         #endregion
  37.  
  38.         #region Vars
  39.         const double rotateMultiplier = 2, moveMultiplier = 2.5;
  40.         double posX = 22, posY = 12;
  41.         double dirX = -1, dirY = 0;
  42.         double planeX = 0, planeY = 0.66;
  43.         UInt32 time = 0, oldTime = 0;
  44.         UInt32 startTick = (UInt32)Environment.TickCount;
  45.         double rotSpeed = 0, moveSpeed = 0;
  46.         bool goingLeft = false, goingRight = false, goingForward = false, goingBackward = false;
  47.         #endregion Vars
  48.  
  49.         public Raycaster() {
  50.             #region Setup form
  51.             Width = 606;        // Gives ClientRectangle width of 600
  52.             Height = 428;       // Gives ClientRectangle height of 400
  53.             Text = "Raycaster";
  54.             MaximizeBox = false;
  55.             FormBorderStyle = FormBorderStyle.FixedSingle;
  56.             StartPosition = FormStartPosition.CenterScreen;
  57.             #endregion Setup form
  58.  
  59.             SetStyle(ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint |
  60.                 ControlStyles.OptimizedDoubleBuffer, true);
  61.         }
  62.  
  63.         #region Overridden methods
  64.         protected override void OnPaint(PaintEventArgs e) {
  65.             double FPS = 0d;
  66.             Bitmap buffer = new Bitmap(ClientRectangle.Width, ClientRectangle.Height);
  67.             using (Graphics gfx = Graphics.FromImage(buffer)) {
  68.                 gfx.Clear(Color.White);
  69.                 double width = buffer.Width;
  70.                 double height = buffer.Height;
  71.  
  72.                 // Check each column of the screen
  73.                 for (int x = 0; x < width; x++) {
  74.  
  75.                     // Calculate ray position and direction
  76.                     double cameraX = 2 * x / width - 1; // X-coordinate in camera space
  77.                     double rayPosX = posX;
  78.                     double rayPosY = posY;
  79.                     double rayDirX = dirX + planeX * cameraX;
  80.                     double rayDirY = dirY + planeY * cameraX;
  81.                     // Get the actual map location
  82.                     int mapX = (int)rayPosX;
  83.                     int mapY = (int)rayPosY;
  84.  
  85.                     // Length of ray from current position to next X- or Y-side
  86.                     double sideDistX;
  87.                     double sideDistY;
  88.  
  89.                     // Length of ray from one X- or Y-side to next X- or Y-side
  90.                     double deltaDistX = Math.Sqrt(1 + (rayDirY * rayDirY) / (rayDirX * rayDirX));
  91.                     double deltaDistY = Math.Sqrt(1 + (rayDirX * rayDirX) / (rayDirY * rayDirY));
  92.                     double perpWallDist;
  93.  
  94.                     // What direction to step in X or Y (+1 / -1)
  95.                     int stepX;
  96.                     int stepY;
  97.  
  98.                     int hit = 0;                        // Was there a wall hit?
  99.                     int side = 0;                       // Was the hit NS or EW?
  100.  
  101.                     // Calculate step and initial side distance
  102.                     if (rayDirX < 0) {
  103.                         stepX = -1;
  104.                         sideDistX = (rayPosX - mapX) * deltaDistX;
  105.                     } else {
  106.                         stepX = 1;
  107.                         sideDistX = (mapX + 1.0d - rayPosX) * deltaDistX;
  108.                     }
  109.                     if (rayDirY < 0) {
  110.                         stepY = -1;
  111.                         sideDistY = (rayPosY - mapY) * deltaDistY;
  112.                     } else {
  113.                         stepY = 1;
  114.                         sideDistY = (mapY + 1.0d - rayPosY) * deltaDistY;
  115.                     }
  116.  
  117.                     // Perform DDA
  118.                     while (hit == 0) {
  119.                         // Jump to next map square, OR in X-direction, OR in Y-direction
  120.                         if (sideDistX < sideDistY) {
  121.                             sideDistX += deltaDistX;
  122.                             mapX += stepX;
  123.                             side = 0;
  124.                         }
  125.                         else {
  126.                             sideDistY += deltaDistY;
  127.                             mapY += stepY;
  128.                             side = 1;
  129.                         }
  130.                         // Check if ray has hit a wall
  131.                         if (worldMap[mapY, mapX] > 0) hit = 1;
  132.                     }
  133.  
  134.                     // Calculate distance projected on camera direction
  135.                     // (oblique distance will give fisheye effect)
  136.                     if (side == 0)
  137.                         perpWallDist = Math.Abs((mapX - rayPosX + (1 - stepX) / 2) / rayDirX);
  138.                     else
  139.                         perpWallDist = Math.Abs((mapY - rayPosY + (1 - stepY) / 2) / rayDirY);
  140.  
  141.                     // Calculate height of line to draw on screen
  142.                     int lineHeight = Math.Abs((int)(height / perpWallDist));
  143.  
  144.                     // Calculate lowest and highest pixel to fill in current strip
  145.                     int drawStart = (int)(-lineHeight / 2 + height / 2);
  146.                     if (drawStart < 0) drawStart = 0;
  147.                     int drawEnd = (int)(lineHeight / 2 + height / 2);
  148.                     if (drawEnd >= height) drawEnd = (int)height - 1;
  149.  
  150.                     // Choose wall color
  151.                     #region Wall color
  152.                     Pen color;
  153.                     switch (worldMap[mapY, mapX]) {
  154.                         case 1:
  155.                             if (side == 1)
  156.                                 color = Pens.DarkRed;
  157.                             else
  158.                                 color = Pens.Red;
  159.                             break;
  160.                         case 2:
  161.                             if (side == 1)
  162.                                 color = Pens.DarkGreen;
  163.                             else
  164.                                 color = Pens.Green;
  165.                             break;
  166.                         case 3:
  167.                             if (side == 1)
  168.                                 color = Pens.DarkBlue;
  169.                             else
  170.                                 color = Pens.Blue;
  171.                             break;
  172.                         case 4:
  173.                             if (side == 1)
  174.                                 color = Pens.DarkGray;
  175.                             else
  176.                                 color = Pens.Gray;
  177.                             break;
  178.                         default:
  179.                             color = Pens.LightGray;
  180.                             break;
  181.                     }
  182.                     #endregion Wall color
  183.  
  184.                     // Draw the strip
  185.                     gfx.DrawLine(color, x, drawStart, x, drawEnd);
  186.                 }
  187.  
  188.                 // Get timing for input and FPS
  189.                 oldTime = time;
  190.                 time = (UInt32)Environment.TickCount - startTick;
  191.                 double frameTime = (time - oldTime) / 1000.0d;
  192.                 FPS = 1.0d / frameTime;
  193.  
  194.                 // Speed modifiers
  195.                 moveSpeed = frameTime * moveMultiplier;
  196.                 rotSpeed = frameTime * rotateMultiplier;
  197.             }
  198.  
  199.             e.Graphics.DrawImageUnscaled(buffer, new Point(0, 0));
  200.             e.Graphics.DrawString(((int)FPS).ToString() + " FPS",
  201.                 new Font("Consolas", 10f), Brushes.Black, new PointF(0, 0));
  202.             e.Graphics.DrawString("Move Speed: " + moveSpeed,
  203.                 new Font("Consolas", 10f), Brushes.Black, new PointF(0, 12));
  204.             e.Graphics.DrawString("Rotate Speed: " + rotSpeed,
  205.                 new Font("Consolas", 10f), Brushes.Black, new PointF(0, 24));
  206.  
  207.             MovePlayer();
  208.             Invalidate();
  209.             System.Threading.Thread.Sleep(10);
  210.         }
  211.  
  212.         protected override void OnPaintBackground(PaintEventArgs e) { }
  213.  
  214.         protected override void OnKeyDown(KeyEventArgs e) {
  215.             switch (e.KeyData) {
  216.  
  217.                 case Keys.A:
  218.                 case Keys.Left:
  219.                     goingLeft = true;
  220.                     break;
  221.  
  222.                 case Keys.D:
  223.                 case Keys.Right:
  224.                     goingRight = true;
  225.                     break;
  226.  
  227.                 case Keys.W:
  228.                 case Keys.Up:
  229.                     goingForward = true;
  230.                     break;
  231.  
  232.                 case Keys.S:
  233.                 case Keys.Down:
  234.                     goingBackward = true;
  235.                     break;
  236.  
  237.                 case Keys.Escape:
  238.                     Application.Exit();
  239.                     break;
  240.  
  241.             }
  242.  
  243.             base.OnKeyDown(e);
  244.         }
  245.  
  246.         protected override void OnKeyUp(KeyEventArgs e) {
  247.             switch (e.KeyData) {
  248.  
  249.                 case Keys.A:
  250.                 case Keys.Left:
  251.                     goingLeft = false;
  252.                     break;
  253.  
  254.                 case Keys.D:
  255.                 case Keys.Right:
  256.                     goingRight = false;
  257.                     break;
  258.  
  259.                 case Keys.W:
  260.                 case Keys.Up:
  261.                     goingForward = false;
  262.                     break;
  263.  
  264.                 case Keys.S:
  265.                 case Keys.Down:
  266.                     goingBackward = false;
  267.                     break;
  268.             }
  269.  
  270.             base.OnKeyUp(e);
  271.         }
  272.         #endregion Overridden methods
  273.  
  274.         protected void MovePlayer() {
  275.             if (goingLeft && !goingRight) {
  276.                 double oldDirX = dirX;
  277.                 dirX = dirX * Math.Cos(rotSpeed) - dirY * Math.Sin(rotSpeed);
  278.                 dirY = oldDirX * Math.Sin(rotSpeed) + dirY * Math.Cos(rotSpeed);
  279.                 double oldPlaneX = planeX;
  280.                 planeX = planeX * Math.Cos(rotSpeed) - planeY * Math.Sin(rotSpeed);
  281.                 planeY = oldPlaneX * Math.Sin(rotSpeed) + planeY * Math.Cos(rotSpeed);
  282.             } else if (goingRight && !goingLeft) {
  283.                 double oldDirX = dirX;
  284.                 dirX = dirX * Math.Cos(-rotSpeed) - dirY * Math.Sin(-rotSpeed);
  285.                 dirY = oldDirX * Math.Sin(-rotSpeed) + dirY * Math.Cos(-rotSpeed);
  286.                 double oldPlaneX = planeX;
  287.                 planeX = planeX * Math.Cos(-rotSpeed) - planeY * Math.Sin(-rotSpeed);
  288.                 planeY = oldPlaneX * Math.Sin(-rotSpeed) + planeY * Math.Cos(-rotSpeed);
  289.             }
  290.  
  291.             if (goingForward && !goingBackward) {
  292.                 int newMapX = (int)(posX + dirX * moveSpeed);
  293.                 int newMapY = (int)(posY + dirY * moveSpeed);
  294.  
  295.                 if (worldMap[(int)posY, newMapX] == 0)
  296.                     posX += dirX * moveSpeed;
  297.                 if (worldMap[newMapY, (int)posX] == 0)
  298.                     posY += dirY * moveSpeed;
  299.             } else if (goingBackward && !goingForward) {
  300.                 int newMapX = (int)(posX - dirX * moveSpeed);
  301.                 int newMapY = (int)(posY - dirY * moveSpeed);
  302.  
  303.                 if (worldMap[(int)posY, newMapX] == 0)
  304.                     posX -= dirX * moveSpeed;
  305.                 if (worldMap[newMapY, (int)posX] == 0)
  306.                     posY -= dirY * moveSpeed;
  307.             }
  308.         }
  309.  
  310.         /// <summary>
  311.         /// The main entry point for the application.
  312.         /// </summary>
  313.         [STAThread]
  314.         static void Main() {
  315.             Application.EnableVisualStyles();
  316.             Application.SetCompatibleTextRenderingDefault(true);
  317.             using (Raycaster rayc = new Raycaster())
  318.                 Application.Run(rayc);
  319.         }
  320.     }
  321. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement