Cloud Buster
Updated on June 26th, 2021 at 1:13 am
What is it?
This was a game that I created in my mobile development class at my Junior College. The app was made with the Corona SDK and programmed in Lua. The concept of the game is based on a popular game called “Flappy Bird”. You play as an airplane that you can control by touching anywhere on the screen. The longer you touch the screen, the longer the plane flies up. As you release your finger from the screen, the plane falls down.
The goal of the game is to run into as many white clouds as you can. There is no end game screen, instead, the goal is to raise your score as high as possible. Your plane only has three lives and flying into gray clouds drops lives. After losing all three lives, the game is over and your score drops to 0. However, you are able to gain lives back by flying into the rare and mysterious rainbow clouds.

What does it do?
This app was designed to be a 2k mobile game. It was created with the Corona SDK and as such, can be built for iOS and Android devices. It may be possible to build the game for macOS and Windows as well.
How does it work?
Games made with the Corona SDK are primarily made of Lua Scripts. Each script would generally equate to a single scene or level within the game. Since this game only has a single scene, there is only one script. The rest of the files in the project are made up of images, icons, backgrounds, and sprites.
main.lua
-----------------------------------------------------------------------------------------
-- Fly Game 2
-- Ryan Bains-Jordan
--
-- Main
-----------------------------------------------------------------------------------------
-- Status Bar
display.setStatusBar( display.HiddenStatusBar )
-- Variable Declarations
local w = display.contentWidth
local h = display.contentHeight
local bg = {}
local plane = {}
local cloud = {}
local cloudSheetWInst
local cloudSheetDInst
local cloudSheetRInst
local touched = false -- Has the screen been touched (Used in screenTouched())
local hits = 0 -- Counts the clouds intercepted by plane (Used in updateScore())
local hitsText
local lives = {}
local splash = {}
local rButton = nil
local rButtonText = ""
-----------------------------------------------------------------------------------------
-- Game Initiation Function
-----------------------------------------------------------------------------------------
function initGame()
-- Background
bg = display.newImageRect( "background.png", w * 4, h )
bg.starting = 660
bg.ending = -250
bg.x = bg.starting
bg.y = h / 2
-- Plane
plane = display.newImageRect( "plane.png", 77, 43 )
plane.x = 75
plane.y = h-100
plane.velocity = 0
plane.acceleration = 0.5 / 2
plane.bounce = 0.5
plane.sound = audio.loadSound( "plane.wav" )
plane.skid = audio.loadSound("skid.wav")
plane.lives = 3
-- Lives
lives.life1 = display.newImage( "plane.png", 50, 20 )
lives.life2 = display.newImage( "plane.png", 100, 20 )
lives.life3 = display.newImage( "plane.png", 150, 20 )
lives.life1:scale( .2, .2)
lives.life2:scale( .2, .2)
lives.life3:scale( .2, .2)
lives.score = {lives.life1, lives.life2, lives.life3}
-- Text Color
local color =
{
hightlight = { r=0.6, g=0.4, b=0.2 },
shadow = { r=0.3, g=0.3, b=0.3 }
}
-- Hit Score
hitsText = display.newEmbossedText( "", w/2, 100, native.systemFont, 25 )
hitsText:setFillColor( 1, .804, 0 )
hitsText:setEmbossColor( color )
-- White Clouds
for i = 1, 3 do
cloud[i] = display.newImageRect("cloud.png", 75, 50)
cloud[i].x = -100 + (i * 200)
cloud[i].y = 100
end
-- Dark Clouds
cloud[4] = display.newImageRect("dark_cloud.png", 75, 50)
cloud[4].x = -100
-- Rainbow Clouds
cloud[5] = display.newImageRect( "rain_cloud.png", 75, 50 )
cloud[5].x = -100
-- Cloud Initiations
cloud.white = { animation=false }
cloud.dark = { visable=false, aniamation=false }
cloud.rain = { visable=false, animation=false }
cloud.sound = audio.loadSound( "poof.wav" )
-- Cloud Animation
cloudSheet = graphics.newImageSheet( "cloud_sheet.png", { width=128, height=128, numFrames=48 } )
cloudSheetWInst = display.newSprite( cloudSheet, { start=1, count=16, time=500, loopCount=1 } )
cloudSheetDInst = display.newSprite( cloudSheet, { start=17, count=16, time=500, loopCount=1 } )
cloudSheetRInst = display.newSprite( cloudSheet, { start=33, count=16, time=500, loopCount=1 } )
cloudSheetWInst.x = -100
cloudSheetWInst.y = -100
cloudSheetDInst.x = -100
cloudSheetDInst.y = -100
cloudSheetRInst.x = -100
cloudSheetRInst.y = -100
-- Game Over Screen
splash.screen = display.newRoundedRect( w/2, h/2, w-100, h-100, 25 )
splash.screen:setFillColor( 0.5, 0.5, 0.5, 0.9 )
splash.screen.isVisible = false
splash.header = display.newEmbossedText( "Game Over", w/2, h/2-100, native.systemFont, 30 )
splash.header:setFillColor( 1, 0.8, 0 )
splash.header.isVisible = false
splash.score = display.newEmbossedText( "Your score was", w/2, h/2-50, native.systemFont, 20 )
splash.score:setFillColor( 1, 0.8, 0 )
splash.score.isVisible = false
splash.hits = display.newEmbossedText( "", w/2, h/2, native.systemFont, 25 )
splash.hits:setFillColor( 1, 0.8, 0 )
splash.hits.isVisible = false
-- Reset Button
rButton = display.newRoundedRect( w/2, h/2+100, 100, 30, 10 )
rButton.strokeWidth = 3
rButton:setFillColor( 1, 0.8, 0 )
rButton:setStrokeColor( 0.6, 0.4, 0.2 )
rButton.isVisible = false
rButtonText = display.newEmbossedText( "Reset", rButton.x, rButton.y, native.systemFont, 15 )
rButtonText:setFillColor( 0.6, 0.4, 0.2 )
rButtonText.isVisible = false
-- Reset the Score Function
function rButton:tap( event )
plane.y = h-100
plane.lives = 3
hits = 0
updateScore()
hitsText.isVisible = true
displayLives()
splash.screen.isVisible = false
splash.header.isVisible = false
splash.score.isVisible = false
splash.hits.isVisible = false
rButton.isVisible = false
rButtonText.isVisible = false
Runtime:addEventListener( "enterFrame", newFrame )
Runtime:addEventListener( "touch", screenTouched )
end
-- Install the animation event listeners
Runtime:addEventListener( "enterFrame", newFrame )
Runtime:addEventListener( "touch", screenTouched )
rButton:addEventListener( "tap", rButton )
end
-----------------------------------------------------------------------------------------
-- Main Functions
-----------------------------------------------------------------------------------------
-- Animate Background
function bgAnimate()
bg.x = bg.x - 5
if bg.x <= bg.ending then
bg.x = bg.starting
end
end
-- Randomise height of clouds
function randomHeight( i )
local rnd = math.random( 50, 250 )
cloud[i].y = rnd
end
-- Calculate Velocity and Acceleration of Fall
function falling()
-- Move the plane according to its current velocity
plane.y = plane.y + plane.velocity
-- If the plane passed the bottom during this frame, make it bounce
if (plane.y > h - 100 ) then
if ( plane.velocity > 3 ) then
audio.play( plane.skid, { channel=6, loops=0 } )
end
plane.y = plane.y - plane.velocity -- Undo the downward movement that went past the bottom
plane.velocity = - plane.velocity * plane.bounce -- Reverse the downward speed and apply bounce factor
end
-- Change the current velocity over time by applying the acceleration (gravity)
plane.velocity = plane.velocity + plane.acceleration
end
-- Calculate Velocity of Climb
function flying()
plane.y = plane.y - 5
plane.velocity = 0
plane.acceleration = 0.5 / 2
end
-- Plane moving event
function screenTouched( event )
if event.phase == "began" or event.phase == "moved" then
touched = true
else
touched = false
end
if event.phase == "began" then
audio.play( plane.sound , { channel=5, loops=-1 })
end
if event.phase == "ended" then
audio.stop( 5 )
end
end
-- Check Collision
function checkCollision()
local collision = false
plane.ftx = plane.x + 38 -- Plane Front Top X Position
plane.fty = plane.y - 21 -- Plane Front Top Y Position
plane.fbx = plane.x + 38 -- Plane Front Bottom X Position
plane.fby = plane.y + 21 -- Plane Front Bottom Y Position
for i = 1, table.getn(cloud) do
cloud.ftx = cloud[i].x - 37 -- Cloud Front Top X Position
cloud.fty = cloud[i].y - 25 -- Cloud Front Top Y Position
cloud.fbx = cloud[i].x - 37 -- Cloud Front Bottom X Position
cloud.fby = cloud[i].y + 25 -- Cloud Front Bottom Y Position
if plane.ftx > cloud.ftx - 5 and plane.ftx < cloud.fbx + 5 then
if plane.fby > cloud.fty and plane.fby < cloud.fby then -- If bottom front of plane hits cloud
collision = true
elseif plane.fty > cloud.fty and plane.fty < cloud.fby then -- If top front of plane hits cloud
collision = true
else
collision = false
end
if collision == true then
if i ~= 4 then
hits = hits + 1
if i == 5 and plane.lives < 3 then
plane.lives = plane.lives + 1
displayLives()
end
else
if plane.lives > 0 then
plane.lives = plane.lives - 1
if plane.lives == 0 then
endGame()
end
displayLives()
end
end
animateCloud(i)
cloud[i].x = math.random( 400, 800 )
randomHeight(i)
audio.play( cloud.sound )
updateScore()
collision = false
end
end
end
end
--Animate the Cloud
function animateCloud(i)
-- Dark Cloud
if i == 4 then
cloud.dark.animation = true
cloudSheetDInst.x = cloud[i].x
cloudSheetDInst.y = cloud[i].y
cloudSheetDInst:play()
-- Rain Cloud
elseif i == 5 then
cloud.rain.animation = true
cloudSheetRInst.x = cloud[i].x
cloudSheetRInst.y = cloud[i].y
cloudSheetRInst:play()
--White Cloud
else
cloud.white.animation = true
cloudSheetWInst.x = cloud[i].x
cloudSheetWInst.y = cloud[i].y
cloudSheetWInst:play()
end
end
-- Update the Score
function updateScore()
hitsText:setText(hits)
splash.hits:setText(hits)
end
-- Dispaly the Planes Lives
function displayLives()
for i = 1, 3 do
if i <= plane.lives then
lives.score[i].isVisible = true
else
lives.score[i].isVisible = false
end
end
end
-- Game Over Screen
function endGame()
splash.screen.isVisible = true
splash.header.isVisible = true
splash.score.isVisible = true
splash.hits.isVisible = true
hitsText.isVisible = false
timer.performWithDelay( 1000, buttonVisability ) --Delay Buttons Visability
Runtime:removeEventListener( "enterFrame", newFrame )
Runtime:removeEventListener( "touch", screenTouched )
audio.stop( 5 )
touched = false
end
-- Button Visability
function buttonVisability()
rButton.isVisible = true
rButtonText.isVisible = true
end
-----------------------------------------------------------------------------------------
-- Animation
-----------------------------------------------------------------------------------------
function newFrame()
bgAnimate()
if touched == false then
falling()
end
if touched == true then
flying()
end
-- Draw White Clouds
for i = 1, 3 do
cloud[i].x = cloud[i].x - 3
if cloud[i].x <= w - 380 then
cloud[i].x = w + 380
randomHeight(i)
end
end
-- Draw Dark Clouds
if cloud.dark.visable == false then
local dc = math.random( 200 ) -- Larger = More Rare
if dc == 50 then -- Any number
cloud.dark.visable = true
randomHeight(4)
end
end
-- Move the Dark Cloud if it Exists
if cloud.dark.visable == true then
cloud[4].x = cloud[4].x - 2
if cloud[4].x <= w - 380 then
cloud[4].x = w + 380
cloud.dark.visable = false
end
end
-- Draw Rainbow Clouds
if cloud.rain.visable == false then
local rc = math.random( 800 ) -- Larger = More Rare
if rc == 50 then -- Any number
cloud.rain.visable = true
randomHeight(5)
end
end
-- Move the Rainbow Cloud if it Exists
if cloud.rain.visable == true then
cloud[5].x = cloud[5].x - 5
if cloud[5].x <= w - 380 then
cloud[5].x = w + 380
cloud.rain.visable = false
end
end
-- Move White Cloud Animation
if cloud.white.animation == true then
cloudSheetWInst.x = cloudSheetWInst.x - 3
if cloudSheetWInst.x <= -380 then
cloud.white.animation = false
end
end
-- Move Dark Cloud Animation
if cloud.dark.animation == true then
cloudSheetDInst.x = cloudSheetDInst.x - 2
if cloudSheetDInst.x <= -380 then
cloud.dark.animation = false
end
end
-- Move Rainbow Cloud Animation
if cloud.rain.animation == true then
cloudSheetRInst.x = cloudSheetRInst.x - 3
if cloudSheetRInst.x <= -380 then
cloud.rain.animation = false
end
end
checkCollision()
end
-----------------------------------------------------------------------------------------
-- Game Initiation
-----------------------------------------------------------------------------------------
initGame()