Skip to content

Instantly share code, notes, and snippets.

@naranyala
Last active July 28, 2025 16:24
Show Gist options
  • Select an option

  • Save naranyala/7f4f5de5cca12e608a7db98d7b4916ef to your computer and use it in GitHub Desktop.

Select an option

Save naranyala/7f4f5de5cca12e608a7db98d7b4916ef to your computer and use it in GitHub Desktop.
2D car obstacles game using nim programming and raylib (imperative style)
import raylib as rl
import random
import math
# Game constants
const
ScreenWidth = 800
ScreenHeight = 600
PlayerWidth = 50
PlayerHeight = 80
ObstacleWidth = 50
ObstacleHeight = 50
MaxObstacles = 10
PlayerSpeed = 5
InitialObstacleSpeed = 3
type
Player = object
x, y: float
color: rl.Color
Obstacle = object
x, y: float
active: bool
color: rl.Color
speed: float
# Initialize window
rl.initWindow(ScreenWidth, ScreenHeight, "Car Escape Game")
rl.setTargetFPS(60)
# Initialize player
var player = Player(
x: ScreenWidth.float / 2 - PlayerWidth.float / 2,
y: ScreenHeight.float - PlayerHeight.float - 20,
color: rl.SKYBLUE
)
# Initialize obstacles
var obstacles: array[MaxObstacles, Obstacle]
for i in 0..<MaxObstacles:
obstacles[i] = Obstacle(
x: 0,
y: -ObstacleHeight.float,
active: false,
color: rl.RED,
speed: InitialObstacleSpeed
)
var score = 0
var gameOver = false
var obstacleSpeed: float64 = InitialObstacleSpeed
# Game loop
while not rl.windowShouldClose():
# Update
if not gameOver:
# Player movement
if rl.isKeyDown(rl.KeyboardKey.LEFT) and player.x > 0:
player.x -= PlayerSpeed
if rl.isKeyDown(rl.KeyboardKey.RIGHT) and player.x < ScreenWidth.float - PlayerWidth.float:
player.x += PlayerSpeed
# Spawn obstacles
for i in 0..<MaxObstacles:
if not obstacles[i].active:
if rand(100) < 2: # 2% chance to spawn each frame
obstacles[i].active = true
obstacles[i].x = rand(ScreenWidth - ObstacleWidth).float
obstacles[i].y = -ObstacleHeight.float
obstacles[i].speed = obstacleSpeed
break
# Update obstacles
for i in 0..<MaxObstacles:
if obstacles[i].active:
obstacles[i].y += obstacles[i].speed
# Check collision
if rl.checkCollisionRecs(
rl.Rectangle(x: player.x, y: player.y, width: PlayerWidth.float, height: PlayerHeight.float),
rl.Rectangle(x: obstacles[i].x, y: obstacles[i].y, width: ObstacleWidth.float, height: ObstacleHeight.float)
):
gameOver = true
# Check if obstacle passed bottom
if obstacles[i].y > ScreenHeight.float:
obstacles[i].active = false
score += 1
# Increase difficulty
if score mod 5 == 0:
obstacleSpeed += 0.5
else:
if rl.isKeyPressed(rl.KeyboardKey.SPACE):
# Reset game
gameOver = false
score = 0
obstacleSpeed = InitialObstacleSpeed
for i in 0..<MaxObstacles:
obstacles[i].active = false
# Draw
rl.beginDrawing()
rl.clearBackground(rl.RAYWHITE)
# Draw road
rl.drawRectangle(0, 0, ScreenWidth, ScreenHeight, rl.DARKGRAY)
# Draw road markings
for i in countup(0, ScreenHeight, 40):
rl.drawRectangle(
rl.Rectangle(
x: (ScreenWidth div 2 - 5).float,
y: i.float,
width: 10.0,
height: 20.0
),
rl.YELLOW
)
# Draw player
rl.drawRectangleRounded(
rl.Rectangle(x: player.x, y: player.y, width: PlayerWidth.float, height: PlayerHeight.float),
0.2, 5, player.color
)
# Draw obstacles
for i in 0..<MaxObstacles:
if obstacles[i].active:
rl.drawRectangleRounded(
rl.Rectangle(x: obstacles[i].x, y: obstacles[i].y, width: ObstacleWidth.float, height: ObstacleHeight.float),
0.2, 5, obstacles[i].color
)
# Draw score
rl.drawText("Score: " & $score, 10, 10, 20, rl.WHITE)
if gameOver:
rl.drawText("GAME OVER", ScreenWidth div 2 - rl.measureText("GAME OVER", 40) div 2, ScreenHeight div 2 - 50, 40, rl.RED)
rl.drawText("Press SPACE to restart", ScreenWidth div 2 - rl.measureText("Press SPACE to restart", 20) div 2, ScreenHeight div 2 + 20, 20, rl.WHITE)
rl.endDrawing()
# Cleanup
rl.closeWindow()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment