Pimp floppy example
This commit is contained in:
parent
ea0628725d
commit
ea2748fd8c
1 changed files with 245 additions and 76 deletions
|
@ -2,148 +2,305 @@ package main
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"runtime"
|
||||
"unsafe"
|
||||
|
||||
"github.com/gen2brain/raylib-go/raylib"
|
||||
)
|
||||
|
||||
const (
|
||||
maxTubes = 100
|
||||
floppyRadius = 24.0
|
||||
tubesWidth = 80
|
||||
// Maximum number of pipes
|
||||
maxPipes = 100
|
||||
// Pipes width
|
||||
pipesWidth = 60
|
||||
// Sprite size
|
||||
spriteSize = 48
|
||||
)
|
||||
|
||||
// Floppy
|
||||
type Floppy struct {
|
||||
Position raylib.Vector2
|
||||
Radius float32
|
||||
Color raylib.Color
|
||||
}
|
||||
|
||||
type Tubes struct {
|
||||
// Pipe
|
||||
type Pipe struct {
|
||||
Rec raylib.Rectangle
|
||||
Color raylib.Color
|
||||
Active bool
|
||||
}
|
||||
|
||||
// Game
|
||||
type Game struct {
|
||||
ScreenWidth int32
|
||||
ScreenHeight int32
|
||||
|
||||
FramesCounter int32
|
||||
FxFlap raylib.Sound
|
||||
FxSlap raylib.Sound
|
||||
FxPoint raylib.Sound
|
||||
FxClick raylib.Sound
|
||||
|
||||
Texture raylib.Texture2D
|
||||
FrameRec raylib.Rectangle
|
||||
|
||||
GameOver bool
|
||||
Dead bool
|
||||
Pause bool
|
||||
SuperFX bool
|
||||
|
||||
Score int
|
||||
HiScore int
|
||||
FramesCounter int32
|
||||
WindowShouldClose bool
|
||||
|
||||
Floppy Floppy
|
||||
Tubes []Tubes
|
||||
TubesPos []raylib.Vector2
|
||||
TubesSpeedX int32
|
||||
SuperFX bool
|
||||
|
||||
Pipes []Pipe
|
||||
PipesPos []raylib.Vector2
|
||||
PipesSpeedX int32
|
||||
}
|
||||
|
||||
// New Game
|
||||
func NewGame() (g Game) {
|
||||
g.Init()
|
||||
return
|
||||
}
|
||||
|
||||
// On Android this sets callback function to be used for android_main
|
||||
func init() {
|
||||
raylib.SetCallbackFunc(run)
|
||||
}
|
||||
|
||||
// Main function, not used on Android, used on desktop platform
|
||||
func main() {
|
||||
game := Game{}
|
||||
game.Init()
|
||||
run(nil)
|
||||
}
|
||||
|
||||
raylib.InitWindow(game.ScreenWidth, game.ScreenHeight, "sample game: floppy")
|
||||
// Callback function on Android, not needed on desktop platform
|
||||
func run(app unsafe.Pointer) {
|
||||
// Initialize game
|
||||
game := NewGame()
|
||||
|
||||
// Initialize window
|
||||
if runtime.GOOS != "android" {
|
||||
raylib.InitWindow(game.ScreenWidth, game.ScreenHeight, "Floppy Gopher")
|
||||
} else {
|
||||
raylib.InitWindow(game.ScreenWidth, game.ScreenHeight, app)
|
||||
}
|
||||
|
||||
// Initialize audio
|
||||
raylib.InitAudioDevice()
|
||||
|
||||
// NOTE: Textures and Sounds MUST be loaded after Window/Audio initialization
|
||||
game.Load()
|
||||
|
||||
// Limit FPS
|
||||
raylib.SetTargetFPS(60)
|
||||
|
||||
for !raylib.WindowShouldClose() {
|
||||
// Main loop
|
||||
for !game.WindowShouldClose {
|
||||
// Update game
|
||||
game.Update()
|
||||
|
||||
// Draw game
|
||||
game.Draw()
|
||||
}
|
||||
|
||||
// Free resources
|
||||
game.Unload()
|
||||
|
||||
// Close audio
|
||||
raylib.CloseAudioDevice()
|
||||
|
||||
// Close window
|
||||
raylib.CloseWindow()
|
||||
|
||||
// Exit
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
// Initialize game
|
||||
func (g *Game) Init() {
|
||||
g.ScreenWidth = 800
|
||||
g.ScreenHeight = 450
|
||||
// Window resolution
|
||||
g.ScreenWidth = 504
|
||||
g.ScreenHeight = 896
|
||||
|
||||
g.Floppy = Floppy{}
|
||||
g.Floppy.Radius = floppyRadius
|
||||
g.Floppy.Position = raylib.NewVector2(80, float32(g.ScreenHeight)/2-g.Floppy.Radius)
|
||||
g.TubesSpeedX = 2
|
||||
g.Floppy.Position = raylib.NewVector2(80, float32(g.ScreenHeight)/2-spriteSize/2)
|
||||
g.PipesSpeedX = 2
|
||||
|
||||
g.TubesPos = make([]raylib.Vector2, maxTubes)
|
||||
// Sprite rectangle
|
||||
g.FrameRec = raylib.NewRectangle(0, 0, spriteSize, spriteSize)
|
||||
|
||||
for i := 0; i < maxTubes; i++ {
|
||||
g.TubesPos[i].X = float32(400 + 280*i)
|
||||
g.TubesPos[i].Y = -float32(raylib.GetRandomValue(0, 120))
|
||||
// Pipes positions
|
||||
g.PipesPos = make([]raylib.Vector2, maxPipes)
|
||||
for i := 0; i < maxPipes; i++ {
|
||||
g.PipesPos[i].X = float32(480 + 360*i)
|
||||
g.PipesPos[i].Y = -float32(raylib.GetRandomValue(0, 240))
|
||||
}
|
||||
|
||||
g.Tubes = make([]Tubes, maxTubes*2)
|
||||
// Pipes colors
|
||||
colors := []raylib.Color{
|
||||
raylib.Orange, raylib.Red, raylib.Gold, raylib.Lime,
|
||||
raylib.Violet, raylib.Brown, raylib.LightGray, raylib.Blue,
|
||||
raylib.Yellow, raylib.Green, raylib.Purple, raylib.Beige,
|
||||
}
|
||||
|
||||
for i := 0; i < maxTubes*2; i += 2 {
|
||||
g.Tubes[i].Rec.X = int32(g.TubesPos[i/2].X)
|
||||
g.Tubes[i].Rec.Y = int32(g.TubesPos[i/2].Y)
|
||||
g.Tubes[i].Rec.Width = tubesWidth
|
||||
g.Tubes[i].Rec.Height = 255
|
||||
// Pipes
|
||||
g.Pipes = make([]Pipe, maxPipes*2)
|
||||
for i := 0; i < maxPipes*2; i += 2 {
|
||||
g.Pipes[i].Rec.X = int32(g.PipesPos[i/2].X)
|
||||
g.Pipes[i].Rec.Y = int32(g.PipesPos[i/2].Y)
|
||||
g.Pipes[i].Rec.Width = pipesWidth
|
||||
g.Pipes[i].Rec.Height = 550
|
||||
g.Pipes[i].Color = colors[raylib.GetRandomValue(0, int32(len(colors)-1))]
|
||||
|
||||
g.Tubes[i+1].Rec.X = int32(g.TubesPos[i/2].X)
|
||||
g.Tubes[i+1].Rec.Y = int32(600 + g.TubesPos[i/2].Y - 255)
|
||||
g.Tubes[i+1].Rec.Width = tubesWidth
|
||||
g.Tubes[i+1].Rec.Height = 255
|
||||
g.Pipes[i+1].Rec.X = int32(g.PipesPos[i/2].X)
|
||||
g.Pipes[i+1].Rec.Y = int32(1200 + g.PipesPos[i/2].Y - 550)
|
||||
g.Pipes[i+1].Rec.Width = pipesWidth
|
||||
g.Pipes[i+1].Rec.Height = 550
|
||||
|
||||
g.Tubes[i/2].Active = true
|
||||
g.Pipes[i/2].Active = true
|
||||
}
|
||||
|
||||
g.Score = 0
|
||||
g.FramesCounter = 0
|
||||
g.WindowShouldClose = false
|
||||
|
||||
g.GameOver = false
|
||||
g.Dead = false
|
||||
g.SuperFX = false
|
||||
g.Pause = false
|
||||
}
|
||||
|
||||
// Load resources
|
||||
func (g *Game) Load() {
|
||||
g.FxFlap = raylib.LoadSound("sounds/flap.wav")
|
||||
g.FxSlap = raylib.LoadSound("sounds/slap.wav")
|
||||
g.FxPoint = raylib.LoadSound("sounds/point.wav")
|
||||
g.FxClick = raylib.LoadSound("sounds/click.wav")
|
||||
g.Texture = raylib.LoadTexture("images/sprite.png")
|
||||
}
|
||||
|
||||
// Unload resources
|
||||
func (g *Game) Unload() {
|
||||
raylib.UnloadSound(g.FxFlap)
|
||||
raylib.UnloadSound(g.FxSlap)
|
||||
raylib.UnloadSound(g.FxPoint)
|
||||
raylib.UnloadSound(g.FxClick)
|
||||
raylib.UnloadTexture(g.Texture)
|
||||
}
|
||||
|
||||
// Update game
|
||||
func (g *Game) Update() {
|
||||
if raylib.WindowShouldClose() {
|
||||
g.WindowShouldClose = true
|
||||
}
|
||||
|
||||
if !g.GameOver {
|
||||
if raylib.IsKeyPressed(raylib.KeyP) {
|
||||
if raylib.IsKeyPressed(raylib.KeyP) || raylib.IsKeyPressed(raylib.KeyBack) {
|
||||
raylib.PlaySound(g.FxClick)
|
||||
|
||||
if runtime.GOOS == "android" && g.Pause {
|
||||
g.WindowShouldClose = true
|
||||
}
|
||||
|
||||
g.Pause = !g.Pause
|
||||
}
|
||||
|
||||
if !g.Pause {
|
||||
for i := 0; i < maxTubes; i++ {
|
||||
g.TubesPos[i].X -= float32(g.TubesSpeedX)
|
||||
if !g.Dead {
|
||||
// Scroll X
|
||||
for i := 0; i < maxPipes; i++ {
|
||||
g.PipesPos[i].X -= float32(g.PipesSpeedX)
|
||||
}
|
||||
|
||||
for i := 0; i < maxTubes*2; i += 2 {
|
||||
g.Tubes[i].Rec.X = int32(g.TubesPos[i/2].X)
|
||||
g.Tubes[i+1].Rec.X = int32(g.TubesPos[i/2].X)
|
||||
for i := 0; i < maxPipes*2; i += 2 {
|
||||
g.Pipes[i].Rec.X = int32(g.PipesPos[i/2].X)
|
||||
g.Pipes[i+1].Rec.X = int32(g.PipesPos[i/2].X)
|
||||
}
|
||||
|
||||
if raylib.IsKeyDown(raylib.KeySpace) && !g.GameOver {
|
||||
// Movement/Controls
|
||||
if raylib.IsKeyDown(raylib.KeySpace) || raylib.IsMouseButtonDown(raylib.MouseLeftButton) && !g.GameOver {
|
||||
raylib.PlaySound(g.FxFlap)
|
||||
|
||||
// Switch flap sprites every 8 frames
|
||||
g.FramesCounter++
|
||||
if g.FramesCounter >= 8 {
|
||||
g.FramesCounter = 0
|
||||
g.FrameRec.X = spriteSize * 3
|
||||
} else {
|
||||
g.FrameRec.X = spriteSize * 2
|
||||
}
|
||||
|
||||
// Floppy go up
|
||||
g.Floppy.Position.Y -= 3
|
||||
} else {
|
||||
g.Floppy.Position.Y += 1
|
||||
// Default sprite
|
||||
//g.FrameRec.X = spriteSize
|
||||
|
||||
// Switch flap sprites every 8 frames
|
||||
g.FramesCounter++
|
||||
if g.FramesCounter >= 8 {
|
||||
g.FramesCounter = 0
|
||||
g.FrameRec.X = spriteSize
|
||||
} else {
|
||||
g.FrameRec.X = 0
|
||||
}
|
||||
|
||||
// Check Collisions
|
||||
for i := 0; i < maxTubes*2; i++ {
|
||||
if raylib.CheckCollisionCircleRec(g.Floppy.Position, g.Floppy.Radius, g.Tubes[i].Rec) {
|
||||
g.GameOver = true
|
||||
g.Pause = false
|
||||
} else if (g.TubesPos[i/2].X < g.Floppy.Position.X) && g.Tubes[i/2].Active && !g.GameOver {
|
||||
g.Score += 100
|
||||
g.Tubes[i/2].Active = false
|
||||
// Floppy fall down
|
||||
g.Floppy.Position.Y += 1
|
||||
}
|
||||
}
|
||||
|
||||
if !g.Dead {
|
||||
// Check Collisions
|
||||
for i := 0; i < maxPipes*2; i++ {
|
||||
if raylib.CheckCollisionRecs(raylib.NewRectangle(int32(g.Floppy.Position.X), int32(g.Floppy.Position.Y), spriteSize, spriteSize), g.Pipes[i].Rec) {
|
||||
// OMG You killed Gopher you bastard!
|
||||
g.Dead = true
|
||||
|
||||
raylib.PlaySound(g.FxSlap)
|
||||
} else if (g.PipesPos[i/2].X < g.Floppy.Position.X-spriteSize) && g.Pipes[i/2].Active && !g.GameOver {
|
||||
// Score point
|
||||
g.Score += 1
|
||||
g.Pipes[i/2].Active = false
|
||||
|
||||
// Flash screen
|
||||
g.SuperFX = true
|
||||
|
||||
// Update HiScore
|
||||
if g.Score > g.HiScore {
|
||||
g.HiScore = g.Score
|
||||
}
|
||||
}
|
||||
|
||||
raylib.PlaySound(g.FxPoint)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if raylib.IsKeyPressed(raylib.KeyEnter) {
|
||||
g.Init()
|
||||
g.GameOver = false
|
||||
// Wait 60 frames before GameOver
|
||||
g.FramesCounter++
|
||||
if g.FramesCounter >= 60 {
|
||||
g.GameOver = true
|
||||
}
|
||||
|
||||
g.FrameRec.X = spriteSize * 4
|
||||
}
|
||||
} else {
|
||||
if raylib.IsMouseButtonDown(raylib.MouseLeftButton) {
|
||||
g.Pause = !g.Pause
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if raylib.IsKeyPressed(raylib.KeyEnter) || raylib.IsMouseButtonDown(raylib.MouseLeftButton) {
|
||||
raylib.PlaySound(g.FxClick)
|
||||
|
||||
// Return of the Gopher!
|
||||
g.Init()
|
||||
} else if runtime.GOOS == "android" && raylib.IsKeyDown(raylib.KeyBack) {
|
||||
g.WindowShouldClose = true
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -151,31 +308,43 @@ func (g *Game) Update() {
|
|||
func (g *Game) Draw() {
|
||||
raylib.BeginDrawing()
|
||||
|
||||
raylib.ClearBackground(raylib.RayWhite)
|
||||
raylib.ClearBackground(raylib.SkyBlue)
|
||||
|
||||
if !g.GameOver {
|
||||
raylib.DrawCircle(int32(g.Floppy.Position.X), int32(g.Floppy.Position.Y), g.Floppy.Radius, raylib.DarkGray)
|
||||
// Draw Gopher
|
||||
raylib.DrawTextureRec(g.Texture, g.FrameRec, g.Floppy.Position, raylib.RayWhite) // Draw part of the texture
|
||||
|
||||
// Draw tubes
|
||||
for i := 0; i < maxTubes; i++ {
|
||||
raylib.DrawRectangle(g.Tubes[i*2].Rec.X, g.Tubes[i*2].Rec.Y, g.Tubes[i*2].Rec.Width, g.Tubes[i*2].Rec.Height, raylib.Gray)
|
||||
raylib.DrawRectangle(g.Tubes[i*2+1].Rec.X, g.Tubes[i*2+1].Rec.Y, g.Tubes[i*2+1].Rec.Width, g.Tubes[i*2+1].Rec.Height, raylib.Gray)
|
||||
// Draw pipes
|
||||
for i := 0; i < maxPipes; i++ {
|
||||
raylib.DrawRectangle(g.Pipes[i*2].Rec.X, g.Pipes[i*2].Rec.Y, g.Pipes[i*2].Rec.Width, g.Pipes[i*2].Rec.Height, g.Pipes[i*2].Color)
|
||||
raylib.DrawRectangle(g.Pipes[i*2+1].Rec.X, g.Pipes[i*2+1].Rec.Y, g.Pipes[i*2+1].Rec.Width, g.Pipes[i*2+1].Rec.Height, g.Pipes[i*2].Color)
|
||||
|
||||
// Draw borders
|
||||
raylib.DrawRectangleLines(g.Pipes[i*2].Rec.X, g.Pipes[i*2].Rec.Y, g.Pipes[i*2].Rec.Width, g.Pipes[i*2].Rec.Height, raylib.Black)
|
||||
raylib.DrawRectangleLines(g.Pipes[i*2+1].Rec.X, g.Pipes[i*2+1].Rec.Y, g.Pipes[i*2+1].Rec.Width, g.Pipes[i*2+1].Rec.Height, raylib.Black)
|
||||
}
|
||||
|
||||
// Draw flashing fx (one frame only)
|
||||
// Draw Super Flashing FX (one frame only)
|
||||
if g.SuperFX {
|
||||
raylib.DrawRectangle(0, 0, g.ScreenWidth, g.ScreenHeight, raylib.White)
|
||||
g.SuperFX = false
|
||||
}
|
||||
|
||||
raylib.DrawText(fmt.Sprintf("%04d", g.Score), 20, 20, 40, raylib.Gray)
|
||||
raylib.DrawText(fmt.Sprintf("HI-SCORE: %04d", g.HiScore), 20, 70, 20, raylib.LightGray)
|
||||
// Draw HI-SCORE
|
||||
raylib.DrawText(fmt.Sprintf("%02d", g.Score), 20, 20, 32, raylib.RayWhite)
|
||||
raylib.DrawText(fmt.Sprintf("HI-SCORE: %02d", g.HiScore), 20, 64, 20, raylib.RayWhite)
|
||||
|
||||
if g.Pause {
|
||||
raylib.DrawText("GAME PAUSED", g.ScreenWidth/2-raylib.MeasureText("GAME PAUSED", 40)/2, g.ScreenHeight/2-40, 40, raylib.Gray)
|
||||
// Draw PAUSED text
|
||||
raylib.DrawText("PAUSED", g.ScreenWidth/2-raylib.MeasureText("PAUSED", 24)/2, g.ScreenHeight/2-50, 20, raylib.RayWhite)
|
||||
}
|
||||
} else {
|
||||
raylib.DrawText("PRESS [ENTER] TO PLAY AGAIN", raylib.GetScreenWidth()/2-raylib.MeasureText("PRESS [ENTER] TO PLAY AGAIN", 20)/2, raylib.GetScreenHeight()/2-50, 20, raylib.Gray)
|
||||
// Draw PLAY AGAIN text
|
||||
if runtime.GOOS == "android" {
|
||||
raylib.DrawText("[TAP] TO PLAY AGAIN", raylib.GetScreenWidth()/2-raylib.MeasureText("[TAP] TO PLAY AGAIN", 20)/2, raylib.GetScreenHeight()/2-50, 20, raylib.RayWhite)
|
||||
} else {
|
||||
raylib.DrawText("[ENTER] TO PLAY AGAIN", raylib.GetScreenWidth()/2-raylib.MeasureText("[ENTER] TO PLAY AGAIN", 20)/2, raylib.GetScreenHeight()/2-50, 20, raylib.RayWhite)
|
||||
}
|
||||
}
|
||||
|
||||
raylib.EndDrawing()
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue