Skip to content

Instantly share code, notes, and snippets.

@naranyala
Created June 22, 2025 01:54
Show Gist options
  • Save naranyala/f5559b63e232423ccd6ccfe7ad40dcc8 to your computer and use it in GitHub Desktop.
Save naranyala/f5559b63e232423ccd6ccfe7ad40dcc8 to your computer and use it in GitHub Desktop.
endless jump game (vertical) made it with odin+raylib
package main
import "core:math"
import "core:fmt"
import rl "vendor:raylib"
Platform :: struct {
pos: rl.Vector2,
size: rl.Vector2,
}
main :: proc() {
rl.InitWindow(800, 600, "Endless Vertical Jump Game")
defer rl.CloseWindow()
rl.SetTargetFPS(60)
player_pos := rl.Vector2{400, 500}
player_vel := rl.Vector2{0, 0}
player_size := rl.Vector2{20, 20}
gravity: f32 = 1200
move_speed: f32 = 2800 // Fast horizontal movement
jump_speed: f32 = 700 // High jump
is_grounded := false
score: i32 = 0
camera_offset: f32 = 0
game_over := false
highest_y: f32 = 500 // Track highest point reached
// Platform generation
platforms := make([dynamic]Platform)
defer delete(platforms)
// Initial platforms - vertical progression
append(&platforms, Platform{{350, 500}, {200, 20}}) // Starting platform
append(&platforms, Platform{{200, 400}, {150, 20}}) // Left side
append(&platforms, Platform{{450, 320}, {150, 20}}) // Right side
append(&platforms, Platform{{100, 240}, {150, 20}}) // Left side
append(&platforms, Platform{{550, 160}, {150, 20}}) // Right side
append(&platforms, Platform{{300, 80}, {200, 20}}) // Center top
platform_spawn_y: f32 = 0 // Spawn platforms going upward (negative Y)
for !rl.WindowShouldClose() {
if game_over {
// Game over screen
rl.BeginDrawing()
defer rl.EndDrawing()
rl.ClearBackground(rl.BLACK)
rl.DrawText("GAME OVER!", 250, 250, 50, rl.RED)
score_text := fmt.ctprintf("Final Score: %d", score)
rl.DrawText(score_text, 300, 320, 30, rl.WHITE)
height_text := fmt.ctprintf("Max Height: %.0fm", abs(highest_y) / 20)
rl.DrawText(height_text, 280, 360, 25, rl.YELLOW)
rl.DrawText("Press R to Restart", 280, 400, 25, rl.WHITE)
if rl.IsKeyPressed(rl.KeyboardKey.R) {
// Reset game
player_pos = {400, 500}
player_vel = {0, 0}
score = 0
camera_offset = 0
highest_y = 500
game_over = false
is_grounded = false
// Reset platforms
clear(&platforms)
append(&platforms, Platform{{350, 500}, {200, 20}})
append(&platforms, Platform{{200, 400}, {150, 20}})
append(&platforms, Platform{{450, 320}, {150, 20}})
append(&platforms, Platform{{100, 240}, {150, 20}})
append(&platforms, Platform{{550, 160}, {150, 20}})
append(&platforms, Platform{{300, 80}, {200, 20}})
platform_spawn_y = 0
}
continue
}
dt := rl.GetFrameTime()
// Apply gravity
player_vel.y += gravity * dt
// Horizontal movement input
player_vel.x *= 0.9
if rl.IsKeyDown(rl.KeyboardKey.A) || rl.IsKeyDown(rl.KeyboardKey.LEFT) {
player_vel.x -= move_speed * dt
}
if rl.IsKeyDown(rl.KeyboardKey.D) || rl.IsKeyDown(rl.KeyboardKey.RIGHT) {
player_vel.x += move_speed * dt
}
// Jump input (only when grounded)
if (rl.IsKeyPressed(rl.KeyboardKey.J) || rl.IsKeyPressed(rl.KeyboardKey.SPACE)) && is_grounded {
player_vel.y = -jump_speed
}
// Update position
player_pos += player_vel * dt
// Track highest point reached
if player_pos.y < highest_y {
highest_y = player_pos.y
}
// Camera follows player vertically (inverted for upward movement)
target_camera := -(player_pos.y - 300) // Keep player in lower part of screen
camera_offset += (target_camera - camera_offset) * 5 * dt
// Keep player within horizontal screen bounds
if player_pos.x < 0 do player_pos.x = 0
if player_pos.x + player_size.x > 800 do player_pos.x = 800 - player_size.x
// Platform collision
is_grounded = false
for &platform in platforms {
// Check if player is landing on platform from above
if player_pos.x + player_size.x > platform.pos.x &&
player_pos.x < platform.pos.x + platform.size.x &&
player_pos.y + player_size.y > platform.pos.y &&
player_pos.y < platform.pos.y + platform.size.y &&
player_vel.y > 0 { // Only land when falling down
player_pos.y = platform.pos.y - player_size.y
player_vel.y = 0
is_grounded = true
break
}
}
// Generate new platforms as player climbs higher
if platform_spawn_y - player_pos.y > -200 { // Generate platforms above player
// Create platforms in a zig-zag pattern for vertical climbing
platform_x: f32
platform_width: f32 = f32(rl.GetRandomValue(120, 180))
// Alternate between left and right sides with some randomness
if rl.GetRandomValue(0, 1) == 0 {
platform_x = f32(rl.GetRandomValue(50, 300)) // Left side
} else {
platform_x = f32(rl.GetRandomValue(450, 700)) // Right side
}
// Ensure platform fits on screen
if platform_x + platform_width > 800 {
platform_x = 800 - platform_width
}
append(&platforms, Platform{{platform_x, platform_spawn_y}, {platform_width, 20}})
// Space platforms vertically for jumpable gaps
// With jump_speed=700 and gravity=1200, max jump height ≈ 204 pixels
platform_spawn_y -= f32(rl.GetRandomValue(120, 180)) // Vertical spacing
}
// Remove platforms that are too far below to save memory
for i := len(platforms) - 1; i >= 0; i -= 1 {
if platforms[i].pos.y > player_pos.y + 800 { // Remove platforms far below
ordered_remove(&platforms, i)
}
}
// Score increases as player climbs higher (negative Y = higher up)
new_score := i32(max(0, abs(highest_y - 500) / 20)) // 20 pixels = 1 point
if new_score > score {
score = new_score
}
// Game over if player falls too far below starting point
if player_pos.y > 800 {
game_over = true
}
// Render
rl.BeginDrawing()
defer rl.EndDrawing()
// Background gradient effect - darker as you go higher
bg_color := rl.Color{
u8(max(0, 20 + i32(player_pos.y) / 10)),
u8(max(0, 30 + i32(player_pos.y) / 15)),
u8(max(10, 60 + i32(player_pos.y) / 8)),
255
}
rl.ClearBackground(bg_color)
// Apply camera offset for vertical movement
rl.BeginMode2D({{0, camera_offset}, {0, 0}, 0, 1})
// Draw platforms
for platform in platforms {
rl.DrawRectangleV(platform.pos, platform.size, rl.BROWN)
rl.DrawRectangleLinesEx({platform.pos.x, platform.pos.y, platform.size.x, platform.size.y}, 2, rl.ORANGE)
}
// Draw player (green when grounded, red when airborne)
player_color := is_grounded ? rl.GREEN : rl.RED
rl.DrawRectangleV(player_pos, player_size, player_color)
rl.DrawRectangleLinesEx({player_pos.x, player_pos.y, player_size.x, player_size.y}, 2, rl.WHITE)
// Draw height markers every 100 pixels
for h := f32(0); h > player_pos.y - 600; h -= 100 {
height_m := abs(h - 500) / 20
marker_text := fmt.ctprintf("%.0fm", height_m)
rl.DrawText(marker_text, 10, i32(h), 20, rl.LIGHTGRAY)
rl.DrawLine(0, i32(h), 50, i32(h), rl.LIGHTGRAY)
}
rl.EndMode2D()
// Draw UI (fixed to screen)
score_text := fmt.ctprintf("Score: %d", score)
rl.DrawText(score_text, 10, 10, 30, rl.WHITE)
height_text := fmt.ctprintf("Height: %.0fm", abs(highest_y - 500) / 20)
rl.DrawText(height_text, 10, 50, 25, rl.YELLOW)
rl.DrawText("A/D: Move | Space/J: Jump | Climb as high as you can!", 10, 550, 18, rl.WHITE)
status_text := is_grounded ? "GROUNDED" : "AIRBORNE"
status_color := is_grounded ? rl.GREEN : rl.RED
rl.DrawText(cstring(raw_data(status_text)), 600, 10, 20, status_color)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment