I am pretty sure Nim's sin() and cos() work exact same way as the C++ ones. I
never had an issue with them working differently. I think error is some place
else.
Some thing I noticed:
* you use uint32 for time while C++ uses double.
* you hard code w to 640 while C++ does not.
* your right and left key is flipped from the C++ code.
* C++ article warns about the problem you hare having.
* you are doing one extra line should be 0 ..< 640 not 0..640
running your code i get: (61, 29) Error: type mismatch: got <array[0..3, int]>
but expected 'array[0..3, int32]'
I switched to using .byte for color values. I switched to using w and h like
C++ code.
I can't find the issue in you code, ... but I did my own C++ to nim conversion
and it works without issues:
import sdl2
import math
var 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,2,2,2,2,2,0,0,0,0,3,0,3,0,3,0,0,0,1],
[1,0,0,0,0,0,2,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,1],
[1,0,0,0,0,0,2,0,0,0,2,0,0,0,0,3,0,0,0,3,0,0,0,1],
[1,0,0,0,0,0,2,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,1],
[1,0,0,0,0,0,2,2,0,2,2,0,0,0,0,3,0,3,0,3,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,4,4,4,4,4,4,4,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
[1,4,0,4,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
[1,4,0,0,0,0,5,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
[1,4,0,4,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
[1,4,0,4,4,4,4,4,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
[1,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
[1,4,4,4,4,4,4,4,4,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]
]
proc main() =
var
posX: float = 22 # x and y start position
posY: float = 12
dirX: float = -1 # initial direction vector
dirY: float = 0
planeX: float = 0 # the 2d raycaster version of camera plane
planeY: float = 0.66
time: float = 0 # time of current frame
oldTime: float = 0 # time of previous frame
w = 680
h = 420
window = createWindow("NIM RayCasting", 100,100,cint w,cint h,
SDL_WINDOW_SHOWN or SDL_WINDOW_OPENGL)
render = createRenderer(window, -1, Renderer_Accelerated or
Renderer_PresentVsync)
evt = sdl2.defaultEvent
runGame = true
while(runGame):
render.setDrawColor(0,0,0,255)
render.clear()
for x in 0 ..< w:
# calculate ray position and direction
var
cameraX = 2 * float(x) / float(w) - 1 # x-coordinate in camera space
rayDirX = dirX + planeX * cameraX
rayDirY = dirY + planeY * cameraX
# which box of the map we're in
mapX: int = int(floor(posX))
mapY: int = int(floor(posY))
# length of ray from current position to next x or y-side
sideDistX: float
sideDistY: float
# length of ray from one x or y-side to next x or y-side
deltaDistX = abs(1 / rayDirX)
deltaDistY = abs(1 / rayDirY)
perpWallDist: float
# what direction to step in x or y-direction (either +1 or -1)
stepX: int
stepY: int
hit = 0 # was there a wall hit?
side: int # was a NS or a EW wall hit?
# calculate step and initial sideDist
if rayDirX < 0:
stepX = -1
sideDistX = (posX - float(mapX)) * deltaDistX
else:
stepX = 1
sideDistX = (float(mapX) + 1.0 - posX) * deltaDistX
if rayDirY < 0:
stepY = -1
sideDistY = (posY - float(mapY)) * deltaDistY
else:
stepY = 1
sideDistY = (float(mapY) + 1.0 - posY) * deltaDistY
# perform DDA
while hit == 0:
# jump to next map square, OR in x-direction, OR in y-direction
if sideDistX < sideDistY:
sideDistX += deltaDistX
mapX += stepX
side = 0
else:
sideDistY += deltaDistY
mapY += stepY
side = 1
# Check if ray has hit a wall
if worldMap[mapX][mapY] > 0:
hit = 1
# Calculate distance projected on camera direction (Euclidean
distance will give fisheye effect!)
if side == 0:
perpWallDist = (float(mapX) - posX + (1 - stepX) / 2) / rayDirX
else:
perpWallDist = (float(mapY) - posY + (1 - stepY) / 2) / rayDirY
# Calculate height of line to draw on screen
var lineHeight = (int)(float(h) / perpWallDist)
# calculate lowest and highest pixel to fill in current stripe
var drawStart = -lineHeight div 2 + h div 2
if drawStart < 0:
drawStart = 0
var drawEnd = lineHeight div 2 + h div 2
if drawEnd >= h:
drawEnd = h - 1
# choose wall color
var color: array[4, byte]
case(worldMap[mapX][mapY]):
of 1: color = [245.byte,66,66,255] # Rojo
of 2: color = [66.byte,255,95,255] # Verde
of 3: color = [66.byte,81,245,255] # Azul
of 4: color = [255.byte,255,255,255] # Blanco
else: color = [255.byte,255,255,255] # Naranja
# give x and y sides different brightness
if side == 1:
for i in 0..2:
color[i] = color[i] div 2
# draw the pixels of the stripe as a vertical line
render.setDrawColor(color[0], color[1], color[2], color[3])
render.drawLine(cint(x),cint(drawStart),cint(x),cint(drawEnd))
# timing for input and FPS counter
oldTime = time
time = float getTicks()
var frameTime = (time - oldTime) / 1000.0 # frameTime is the time this
frame has taken, in seconds
render.present()
# speed modifiers
var moveSpeed = frameTime * 5.0 # the constant value is in
squares/second
var rotSpeed = frameTime * 3.0 # the constant value is in radians/second
while pollEvent(evt):
if evt.kind == QuitEvent:
runGame = false
break
var state = getKeyboardState()
# move forward if no wall in front of you
if state[int SDL_SCANCODE_W] != 0:
if worldMap[int(posX + dirX * moveSpeed)][int(posY)] == 0:
posX += dirX * moveSpeed
if worldMap[int(posX)][int(posY + dirY * moveSpeed)] == 0:
posY += dirY * moveSpeed
# move backwards if no wall behind you
if state[int SDL_SCANCODE_S] != 0:
if worldMap[int(posX - dirX * moveSpeed)][int(posY)] == 0:
posX -= dirX * moveSpeed
if worldMap[int(posX)][int(posY - dirY * moveSpeed)] == 0:
posY -= dirY * moveSpeed
# rotate to the right
if state[int SDL_SCANCODE_D] != 0:
# both camera direction and camera plane must be rotated
var oldDirX = dirX
dirX = dirX * cos(-rotSpeed) - dirY * sin(-rotSpeed)
dirY = oldDirX * sin(-rotSpeed) + dirY * cos(-rotSpeed)
var oldPlaneX = planeX
planeX = planeX * cos(-rotSpeed) - planeY * sin(-rotSpeed)
planeY = oldPlaneX * sin(-rotSpeed) + planeY * cos(-rotSpeed)
# rotate to the left
if state[int SDL_SCANCODE_A] != 0:
# both camera direction and camera plane must be rotated
var oldDirX = dirX
dirX = dirX * cos(rotSpeed) - dirY * sin(rotSpeed)
dirY = oldDirX * sin(rotSpeed) + dirY * cos(rotSpeed)
var oldPlaneX = planeX
planeX = planeX * cos(rotSpeed) - planeY * sin(rotSpeed)
planeY = oldPlaneX * sin(rotSpeed) + planeY * cos(rotSpeed)
main()
Run