Last active
July 28, 2025 16:24
-
-
Save naranyala/7f4f5de5cca12e608a7db98d7b4916ef to your computer and use it in GitHub Desktop.
2D car obstacles game using nim programming and raylib (imperative style)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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