Compare commits

...

3 Commits

Author SHA1 Message Date
c9d3d0c65f README and persist high score on game over screen 2024-09-23 12:37:02 +02:00
a3dd393b7f Add high score and asphalt/stripes 2024-09-23 12:28:40 +02:00
3779c2ada7 Fix shitcode 2024-09-23 12:13:51 +02:00
6 changed files with 133 additions and 200 deletions

View File

@ -1,2 +1,10 @@
# autogo # autogo
The silly Raylib cargame I made in C but in Go The silly Raylib cargame I made in C but in Go for my champ
## Screenshot
![Screenshot](./resources/screenshot.png)
### note Garage texture
changed saturation to 10% to make Raylib tint work well enough, using ImageMagick:
```convert garage.png -resize 200x200! -channel A -evaluate multiply 0.5 +channel -modulate 100,25,100 garage_200px.png```

3
go.mod
View File

@ -2,9 +2,10 @@ module github.com/bdnugget/autogo.git
go 1.23.0 go 1.23.0
require github.com/gen2brain/raylib-go/raylib v0.0.0-20240826113553-b4d0c52dc927
require ( require (
github.com/ebitengine/purego v0.7.1 // indirect github.com/ebitengine/purego v0.7.1 // indirect
github.com/gen2brain/raylib-go/raylib v0.0.0-20240826113553-b4d0c52dc927 // indirect
golang.org/x/exp v0.0.0-20240823005443-9b4947da3948 // indirect golang.org/x/exp v0.0.0-20240823005443-9b4947da3948 // indirect
golang.org/x/sys v0.24.0 // indirect golang.org/x/sys v0.24.0 // indirect
) )

320
main.go
View File

