Final project for codebar festival 2022 workshop.
Art assets from Freepik:
- Ground and icicle created by macrovector - www.freepik.com
- Bird created by freepik - www.freepik.com
Font from Google fonts:
Step-by-step:
- Open project
- Drag
bird_down
sprite from Assets > Sprites to the FlappyScene hierarchy - Rename the object to Bird
- Bring in the ground similarly, drag the position so that it's at the bottom
- Modify camera to solid color instead of skybox
- Set up sorting layers for sprites: obstacles, ground, bird & add sprites there, add bird & ground to correct layers
- Add colliders to sprites: PolygonCollider2D for the bird, BoxCollider2D for the ground + adjust if necessary with edit mode
- Add RigidBody2D to the bird game object
- Create Bird script in the Scripts folder and add it to the Bird game object
- Open script in VSCode by double clicking
- Create
isDead
boolen variable and use that in theUpdate()
method to check if the game is over or not - Create
rb
Rigidbody2D variable and get theRigidBody2D
component to that in Start - Create a serialized float for
upForce
- In Update, with
Input.GetMouseButton(0)
check if the player has pressed the mouse button and
- set
rb.velocity
to zero to reset the velocity - use
rb.AddForce
to add the force to the y coordinate
- Get back to Unity, set
upForce
in the Inspector to 300, test if flapping works - Add Unity built-in
OnCollisionEnter2D
method toBird.cs
to check for collision with ground, and setisDead
to true
- Right-click in the hierarchy and create a Text game object from UI > Text – Text Mesh Pro
- Import the TMP Essentials when suggested
- Change the Canvas UI Scale Mode to Scale With Screen Size and use 1920 x 1080 as the reference resolution
- The EventSystem game object won't be needed as we're not going to interact with UI, so delete that
- Rename then the Text (TMP) game object to Score, set the text of it to Score: 0 and change the font to the one included in the project (Fredoka One)
- Set the font size to a larger one, set the wrapping to disabled and align the text in the middle center
- Set the anchor point on the Canvas (hold down Alt key in the anchor view), and lift the text up a bit so that's in a nice position at the bottom
- Duplicate the Score game object with Ctrl+D (Cmd+D on macOS) and rename the duplicated one to GameOver, set the text to Game Over and the color to black
- Anchor it to the top and adjust the y position to a nice position at the top
- Duplicate the score text once more, rename it to FlapToRestart and set it as a child game object to the GameOver one
- Set the text to "Flap to restart!", reset the y position and adjust it nicely below the game over text, and also decrease the font size a bit
- Hide the GameOver GameObject from the checkbox in the Inspector
- Create an empty GameObject by right-clicking in the hierarchy and selecting Create Empty, and name it GameController
- Create GameController script in the Scripts folder and add it to the GameController game object
- Create a method that handles the situation when the bird has died, birdDied in the GameController
- Create a serialized GameObject for
gameOverText
- Set the
gameOverText
to active in the birdDied method - Create another serialized variable of type Bird for the bird script
- Then make the Bird script's
isDead
variable a publicly gettable one (change toIsDead
) - Start checking the bird's status in the game controller's Update method and call the birdDied method when the bird dies
- Make a check that only calls the SetActive if the game object is not active already
- Set the references to the script in Unity
- Add a condition to game controller's Update method to check for player input when the bird is dead
- Add needed using statement for
UnityEngine.SceneManagement
to be able to reload the scene - Add the scene reloading functionality to Update with
SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex);
- Create ScrollingObject script in the Scripts folder and add it to the Ground game object
- Add a RigidBody2D component to the Ground game object and set the type to Kinematic so that it's not affected by gravity and will only be moved from script
- Create
rb
Rigidbody2D variable and get theRigidBody2D
component to that in Start - Create a serialized float for
scrollSpeed
(talk about the setting the initial value and set it in the Inspector to -5) - Set the
rb.velocity
to the scroll speed in the x direction - Create a
stopScrolling
method for the scrolling object script - Create
bird
Bird variable and get theBird
script to that in Start viaGameObject.Find
- Call the
stopScrolling
method once the bird is dead - Create an empty game object in the hierarchy called Scenery, move the Ground underneath and duplicate the Ground two times (make sure that Scenery is at (0, 0, 0))
- Move the first duplicate to the right by the amount indicator by the collider, and the second two times that
- Create RepeatingBackground script in the Scripts folder and add it to the Ground game object
- Create
boxCollider
BoxCollider2D variable and get theBoxCollider2D
component to that in Start - Create
length
float variable and get the collider's length in x direction to that in Start - Create
repositionBackground
method and make the ground move to the left with an offset oflength * 3
- Check the position in Update and if in the x direction it's less than
-length
, then call the reposition method - Add the script to all ground game objects in the hierarchy
- Drag
icicle
sprite from Assets > Sprites to the FlappyScene hierarchy - Rename the object to Icicle, scale and position it to the top part
- Setup a PolygonCollider2D for the Icicle game object
- Duplicate the Icicle game object, change the scale in y to negative and position nicely
- Create an empty game object and call it Icicles, and move the two Icicles to its children
- Add a BoxCollider2D to the Icicles game object and position it in the center of the two icicles, and set its Is Trigger on
- Add a Rigidbody2D component to the Icicles game object and make it Kinematic
- Create Icicles script in the Scripts folder and add it to the Icicles game object
- Use
OnTriggerEnter2D
to detect collision between the scoring area and the bird - Add a public method
SetScoreCallback
that takes in an Action calledscoreCallback
and stores that in a variable calledscoreCallback
in the Icicles class - Add
using System;
to top for usingAction
- Call the
scoreCallback
when the bird scores - Add the ScrollingObject script to the Icicles game object
- Create a Prefabs folder in the Project and then drag the Icicles game object there to create a prefab
- Delete the prefab from the scene
- Add a method called
birdScored
to the game controller script and add there also a score variable that tracks the score - Add
using TMPro;
at the top and then create a serialized variable called scoreText of type TMP_Text and drag the score text object to that in the Inspector - Update the scoreText from the
birdScored
method
- Create IciclePool script in the Scripts folder and add it to the GameController game object
- Create a serialized GameObject for
icilesPrefab
- Create a serialized int for
poolSize
- Set the variables in the Inspector
- Create an array of GameObjects in the IciclePool script to store the icicles and initialize it in Start with the
poolSize
- Add a variable
poolPosition
at (-50, -50) - Instantiate the icicle game objects to the array in Start with a loop
- Add variables for
spawnRate
(can be serialized),timeSinceLastSpawned
and a public variableActive
- Update
timeSinceLastSpawned
in the Update method withTime.deltaTime
- Create
icicleIdx
int variable to store the column index - Create
spawnPositionX
to control where the new columns are spawned - If
timeSinceLastSpawned
is larger than the spawn rate, set it to zero, create random y position for the next column and set the position of the current column to that - Lastly increase the
icicleIdx
and if it's larger than or equal topoolSize
, set it back to zero - Add a public method
SetScoreCallback
that takes in an Action calledscoreCallback
and stores that in a variable calledscoreCallback
in the IciclePool class and addusing System;
to the top - Call the
SetScoreCallback
for each Icicle created in the Start by getting the Icicles component of theicicles[i]
game object - Create an IciclePool variable for
iciclePool
in the game controller script get that in Start, and call itsSetScoreCallback
in Start to set the score callback tobirdScored
- Set the
iciclePool.Active
to false when the bird dies to stop the pool from recycling the icicles - Set the Script Execution Order in Edit > Project Settings so that GameController is executed before IciclePool to ensure that the callback is set correctly
- Create an Animations Folder in Assets
- Open Animation Window in Unity, select Bird game object and hit the Create button, name the animation Idle and save to Animations
- Add property, expand Sprite Renderer category, add Sprite with the + add the bottom, and expand the sprite in the view
- Delete second keyframe
- Select the sprite by dragging over it, hit Ctrl+C (Cmd+C on macOS) to copy, select the Idle dropdown menu and select Create New Clip...
- Save the new clip as Flap, hit Ctrl+V (Cmd+V on macOS) to paste
- Hit the record button and then drag the
bird_up
sprite from the Project view to the Bird game object's Sprite Renderer - Open the Animator window, set up conditions for the animations:
- open the Parameters list on the list, create a Trigger parameter called Flap
- right-click on Idle, then Make Transition and drag it to Flap
- edit the transition by clicking on the arrow, remove Has Exit Time checkbox tick
- add the Flap trigger to the Conditions in the Inspector
- make a transition from Flap to Idle with Has Exit Time checked
- Set the triggers from code:
- create
anim
Animator variable and get theAnimator
component to that in Start - use
anim.SetTrigger
to change to the Flap state of the animator when the mouse button is pressed