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
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()