Pimp floppy example

This commit is contained in:
Milan Nikolic 2017-02-03 00:26:27 +01:00
parent ea0628725d
commit ea2748fd8c

View file

@ -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
GameOver bool
Pause bool
Score int
HiScore int
FxFlap raylib.Sound
FxSlap raylib.Sound
FxPoint raylib.Sound
FxClick raylib.Sound
Floppy Floppy
Tubes []Tubes
TubesPos []raylib.Vector2
TubesSpeedX int32
SuperFX bool
Texture raylib.Texture2D
FrameRec raylib.Rectangle
GameOver bool
Dead bool
Pause bool
SuperFX bool
Score int
HiScore int
FramesCounter int32
WindowShouldClose bool
Floppy Floppy
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 < 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)
}
// 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 {
// 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
}
// Floppy fall down
g.Floppy.Position.Y += 1
}
}
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)
}
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
if raylib.IsKeyDown(raylib.KeySpace) && !g.GameOver {
g.Floppy.Position.Y -= 3
} else {
g.Floppy.Position.Y += 1
}
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
// 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
// Flash screen
g.SuperFX = true
g.SuperFX = true
// Update HiScore
if g.Score > g.HiScore {
g.HiScore = g.Score
}
if g.Score > g.HiScore {
g.HiScore = g.Score
raylib.PlaySound(g.FxPoint)
}
}
} else {
// 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) {
if raylib.IsKeyPressed(raylib.KeyEnter) || raylib.IsMouseButtonDown(raylib.MouseLeftButton) {
raylib.PlaySound(g.FxClick)
// Return of the Gopher!
g.Init()
g.GameOver = false
} 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()