@ -3,234 +3,158 @@ package main
import ( import (
"fmt" "fmt"
"math/rand" "math/rand"
"time"
rl "github.com/gen2brain/raylib-go/raylib" rl "github.com/gen2brain/raylib-go/raylib"
) )
const ( const (
SQUARE_SIZE int32 = 200 screenWidth = 1600
FPS_TARGET int32 = 60 screenHeight = 800
GARAGE_COUNT int32 = 5 numLanes = 5
numGarages = 5
carSpeed = 5
laneHeight = screenHeight / numLanes
)
var (
garageColors = [numGarages]rl.Color{rl.Red, rl.Blue, rl.Green, rl.Yellow, rl.Purple}
autoHappy rl.Sound
autoSad rl.Sound
autoTexture rl.Texture2D
garageTexture rl.Texture2D
highScore int
) )
type Car struct { type Car struct {
position rl.Vector2 texture rl.Texture2D
size rl.Vector2 lane int
color rl.Color color rl.Color
direction int32 xPos int
} }
type Garage struct { type Garage struct {
position rl.Vector2 lane int
size rl.Vector2 color rl.Color
color rl.Color
} }
type GameState struct { type Game struct {
score int32 car Car
car Car garages [numGarages]Garage
framesCounter int32 score int
gameOver bool gameOver bool
pause bool
allowMove bool
garages []Garage
} }
var ( func NewCar() Car {
screenWidth int32 = 1600 return Car{
screenHeight int32 = 1000 texture: autoTexture,
lane: rand.Intn(numLanes),
color: randomColor(),
xPos: 25,
}
}
autoTexture rl.Texture2D func NewGame() *Game {
autoHappy rl.Sound game := &Game{
autoSad rl.Sound car: NewCar(),
garageColors = []rl.Color{rl.Red, rl.Green, rl.Blue, rl.Yellow, rl.Purple} score: 0,
gameState GameState gameOver: false,
offset rl.Vector2 }
)
// Initialize garages
for i := range game.garages {
game.garages[i] = Garage{
lane: i,
color: garageColors[i],
}
}
return game
}
func randomColor() rl.Color {
return garageColors[rand.Intn(len(garageColors))]
}
func (g *Game) draw() {
// Draw stripes on the road
for i := 0; i < numLanes; i++ {
rl.DrawRectangle(0, int32(i*laneHeight), screenWidth, 2, rl.White)
}
// Draw garages
for _, garage := range g.garages {
rl.DrawRectangle(int32(screenWidth-150), int32(garage.lane*laneHeight), 150, int32(laneHeight), garage.color)
rl.DrawTexture(garageTexture, int32(screenWidth-150), int32(garage.lane*laneHeight), garage.color)
}
// Draw car
rl.DrawTexture(g.car.texture, int32(g.car.xPos), int32(g.car.lane*laneHeight), g.car.color)
rl.DrawText(fmt.Sprintf("Score: %d\nHigh Score: %d", g.score, highScore), 10, 10, 32, rl.DarkGreen)
if g.gameOver {
rl.DrawText("You're not an WinRAR :(\nPress Enter to Restart", int32(screenWidth/2-150), int32(screenHeight/2-20), 32, rl.Red)
}
}
func (g *Game) update() {
if g.gameOver {
if rl.IsKeyPressed(rl.KeyEnter) {
*g = *NewGame()
}
return
}
g.car.xPos += carSpeed
// Check if the car has reached the garages
if int32(g.car.xPos)+g.car.texture.Width >= screenWidth-100 {
garage := g.garages[g.car.lane]
if g.car.color == garage.color {
rl.PlaySound(autoHappy)
g.score++
if g.score > highScore {
highScore = g.score
}
g.car = NewCar()
} else {
rl.PlaySound(autoSad)
g.gameOver = true
}
}
// Move car
if rl.IsKeyPressed(rl.KeyUp) && g.car.lane > 0 {
g.car.lane--
} else if (rl.IsKeyPressed(rl.KeyDown) || rl.IsKeyPressed(rl.KeyLeft) || rl.IsKeyPressed(rl.KeyRight)) && g.car.lane < numLanes-1 {
g.car.lane++
}
}
func main() { func main() {
rl.InitWindow(screenWidth, screenHeight, "Dikke Vette Cargame voor Milo") rl.InitWindow(screenWidth, screenHeight, "Dikke Vette Cargame voor Milo")
rl.InitAudioDevice() rl.InitAudioDevice()
defer rl.CloseAudioDevice() defer rl.CloseAudioDevice()
defer rl.CloseWindow()
// Load assets
autoHappy = rl.LoadSound("resources/auto_happy_vob.ogg") autoHappy = rl.LoadSound("resources/auto_happy_vob.ogg")
autoSad = rl.LoadSound("resources/auto_sad_vob.ogg") autoSad = rl.LoadSound("resources/auto_sad_vob.ogg")
autoTexture = rl.LoadTexture("resources/car_200px.png") autoTexture = rl.LoadTexture("resources/car_200px.png")
garageTexture = rl.LoadTexture("resources/garage_200px.png")
defer rl.UnloadTexture(autoTexture)
defer rl.UnloadSound(autoHappy) defer rl.UnloadSound(autoHappy)
defer rl.UnloadSound(autoSad) defer rl.UnloadSound(autoSad)
defer rl.UnloadTexture(autoTexture)
offset = rl.Vector2{X: float32(screenWidth % SQUARE_SIZE), Y: float32(screenHeight % SQUARE_SIZE)} game := NewGame()
InitGame() rl.SetTargetFPS(60)
rl.SetTargetFPS(FPS_TARGET)
for !rl.WindowShouldClose() { for !rl.WindowShouldClose() {
UpdateDrawFrame() rl.BeginDrawing()
rl.ClearBackground(rl.DarkGray)
game.update()
game.draw()
rl.EndDrawing()
} }
} }
func InitGame() {
rand.Seed(time.Now().UnixNano())
randomIndex := rand.Intn(int(GARAGE_COUNT))
gameState.framesCounter = 0
gameState.gameOver = false
gameState.pause = false
gameState.allowMove = false
gameState.car = Car{
position: rl.Vector2{X: offset.X / 2, Y: offset.Y/2 + 2*float32(SQUARE_SIZE)},
size: rl.Vector2{X: float32(SQUARE_SIZE), Y: float32(SQUARE_SIZE)},
color: garageColors[randomIndex],
direction: 0,
}
gameState.garages = make([]Garage, GARAGE_COUNT)
InitGarages()
}
func UpdateDrawFrame() {
UpdateGame()
DrawGame()
}
func UpdateGame() {
if !gameState.gameOver {
HandlePause()
HandleMovement()
CheckCollisions()
IncrementFrameCounter()
} else {
HandleRestart()
}
}
func HandlePause() {
if rl.IsKeyPressed(int32('P')) {
gameState.pause = !gameState.pause
}
}
func HandleMovement() {
if !gameState.pause {
if rl.IsKeyPressed(rl.KeyUp) && gameState.allowMove && gameState.car.position.Y > 0 {
gameState.car.direction = -1
gameState.allowMove = false
}
if (rl.IsKeyPressed(rl.KeyDown) || rl.IsKeyPressed(rl.KeyLeft) || rl.IsKeyPressed(rl.KeyRight)) &&
gameState.allowMove &&
gameState.car.position.Y < float32(screenHeight-SQUARE_SIZE) {
gameState.car.direction = 1
gameState.allowMove = false
}
if gameState.framesCounter%(FPS_TARGET/60) == 0 {
MoveCar()
}
}
}
func MoveCar() {
gameState.car.position.X += float32(SQUARE_SIZE) / float32(FPS_TARGET)
gameState.car.position.Y += float32(gameState.car.direction * SQUARE_SIZE)
gameState.allowMove = true
gameState.car.direction = 0
}
func CheckCollisions() {
for i := int32(0); i < GARAGE_COUNT; i++ {
if rl.CheckCollisionRecs(
rl.Rectangle{X: gameState.car.position.X, Y: gameState.car.position.Y, Width: gameState.car.size.X, Height: gameState.car.size.Y},
rl.Rectangle{X: gameState.garages[i].position.X, Y: gameState.garages[i].position.Y, Width: gameState.garages[i].size.X, Height: gameState.garages[i].size.Y},
) {
HandleCollision(i)
}
}
}
func HandleCollision(index int32) {
if rl.ColorToInt(gameState.car.color) == rl.ColorToInt(gameState.garages[index].color) {
rl.PlaySound(autoHappy)
gameState.score++
InitGame()
} else {
rl.PlaySound(autoSad)
gameState.gameOver = true
}
}
func IncrementFrameCounter() {
gameState.framesCounter++
}
func HandleRestart() {
if rl.IsKeyPressed(rl.KeyEnter) {
gameState.score = 0
InitGame()
}
}
func DrawGame() {
rl.BeginDrawing()
rl.ClearBackground(rl.DarkGray)
if !gameState.gameOver {
for i := int32(1); i < screenHeight/SQUARE_SIZE+1; i++ {
for j := int32(0); j < screenWidth/(SQUARE_SIZE/2); j += 2 {
rl.DrawRectangle(
int32(j)*((SQUARE_SIZE/2)+int32(offset.X)/2),
int32(i*SQUARE_SIZE+int32(offset.Y)/2),
SQUARE_SIZE/2,
SQUARE_SIZE/8,
rl.RayWhite,
)
}
}
// Draw garages
for i := int32(0); i < GARAGE_COUNT; i++ {
rl.DrawRectangleRec(
rl.Rectangle{X: gameState.garages[i].position.X, Y: gameState.garages[i].position.Y, Width: gameState.garages[i].size.X, Height: gameState.garages[i].size.Y},
gameState.garages[i].color,
)
}
rl.DrawTextureV(autoTexture, gameState.car.position, gameState.car.color)
// Draw score
rl.DrawText(fmt.Sprintf("Score: %d", gameState.score), 20, 20, 20, rl.RayWhite)
if gameState.pause {
rl.DrawText(
"GAME PAUSED",
screenWidth/2-rl.MeasureText("GAME PAUSED", 40)/2,
screenHeight/2-40,
40,
rl.Gray,
)
}
} else {
rl.DrawText(
"A WINRAR IS NOT YOU :(\nPRESS [ENTER] TO PLAY AGAIN",
screenWidth/2-rl.MeasureText("A WINRAR IS NOT YOU :(\nPRESS [ENTER] TO PLAY AGAIN", 20)/2,
screenHeight/2-50,
20,
rl.Gray,
)
}
rl.EndDrawing()
}
func InitGarages() {
for i := int32(0); i < GARAGE_COUNT; i++ {
gameState.garages[i].size = rl.Vector2{X: float32(SQUARE_SIZE), Y: float32(SQUARE_SIZE)}
gameState.garages[i].position = rl.Vector2{X: float32(screenWidth - SQUARE_SIZE), Y: float32(i * SQUARE_SIZE)}
gameState.garages[i].color = garageColors[i]
}
}

BIN
resources/garage.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

BIN
resources/garage_200px.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

BIN
resources/screenshot.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB