Results 1 to 5 of 5

Thread: I have a problem getting this raycasting example to work

  1. #1

    Thread Starter
    Junior Member
    Join Date
    Jun 2017
    Posts
    16

    Question I have a problem getting this raycasting example to work

    First of all, I am copying lodevs c++ tutorial on raycasting. I got it to work partway, but my inexperience got me stuck in several different points. I'm posting the code here. You will need a picturebox and a timer to get this to run. It is a windows forms application.

    If you run it and use the w-a-s-d keys, turn left and right a couple of key presses. You will notice that there is an anomaly and the room is not rendered the way it is in the map array. I don't know why.
    Another problem I have, is that I did not correctly copy the timing routine from lodevs example. I'm not sure how to set that up in visual basic. So I am using a timer for the steps. I am guessing that maybe because its exactly 100 milliseconds between ticks, that i get the the artifacts. How can I fix this. i understand that this is a big question and that it takes considerable knowledge to perhaps get this going, but maybe there is an expert here that knows 3D graphics. As for Visual Basic, I initially noticed that in raycasting, the example's performance is really good. So it is a possible project, that I would like to take further once I understand this.

    Since it's my first post, I think I shouldn't post a link. Just google "Lodev's raycasting" graphics tutorial and it should come up with the C++ example webpage so you can compare my effort.

    Thank you.

    Code:
    Public Class frmMain
        Dim w As Integer = 512
        Dim h As Integer = 384
    
    
        Const mapWidth As Integer = 23
        Const mapHeight As Integer = 23
    
    
        Dim worldMap(mapWidth, mapHeight) As Integer
    
    
        Dim posX As Double = 22
        Dim posY As Double = 12
        Dim dirX As Double = -1
        Dim dirY As Double = 0
        Dim planeX As Double = 0
        Dim planeY As Double = 0.66
    
    
        Dim backbuffer As New Bitmap(w, h)
        Dim g_backbuffer As Graphics = Graphics.FromImage(backbuffer)
    
    
        Private Sub frmMain_Load(ByVal sender As Object, ByVal e As EventArgs) Handles MyBase.Load
            Init()
    
    
            myTimer.Interval = 100
            myTimer.Start()
        End Sub
    
    
        Private Sub Init()
            worldMap = {{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
                        {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
                        {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
                        {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
                        {1, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
                        {1, 0, 0, 0, 0, 0, 0, 4, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
                        {1, 0, 0, 0, 0, 0, 0, 4, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
                        {1, 0, 0, 0, 0, 0, 0, 4, 0, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
                        {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
                        {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
                        {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
                        {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
                        {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
                        {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
                        {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
                        {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
                        {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
                        {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
                        {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
                        {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
                        {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
                        {1, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
                        {1, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
                        {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}}
        End Sub
    
    
        Dim s As New Stopwatch
    
    
        Private Sub GameLoop()
            g_backbuffer.Clear(Color.Black)
            For x As Integer = 0 To w - 1
                Dim cameraX As Double = 2 * x / w - 1
                Dim rayPosX As Double = posX
                Dim rayPosY As Double = posY
                Dim rayDirX As Double = dirX + planeX * cameraX
                Dim rayDirY As Double = dirY + planeY * cameraX
    
    
                Dim mapX As Integer = CInt(rayPosX)
                Dim mapY As Integer = CInt(rayPosY)
    
    
                Dim sideDistX As Double
                Dim sideDistY As Double
    
    
                Dim deltaDistX As Double = Math.Sqrt(1 + (rayDirY * rayDirY) / (rayDirX * rayDirX))
                Dim deltaDistY As Double = Math.Sqrt(1 + (rayDirX * rayDirX) / (rayDirY * rayDirY))
                Dim perpWallDist As Double
    
    
                Dim stepX As Integer
                Dim stepY As Integer
    
    
                Dim hit As Integer = 0
                Dim side As Integer
    
    
                If rayDirX < 0 Then
                    stepX = -1
                    sideDistX = (rayPosX - mapX) * deltaDistX
                Else
                    stepX = 1
                    sideDistX = (mapX + 1.0 - rayPosX) * deltaDistX
                End If
                If rayDirY < 0 Then
                    stepY = -1
                    sideDistX = (rayPosY - mapY) * deltaDistY
                Else
                    stepY = 1
                    sideDistY = (mapY + 1.0 - rayPosY) * deltaDistY
                End If
    
    
                While hit = 0
                    If sideDistX < sideDistY Then
                        sideDistX += deltaDistX
                        mapX += stepX
                        side = 0
                    Else
                        sideDistY += deltaDistY
                        mapY += stepY
                        side = 1
                    End If
                    If worldMap(mapX, mapY) > 0 Then
                        hit = 1
                    End If
                End While
                If side = 0 Then
                    perpWallDist = (mapX - rayPosX + (1 - stepX) / 2) / rayDirX
                Else
                    perpWallDist = (mapY - rayPosY + (1 - stepY) / 2) / rayDirY
                End If
    
    
                Dim lineHeight As Integer = CInt(h / perpWallDist)
    
    
                Dim drawStart As Double = -lineHeight / 2 + h / 2
                If drawStart < 0 Then
                    drawStart = 0
                End If
                Dim drawEnd As Double = lineHeight / 2 + h / 2
                If drawEnd >= h Then
                    drawEnd = h - 1
                End If
    
    
                Dim colr As Color
                Select Case worldMap(mapX, mapY)
                    Case 1
                        colr = Color.Red
                    Case 2
                        colr = Color.Green
                    Case 3
                        colr = Color.Blue
                    Case 4
                        colr = Color.White
                    Case Else
                        colr = Color.Yellow
                End Select
    
    
                If side = 1 Then
                    colr = Color.FromArgb(colr.R \ 2, colr.G \ 2, colr.B \ 2)
                End If
    
    
                g_backbuffer.DrawLine(New Pen(colr), x, CInt(drawStart), x, CInt(drawEnd))
            Next
        End Sub
    
    
        Dim moveSpeed As Double
        Dim rotSpeed As Double
    
    
        Private Sub pbView_Paint(sender As Object, e As PaintEventArgs) Handles pbView.Paint
            e.Graphics.InterpolationMode = Drawing2D.InterpolationMode.NearestNeighbor
            e.Graphics.PixelOffsetMode = Drawing2D.PixelOffsetMode.Half
            e.Graphics.DrawImage(backbuffer, 0, 0)
        End Sub
    
    
        Private Sub frmMain_KeyDown(sender As Object, e As KeyEventArgs) Handles Me.KeyDown
            Select Case e.KeyCode
                Case Keys.W
                    If worldMap(CInt(posX + dirX * moveSpeed), CInt(posY)) = 0 Then
                        posX += dirX * moveSpeed
                    End If
                    If worldMap(CInt(posX), CInt(posY + dirY * moveSpeed)) = 0 Then
                        posY += dirY * moveSpeed
                    End If
                    pbView.Invalidate()
                Case Keys.S
                    If worldMap(CInt(posX - dirX * moveSpeed), CInt(posY)) = 0 Then
                        posX -= dirX * moveSpeed
                    End If
                    If worldMap(CInt(posX), CInt(posY - dirY * moveSpeed)) = 0 Then
                        posY -= dirY * moveSpeed
                    End If
                Case Keys.D
                    Dim oldDirX As Double = dirX
                    dirX = dirX * Math.Cos(-rotSpeed) - dirY * Math.Sin(-rotSpeed)
                    dirY = oldDirX * Math.Sin(-rotSpeed) + dirY * Math.Cos(-rotSpeed)
                    Dim oldPlaneX As Double = planeX
                    planeX = planeX * Math.Cos(-rotSpeed) - planeY * Math.Sin(-rotSpeed)
                    planeY = oldPlaneX * Math.Sin(-rotSpeed) + planeY * Math.Cos(-rotSpeed)
                Case Keys.A
                    Dim oldDirX As Double = dirX
                    dirX = dirX * Math.Cos(rotSpeed) - dirY * Math.Sin(rotSpeed)
                    dirY = oldDirX * Math.Sin(rotSpeed) + dirY * Math.Cos(rotSpeed)
                    Dim oldPlaneX As Double = planeX
                    planeX = planeX * Math.Cos(rotSpeed) - planeY * Math.Sin(rotSpeed)
                    planeY = oldPlaneX * Math.Sin(rotSpeed) + planeY * Math.Cos(rotSpeed)
            End Select
        End Sub
    
    
        Private Sub myTimer_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles myTimer.Tick
            moveSpeed = 1.0
            rotSpeed = 1.0
            GameLoop()
            pbView.Invalidate
        End Sub
    End Class

  2. #2
    Sinecure devotee
    Join Date
    Aug 2013
    Location
    Southern Tier NY
    Posts
    6,582

    Re: I have a problem getting this raycasting example to work

    Well, there may be other problems, but one definite one is a copy and past error, I think.
    Code:
                If rayDirY < 0 Then
                    stepY = -1
                    sideDistX = (rayPosY - mapY) * deltaDistY
                Else
    You're dealing with Y here, but modifying sideDistX instead of sideDistY.
    That should clear up the major anomaly.

  3. #3

    Thread Starter
    Junior Member
    Join Date
    Jun 2017
    Posts
    16

    Re: I have a problem getting this raycasting example to work

    It's really great to get a second opinion. I verified the mistake and the lodev tutorial does not have the mistake either, so like you said it's probably my cut and paste error. I will test it first thing tomorrow. I really appreciate that, thank you.

  4. #4

    Thread Starter
    Junior Member
    Join Date
    Jun 2017
    Posts
    16

    Question Re: I have a problem getting this raycasting example to work

    I followed the recommendation and as it turns out, the problem disappeared. I have a few more issues that I am trying to solve, which I am still having a hard time with.

    What I did first of all is strip the program down completely so it does not depend on timing of any type. This time all you have to do is cut and paste the code and add a picturebox (be sure to name it). So you don't have to worry about setting up a timer or anything like that.

    The issue now is in the WASD keys. I would like to move 1 unit forward and 1 back and turn 90 degrees left and 90 degrees right. I followed the rules with sin and cos, but the turns are not accurate 90 degree turns. The steps forward and backward are in units of 1, so also I am not sure how that could correspond to each square on the map. I don't know how to measure it.

    After solving this, the only other thing that does not work is collision detection. In the original lodev program, there seems to be a boundary that is not passed. If I take steps instead of units, I think I step into the collision which crashes the program. Not sure if I understand that either, so here I am again asking for someone to look at this for me.

    btw - What I am trying to do is move around in 3D space like I would in a tile map.

    Code:
    Public Class frmMain
        Dim w As Integer = 512
        Dim h As Integer = 384
    
    
        Const mapWidth As Integer = 23
        Const mapHeight As Integer = 23
    
    
        Dim worldMap(mapWidth, mapHeight) As Integer
    
    
        Dim posX As Double = 22
        Dim posY As Double = 12
        Dim dirX As Double = -1
        Dim dirY As Double = 0
        Dim planeX As Double = 0
        Dim planeY As Double = 0.66
    
    
        Dim backbuffer As New Bitmap(w, h)
        Dim g_backbuffer As Graphics = Graphics.FromImage(backbuffer)
    
    
        Private Sub frmMain_Load(ByVal sender As Object, ByVal e As EventArgs) Handles MyBase.Load
            Init()
    
    
        End Sub
    
    
        Private Sub Init()
            worldMap = {{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
                        {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
                        {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
                        {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
                        {1, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
                        {1, 0, 0, 0, 0, 0, 0, 4, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
                        {1, 0, 0, 0, 0, 0, 0, 4, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
                        {1, 0, 0, 0, 0, 0, 0, 4, 0, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
                        {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
                        {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
                        {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
                        {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
                        {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
                        {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
                        {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
                        {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
                        {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
                        {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
                        {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
                        {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
                        {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
                        {1, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
                        {1, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
                        {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}}
        End Sub
    
    
        Private Sub GameLoop()
            g_backbuffer.Clear(Color.Black)
            For x As Integer = 0 To w - 1
                Dim cameraX As Double = 2 * x / w - 1
                Dim rayPosX As Double = posX
                Dim rayPosY As Double = posY
                Dim rayDirX As Double = dirX + planeX * cameraX
                Dim rayDirY As Double = dirY + planeY * cameraX
    
    
                Dim mapX As Integer = CInt(rayPosX)
                Dim mapY As Integer = CInt(rayPosY)
    
    
                Dim sideDistX As Double
                Dim sideDistY As Double
    
    
                Dim deltaDistX As Double = Math.Sqrt(1 + (rayDirY * rayDirY) / (rayDirX * rayDirX))
                Dim deltaDistY As Double = Math.Sqrt(1 + (rayDirX * rayDirX) / (rayDirY * rayDirY))
                Dim perpWallDist As Double
    
    
                Dim stepX As Integer
                Dim stepY As Integer
    
    
                Dim hit As Integer = 0
                Dim side As Integer
    
    
                If rayDirX < 0 Then
                    stepX = -1
                    sideDistX = (rayPosX - mapX) * deltaDistX
                Else
                    stepX = 1
                    sideDistX = (mapX + 1.0 - rayPosX) * deltaDistX
                End If
                If rayDirY < 0 Then
                    stepY = -1
                    sideDistY = (rayPosY - mapY) * deltaDistY
                Else
                    stepY = 1
                    sideDistY = (mapY + 1.0 - rayPosY) * deltaDistY
                End If
    
    
                While hit = 0
                    If sideDistX < sideDistY Then
                        sideDistX += deltaDistX
                        mapX += stepX
                        side = 0
                    Else
                        sideDistY += deltaDistY
                        mapY += stepY
                        side = 1
                    End If
                    If worldMap(mapX, mapY) > 0 Then
                        hit = 1
                    End If
                End While
                If side = 0 Then
                    perpWallDist = (mapX - rayPosX + (1 - stepX) / 2) / rayDirX
                Else
                    perpWallDist = (mapY - rayPosY + (1 - stepY) / 2) / rayDirY
                End If
    
    
                Dim lineHeight As Integer = CInt(h / perpWallDist)
    
    
                Dim drawStart As Double = -lineHeight / 2 + h / 2
                If drawStart < 0 Then
                    drawStart = 0
                End If
                Dim drawEnd As Double = lineHeight / 2 + h / 2
                If drawEnd >= h Then
                    drawEnd = h - 1
                End If
    
    
                Dim colr As Color
                Select Case worldMap(mapX, mapY)
                    Case 1
                        colr = Color.Red
                    Case 2
                        colr = Color.Green
                    Case 3
                        colr = Color.Blue
                    Case 4
                        colr = Color.White
                    Case Else
                        colr = Color.Yellow
                End Select
    
    
                If side = 1 Then
                    colr = Color.FromArgb(colr.R \ 2, colr.G \ 2, colr.B \ 2)
                End If
    
    
                g_backbuffer.DrawLine(New Pen(colr), x, CInt(drawStart), x, CInt(drawEnd))
            Next
            pbView.Invalidate()
        End Sub
    
    
        Dim moveSpeed As Double = 1.0F
        Dim rotSpeed As Double = 1.0F
    
    
        Private Sub pbView_Paint(sender As Object, e As PaintEventArgs) Handles pbView.Paint
            e.Graphics.InterpolationMode = Drawing2D.InterpolationMode.NearestNeighbor
            e.Graphics.PixelOffsetMode = Drawing2D.PixelOffsetMode.Half
    
    
            GameLoop()
    
    
            e.Graphics.DrawImage(backbuffer, 0, 0)
        End Sub
    
    
        Private Sub frmMain_KeyDown(sender As Object, e As KeyEventArgs) Handles Me.KeyDown
            Select Case e.KeyCode
                Case Keys.W
                    If worldMap(CInt(posX + dirX * moveSpeed), CInt(posY)) = 0 Then
                        posX += dirX * moveSpeed
                    End If
                    If worldMap(CInt(posX), CInt(posY + dirY * moveSpeed)) = 0 Then
                        posY += dirY * moveSpeed
                    End If
                    pbView.Invalidate()
                Case Keys.S
                    If worldMap(CInt(posX - dirX * moveSpeed), CInt(posY)) = 0 Then
                        posX -= dirX * moveSpeed
                    End If
                    If worldMap(CInt(posX), CInt(posY - dirY * moveSpeed)) = 0 Then
                        posY -= dirY * moveSpeed
                    End If
                Case Keys.D
                    Dim oldDirX As Double = dirX
                    dirX = dirX * Math.Cos(-90) - dirY * Math.Sin(-90)
                    dirY = oldDirX * Math.Sin(-90) + dirY * Math.Sin(-90)
                    Dim oldPlaneX As Double = planeX
                    planeX = planeX * Math.Cos(-90) - planeY * Math.Sin(-90)
                    planeY = oldPlaneX * Math.Sin(-90) + planeY * Math.Cos(-90)
                Case Keys.A
                    ' opposite direction
            End Select
        End Sub
    End Class

  5. #5

    Thread Starter
    Junior Member
    Join Date
    Jun 2017
    Posts
    16

    Question Re: I have a problem getting this raycasting example to work

    OK, somewhat of a success. I don't want to clutter this thread, so let me be clear about what is going on. There is only one more thing I need assistance with for now. Hopefully someone can help.

    I finally have a working example, that steps approximately. The only problem, if you notice is that each step the player takes is not exactly 1 unit square. All this code with degrees and radians is a bit confusing to me. Everything works, and collision is approximately ok. I know the collision is bad because the steps are incorrect now.

    What I would like to know, is how can I finally normalize the steps. So one keypress = 1 unit square step for the player. Every time I rotate, the radians that are the result for dirX and dirY multiply a different extent for the pos of the player. How can I normalize it to 1?

    Here is the code:
    Code:
    Public Class frmMain
        Dim w As Integer = 512
        Dim h As Integer = 384
    
    
        Const mapWidth As Integer = 23
        Const mapHeight As Integer = 23
    
    
        Dim worldMap(mapWidth, mapHeight) As Integer
    
    
        Dim posX As Double = 7
        Dim posY As Double = 12
        Dim dirX As Double = -1
        Dim dirY As Double = 0
        Dim planeX As Double = 0
        Dim planeY As Double = 0.66
    
    
        Dim backbuffer As New Bitmap(w, h)
        Dim g_backbuffer As Graphics = Graphics.FromImage(backbuffer)
    
    
        Dim bRunning As Boolean = True
    
    
        Private Sub frmMain_FormClosing(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
            bRunning = False
        End Sub
    
    
        Private Sub frmMain_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            Init()
    
    
            Me.Show()
    
    
            Do While bRunning
                Application.DoEvents()
                GameLoop
            Loop
        End Sub
    
    
        Private Sub Init()
            worldMap = {{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
                        {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
                        {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
                        {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
                        {1, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
                        {1, 0, 0, 0, 0, 0, 0, 4, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
                        {1, 0, 0, 0, 0, 0, 0, 4, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
                        {1, 0, 0, 0, 0, 0, 0, 4, 0, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
                        {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
                        {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
                        {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
                        {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
                        {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
                        {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
                        {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
                        {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
                        {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
                        {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
                        {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
                        {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
                        {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
                        {1, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
                        {1, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
                        {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}}
        End Sub
    
    
        Private Sub GameLoop()
            g_backbuffer.Clear(Color.Black)
            For x As Integer = 0 To w - 1
                Dim cameraX As Double = 2 * x / w - 1
                Dim rayPosX As Double = posX
                Dim rayPosY As Double = posY
                Dim rayDirX As Double = dirX + planeX * cameraX
                Dim rayDirY As Double = dirY + planeY * cameraX
    
    
                Dim mapX As Integer = CInt(rayPosX)
                Dim mapY As Integer = CInt(rayPosY)
    
    
                Dim sideDistX As Double
                Dim sideDistY As Double
    
    
                Dim deltaDistX As Double = Math.Sqrt(1 + (rayDirY * rayDirY) / (rayDirX * rayDirX))
                Dim deltaDistY As Double = Math.Sqrt(1 + (rayDirX * rayDirX) / (rayDirY * rayDirY))
                Dim perpWallDist As Double
    
    
                Dim stepX As Integer
                Dim stepY As Integer
    
    
                Dim hit As Integer = 0
                Dim side As Integer
    
    
                If rayDirX < 0 Then
                    stepX = -1
                    sideDistX = (rayPosX - mapX) * deltaDistX
                Else
                    stepX = 1
                    sideDistX = (mapX + 1.0 - rayPosX) * deltaDistX
                End If
                If rayDirY < 0 Then
                    stepY = -1
                    sideDistY = (rayPosY - mapY) * deltaDistY
                Else
                    stepY = 1
                    sideDistY = (mapY + 1.0 - rayPosY) * deltaDistY
                End If
    
    
                While hit = 0
                    If sideDistX < sideDistY Then
                        sideDistX += deltaDistX
                        mapX += stepX
                        side = 0
                    Else
                        sideDistY += deltaDistY
                        mapY += stepY
                        side = 1
                    End If
                    If worldMap(mapX, mapY) > 0 Then
                        hit = 1
                    End If
                End While
                If side = 0 Then
                    perpWallDist = (mapX - rayPosX + (1 - stepX) / 2) / rayDirX
                Else
                    perpWallDist = (mapY - rayPosY + (1 - stepY) / 2) / rayDirY
                End If
    
    
                Dim lineHeight As Integer = CInt(h / perpWallDist)
    
    
                Dim drawStart As Double = -lineHeight / 2 + h / 2
                If drawStart < 0 Then
                    drawStart = 0
                End If
                Dim drawEnd As Double = lineHeight / 2 + h / 2
                If drawEnd >= h Then
                    drawEnd = h - 1
                End If
    
    
                Dim colr As Color
                Select Case worldMap(mapX, mapY)
                    Case 1
                        colr = Color.Red
                    Case 2
                        colr = Color.Green
                    Case 3
                        colr = Color.Blue
                    Case 4
                        colr = Color.White
                    Case Else
                        colr = Color.Yellow
                End Select
    
    
                If side = 1 Then
                    colr = Color.FromArgb(colr.R \ 2, colr.G \ 2, colr.B \ 2)
                End If
    
    
                g_backbuffer.DrawLine(New Pen(colr), x, CInt(drawStart), x, CInt(drawEnd))
            Next
            pbView.Invalidate()
    
    
        End Sub
    
    
        Private Sub pbView_Paint(ByVal sender As Object, ByVal e As PaintEventArgs) Handles pbView.Paint
            e.Graphics.InterpolationMode = Drawing2D.InterpolationMode.NearestNeighbor
            e.Graphics.PixelOffsetMode = Drawing2D.PixelOffsetMode.Half
            e.Graphics.DrawImage(backbuffer, 0, 0)
        End Sub
    
    
        Private Sub frmMain_KeyDown(ByVal sender As Object, ByVal e As KeyEventArgs) Handles Me.KeyDown
            Select Case e.KeyCode
                Case Keys.W
                    If worldMap(CInt(posX + dirX), CInt(posY)) = 0 Then
                        posX += dirX
                    End If
                    If worldMap(CInt(posX), CInt(posY + dirY)) = 0 Then
                        posY += dirY
                    End If
                Case Keys.S
                    If worldMap(CInt(posX - dirX), CInt(posY)) = 0 Then
                        posX -= dirX
                    End If
                    If worldMap(CInt(posX), CInt(posY - dirY)) = 0 Then
                        posY -= dirY
                    End If
                Case Keys.D
                    'Dim oldDirX As Double = dirX
                    'dirX = dirX * Math.Cos(-rotSpeed) - dirY * Math.Sin(-rotSpeed)
                    'dirY = oldDirX * Math.Sin(-rotSpeed) + dirY * Math.Cos(-rotSpeed)
                    'Dim oldPlaneX As Double = planeX
                    'planeX = planeX * Math.Cos(-rotSpeed) - planeY * Math.Sin(-rotSpeed)
                    'planeY = oldPlaneX * Math.Sin(-rotSpeed) + planeY * Math.Cos(-rotSpeed)
                    Dim oldDirX As Double = dirX
                    dirX = dirX * Math.Cos(-1.5708) - dirY * Math.Sin(-1.5708)
                    dirY = oldDirX * Math.Sin(-1.5708) + dirY * Math.Cos(-1.5708)
                    Dim oldPlaneX As Double = planeX
                    planeX = planeX * Math.Cos(-1.5708) - planeY * Math.Sin(-1.5708)
                    planeY = oldPlaneX * Math.Sin(-1.5708) + planeY * Math.Cos(-1.5708)
                Case Keys.A
                    'Dim oldDirX As Double = dirX
                    'dirX = dirX * Math.Cos(rotSpeed) - dirY * Math.Sin(rotSpeed)
                    'dirY = oldDirX * Math.Sin(rotSpeed) + dirY * Math.Cos(rotSpeed)
                    'Dim oldPlaneX As Double = planeX
                    'planeX = planeX * Math.Cos(rotSpeed) - planeY * Math.Sin(rotSpeed)
                    'planeY = oldPlaneX * Math.Sin(rotSpeed) + planeY * Math.Cos(rotSpeed)
                    Dim oldDirX As Double = dirX
                    dirX = dirX * Math.Cos(1.5708) - dirY * Math.Sin(1.5708)
                    dirY = oldDirX * Math.Sin(1.5708) + dirY * Math.Cos(1.5708)
                    Dim oldPlaneX As Double = planeX
                    planeX = planeX * Math.Cos(1.5708) - planeY * Math.Sin(1.5708)
                    planeY = oldPlaneX * Math.Sin(1.5708) + planeY * Math.Cos(1.5708)
            End Select
            Me.Text = dirX.ToString & ":" & dirY.ToString
        End Sub
    
    
    End Class

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width