From d9d26d30f31d3003c375aba869925fca0215ff1e Mon Sep 17 00:00:00 2001 From: Milan Nikolic Date: Sat, 25 Feb 2017 21:54:32 +0100 Subject: [PATCH] Add scrolling background and particles --- examples/games/floppy/README.md | 3 + examples/games/floppy/images/clouds.png | Bin 0 -> 4771 bytes examples/games/floppy/images/smoke.png | Bin 0 -> 10010 bytes examples/games/floppy/main.go | 192 +++++++++++++++++++----- 4 files changed, 155 insertions(+), 40 deletions(-) create mode 100644 examples/games/floppy/README.md create mode 100644 examples/games/floppy/images/clouds.png create mode 100644 examples/games/floppy/images/smoke.png diff --git a/examples/games/floppy/README.md b/examples/games/floppy/README.md new file mode 100644 index 0000000..affbc19 --- /dev/null +++ b/examples/games/floppy/README.md @@ -0,0 +1,3 @@ +## Floppy Gopher + +![screenshot](https://goo.gl/uwRi60) diff --git a/examples/games/floppy/images/clouds.png b/examples/games/floppy/images/clouds.png new file mode 100644 index 0000000000000000000000000000000000000000..7b5bf85064f53482481cc1781b91cd1b66527dc4 GIT binary patch literal 4771 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 VMm~ciFMy5!($4Wr^{>8Z{|C!1%gF!$ literal 0 HcmV?d00001 diff --git a/examples/games/floppy/images/smoke.png b/examples/games/floppy/images/smoke.png new file mode 100644 index 0000000000000000000000000000000000000000..85cd23777b95aa082fff90262cef3f50c200ba42 GIT binary patch literal 10010 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 literal 0 HcmV?d00001 diff --git a/examples/games/floppy/main.go b/examples/games/floppy/main.go index d10918c..fd1bbf2 100644 --- a/examples/games/floppy/main.go +++ b/examples/games/floppy/main.go @@ -10,12 +10,28 @@ import ( ) const ( + // Screen width + screenWidth = 504 + // Screen height + screenHeight = 896 + // Maximum number of pipes maxPipes = 100 + // Maximum number of particles + maxParticles = 50 + // Pipes width pipesWidth = 60 // Sprite size spriteSize = 48 + + // Pipes speed + pipesSpeedX = 2.5 + // Clouds speed + cloudsSpeedX = 1 + + // Gravity + gravity = 1.2 ) // Floppy type @@ -30,17 +46,28 @@ type Pipe struct { Active bool } +// Particle type +type Particle struct { + Position raylib.Vector2 + Color raylib.Color + Alpha float32 + Size float32 + Rotation float32 + Active bool +} + // Game type type Game struct { - ScreenWidth int32 - ScreenHeight int32 - FxFlap raylib.Sound FxSlap raylib.Sound FxPoint raylib.Sound FxClick raylib.Sound - Texture raylib.Texture2D + TxSprites raylib.Texture2D + TxSmoke raylib.Texture2D + TxClouds raylib.Texture2D + + CloudRec raylib.Rectangle FrameRec raylib.Rectangle GameOver bool @@ -48,16 +75,17 @@ type Game struct { Pause bool SuperFX bool - Score int - HiScore int - FramesCounter int32 + Score int + HiScore int + FramesCounter int32 + WindowShouldClose bool - Floppy Floppy + Floppy Floppy + Particles []Particle - Pipes []Pipe - PipesPos []raylib.Vector2 - PipesSpeedX int32 + Pipes []Pipe + PipesPos []raylib.Vector2 } // NewGame - Start new game @@ -80,12 +108,13 @@ func main() { func run(app unsafe.Pointer) { // Initialize game game := NewGame() + game.GameOver = true // Initialize window if runtime.GOOS != "android" { - raylib.InitWindow(game.ScreenWidth, game.ScreenHeight, "Floppy Gopher") + raylib.InitWindow(screenWidth, screenHeight, "Floppy Gopher") } else { - raylib.InitWindow(game.ScreenWidth, game.ScreenHeight, app) + raylib.InitWindow(screenWidth, screenHeight, app) } // Initialize audio @@ -121,17 +150,27 @@ func run(app unsafe.Pointer) { // Init - Initialize game func (g *Game) Init() { - // Window resolution - g.ScreenWidth = 504 - g.ScreenHeight = 896 - g.Floppy = Floppy{} - g.Floppy.Position = raylib.NewVector2(80, float32(g.ScreenHeight)/2-spriteSize/2) - g.PipesSpeedX = 2 + // Gopher + g.Floppy = Floppy{raylib.NewVector2(80, float32(screenHeight)/2-spriteSize/2)} // Sprite rectangle g.FrameRec = raylib.NewRectangle(0, 0, spriteSize, spriteSize) + // Cloud rectangle + g.CloudRec = raylib.NewRectangle(0, 0, screenWidth, g.TxClouds.Height) + + // Initialize particles + g.Particles = make([]Particle, maxParticles) + for i := 0; i < maxParticles; i++ { + g.Particles[i].Position = raylib.NewVector2(0, 0) + g.Particles[i].Color = raylib.RayWhite + g.Particles[i].Alpha = 1.0 + g.Particles[i].Size = float32(raylib.GetRandomValue(1, 30)) / 20.0 + g.Particles[i].Rotation = float32(raylib.GetRandomValue(0, 360)) + g.Particles[i].Active = false + } + // Pipes positions g.PipesPos = make([]raylib.Vector2, maxPipes) for i := 0; i < maxPipes; i++ { @@ -179,7 +218,9 @@ func (g *Game) Load() { 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") + g.TxSprites = raylib.LoadTexture("images/sprite.png") + g.TxSmoke = raylib.LoadTexture("images/smoke.png") + g.TxClouds = raylib.LoadTexture("images/clouds.png") } // Unload - Unload resources @@ -188,7 +229,9 @@ func (g *Game) Unload() { raylib.UnloadSound(g.FxSlap) raylib.UnloadSound(g.FxPoint) raylib.UnloadSound(g.FxClick) - raylib.UnloadTexture(g.Texture) + raylib.UnloadTexture(g.TxSprites) + raylib.UnloadTexture(g.TxSmoke) + raylib.UnloadTexture(g.TxClouds) } // Update - Update game @@ -210,9 +253,9 @@ func (g *Game) Update() { if !g.Pause { if !g.Dead { - // Scroll X + // Scroll pipes for i := 0; i < maxPipes; i++ { - g.PipesPos[i].X -= float32(g.PipesSpeedX) + g.PipesPos[i].X -= float32(pipesSpeedX) } for i := 0; i < maxPipes*2; i += 2 { @@ -220,10 +263,28 @@ func (g *Game) Update() { g.Pipes[i+1].Rec.X = int32(g.PipesPos[i/2].X) } + // Scroll clouds + g.CloudRec.X += cloudsSpeedX + if g.CloudRec.X > g.TxClouds.Width { + g.CloudRec.X = 0 + } + // Movement/Controls - if raylib.IsKeyDown(raylib.KeySpace) || raylib.IsMouseButtonDown(raylib.MouseLeftButton) && !g.GameOver { + if raylib.IsKeyDown(raylib.KeySpace) || raylib.IsMouseButtonDown(raylib.MouseLeftButton) { raylib.PlaySound(g.FxFlap) + // Activate one particle every frame + for i := 0; i < maxParticles; i++ { + if !g.Particles[i].Active { + g.Particles[i].Active = true + g.Particles[i].Alpha = 1.0 + g.Particles[i].Position = g.Floppy.Position + g.Particles[i].Position.X += spriteSize / 2 + g.Particles[i].Position.Y += spriteSize / 2 + i = maxParticles + } + } + // Switch flap sprites every 8 frames g.FramesCounter++ if g.FramesCounter >= 8 { @@ -236,10 +297,7 @@ func (g *Game) Update() { // Floppy go up g.Floppy.Position.Y -= 3 } else { - // Default sprite - //g.FrameRec.X = spriteSize - - // Switch flap sprites every 8 frames + // Switch run sprites every 8 frames g.FramesCounter++ if g.FramesCounter >= 8 { g.FramesCounter = 0 @@ -249,11 +307,23 @@ func (g *Game) Update() { } // Floppy fall down - g.Floppy.Position.Y += 1 + g.Floppy.Position.Y += gravity + } + + // Update active particles + for i := 0; i < maxParticles; i++ { + if g.Particles[i].Active { + g.Particles[i].Position.X -= 1.0 + g.Particles[i].Alpha -= 0.05 + + if g.Particles[i].Alpha <= 0.0 { + g.Particles[i].Active = false + } + + g.Particles[i].Rotation += 3.0 + } } - } - 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) { @@ -284,7 +354,12 @@ func (g *Game) Update() { g.GameOver = true } - g.FrameRec.X = spriteSize * 4 + // Switch dead sprite + if g.FramesCounter >= 8 { + g.FrameRec.X = spriteSize * 5 + } else { + g.FrameRec.X = spriteSize * 4 + } } } else { if raylib.IsMouseButtonDown(raylib.MouseLeftButton) { @@ -301,6 +376,15 @@ func (g *Game) Update() { g.WindowShouldClose = true } + // Switch flap sprites + g.FramesCounter++ + if g.FramesCounter >= 8 { + g.FramesCounter = 0 + g.FrameRec.X = spriteSize + } else { + g.FrameRec.X = 0 + } + } } @@ -311,8 +395,31 @@ func (g *Game) Draw() { raylib.ClearBackground(raylib.SkyBlue) if !g.GameOver { + // Draw clouds + raylib.DrawTextureRec(g.TxClouds, g.CloudRec, raylib.NewVector2(0, float32(screenHeight-g.TxClouds.Height)), raylib.RayWhite) + + // Draw rotated clouds + raylib.DrawTexturePro(g.TxClouds, raylib.NewRectangle(-g.CloudRec.X, 0, g.TxClouds.Width, g.TxClouds.Height), + raylib.NewRectangle(0, 0, g.TxClouds.Width, g.TxClouds.Height), raylib.NewVector2(float32(g.TxClouds.Width), float32(g.TxClouds.Height)), 180, raylib.White) + // Draw Gopher - raylib.DrawTextureRec(g.Texture, g.FrameRec, g.Floppy.Position, raylib.RayWhite) // Draw part of the texture + raylib.DrawTextureRec(g.TxSprites, g.FrameRec, g.Floppy.Position, raylib.RayWhite) + + // Draw active particles + if !g.Dead { + for i := 0; i < maxParticles; i++ { + if g.Particles[i].Active { + raylib.DrawTexturePro( + g.TxSmoke, + raylib.NewRectangle(0, 0, g.TxSmoke.Width, g.TxSmoke.Height), + raylib.NewRectangle(int32(g.Particles[i].Position.X), int32(g.Particles[i].Position.Y), g.TxSmoke.Width*int32(g.Particles[i].Size), g.TxSmoke.Height*int32(g.Particles[i].Size)), + raylib.NewVector2(float32(g.TxSmoke.Width)*g.Particles[i].Size/2, float32(g.TxSmoke.Height)*g.Particles[i].Size/2), + g.Particles[i].Rotation, + raylib.Fade(g.Particles[i].Color, g.Particles[i].Alpha), + ) + } + } + } // Draw pipes for i := 0; i < maxPipes; i++ { @@ -326,25 +433,30 @@ func (g *Game) Draw() { // Draw Super Flashing FX (one frame only) if g.SuperFX { - raylib.DrawRectangle(0, 0, g.ScreenWidth, g.ScreenHeight, raylib.White) + raylib.DrawRectangle(0, 0, screenWidth, screenHeight, raylib.White) g.SuperFX = false } // 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) + raylib.DrawText(fmt.Sprintf("%02d", g.Score), 20, 20, 32, raylib.Black) + raylib.DrawText(fmt.Sprintf("HI-SCORE: %02d", g.HiScore), 20, 64, 20, raylib.Black) if g.Pause { // Draw PAUSED text - raylib.DrawText("PAUSED", g.ScreenWidth/2-raylib.MeasureText("PAUSED", 24)/2, g.ScreenHeight/2-50, 20, raylib.RayWhite) + raylib.DrawText("PAUSED", screenWidth/2-raylib.MeasureText("PAUSED", 24)/2, screenHeight/2-50, 20, raylib.Black) } } else { - // Draw PLAY AGAIN text + // Draw text + raylib.DrawText("Floppy Gopher", raylib.GetScreenWidth()/2-raylib.MeasureText("Floppy Gopher", 40)/2, raylib.GetScreenHeight()/2-150, 40, raylib.RayWhite) + 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) + raylib.DrawText("[TAP] TO PLAY", raylib.GetScreenWidth()/2-raylib.MeasureText("[TAP] TO PLAY", 20)/2, raylib.GetScreenHeight()/2-50, 20, raylib.Black) } 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.DrawText("[ENTER] TO PLAY", raylib.GetScreenWidth()/2-raylib.MeasureText("[ENTER] TO PLAY", 20)/2, raylib.GetScreenHeight()/2-50, 20, raylib.Black) } + + // Draw Gopher + raylib.DrawTextureRec(g.TxSprites, g.FrameRec, raylib.NewVector2(float32(raylib.GetScreenWidth()/2-spriteSize/2), float32(raylib.GetScreenHeight()/2)), raylib.RayWhite) } raylib.EndDrawing()