Schedule
| Exercise | Deadline |
|---|---|
| Exercise 0: An Unskippable Tutorial | Tuesday, September 8 |
| Exercise 1, Increment 1: 2D Physics-Based Gameplay | Tuesday, September 15 |
| Exercise 1, Increment 2: Game Logic, Graphics, and Sound | Tuesday, September 22 |
| Exercise 1, Increment 3: Titles and Animation | Tuesday, September 29 |
General Instructions
Submission and Deadlines
All repositories must be in our course organization on GitHub.
Unless otherwise specified, deadlines are at the start of class on the indicated date. This way, each student has the same amount of time to complete their work. Projects must be submitted by the deadline in order to be eligible for course credit.
Evaluation Criteria and Save Points
Each exercise specifies the criteria on which it will be evaluated. To earn a particular grade in an exercise, one must meet that grade’s criteria as well as all previous criteria. For example, to earn a B, one has to complete the criteria for levels B, C, and D.
Each student is given two Save Points to use during the semester on individual work. If you miss the original deadline for a project, you may spend a Save Point to turn it in up to 48 hours after the original deadline. Alternatively, if my feedback indicates an error in your self-assessment---that is, something you thought you had correct was actually incorrect---you may spend a Save Point to address the deficiency within 48 hours of the original feedback. Release this new version as a bugfix, incrementing the patch number and explaining the change in the commit history.
Self-Evaluation and the README.md file
Your project’s README.md file must include a self-evaluation
under its own heading.
The self-evaluation documents which evaluation criteria you have satisfied
and states what grade you have earned.
Exercise 0: An Unskippable Tutorial
Objectives
This project will introduce you to Godot Engine as well as the norms of the class.
1. Preliminaries
Complete the account registration form that linked from Canvas. This will get you access to the class’ private GitHub organization, which is required to complete later steps of this project.
Install Microsoft Visual Studio Code (VSCode). We will be using VSCode as a robust Markdown editor. If you already know Markdown and have a preferred editor for it, use that. If not, use VSCode.
Make sure you can run git from the command line.
Windows users will use Git Bash, which is part of
the git installation for Windows.
Set up your identity following the setup instructions.
Configure git to use VSCode as your editor.
2. Tutorial
Work through the “Your first 2D game tutorial” using GDScript.
3. Version Control
You should have previous experience with distributed version control from the prerequisite courses. This semester’s work builds upon that experience with more professional techniques.
Set up a git repository for your project. For example, you can use the command
line to navigate to your project folder and then issue the command git init.
When you make a new project,
Godot Engine will create appropriate .gitignore and .gitattributes files
that tell git what files to ignore and how to deal with different
kinds of files, respectively.
Take a look at the .gitignore file, opening it in a plain text editor
such as VSCode.
You should see that .gitignore is ignoring a folder called
.godot, and that this folder contains all manner of gobbledygook.
Godot Engine
uses that folder to hold its generated content&mdashl;the files it needs to edit and
build your project. Since it is generated content, it should not be tracked in
version control. Three cheers for Godot Engine’s helpful default git
configuration files!
If you are using macOS, you need to edit your .gitignore to
ignores the .DS_Store files created by your operating system.
Once you are done, your .gitignore will look like this:
# Godot 4+ specific ignores
.godot/
# macOS ignores
.DS_Store
Use git status at any time to see what is currently being tracked by git.
You will see me use this comment a lot to make sure my mental model matches
the computer’s state.
From the project directory, you can add all the non-ignored files with the following command. That is, this tells git to stage these files for commit.
git add -A
This would be a good time to do git status and compare the previous results to these.
You should now be ready to commit.
Tell git to commit all of the staged flags (the -a flag) and also that you
will give the commit message on the command line (the -m flag,
which is combined with the previous into the string -am).
Notice that this commit message follows the style guide.
git commit -am "Complete the tutorial"
Once again, git status is informative here.
This is also a good time to try git log. If you want to get fancy,
try this expanded version of the command:
git log --abbrev --decorate --online --graph
With your local repository ready, it’s time to make a remote one.
Create a repository in our course organization on GitHub,
naming it E0-myname, where myname is your BSU username or your surname. This
naming scheme identifies the repository as being yours and corresponding to Exercise 0.
Make sure it is an empty, private repository.
When you create the repository,
follow the instructions GitHub shows to set your remote origin and push
your changes to GitHub.
One of the steps renames the default branch from master
to main, and this step is optional.
Reload your page on GitHub, and you should now see that your remote repository is an exact copy of your local one.
Confirm that you have handled these steps properly by cloning your remote repository to a new location on your workstation. Do this by clicking the “Code” button on GitHub to get the HTTPS URL to your repository. It should look something like https://github.com/bsu-cs315/E0-myname. From your terminal, go to any convenient location in your filesystem and clone the repository using the git clone command, like this:
git clone https://github.com/bsu-cs315/E0-myname
This will make an exact copy of what is on GitHub. You can open this project using Godot Engine and verify that everything is working properly.
4. The README.md File
Use VSCode to create a README.md file at the root of your project.
Complete your self-evaluation in this file following the general instructions above.
The README.md file is in Markdown,
which is a plain text format.
VSCode has built-in support for Markdown editing.
A useful feature is that you can bring up an HTML render preview
using Ctrl-K, V (that is, hit Control and k together,
release both, then tap v).
This can help you ensure that your Markdown is well-formed.
Here are the most important Markdown features you need to know to get started.
- Headings are given with
#characters; the more of them, the deeper the heading level. - Blank lines, not line breaks, separate paragraphs.
- Hyperlinks are given as
[link text](url).
When you’re done, keeping in mind the self-evaluation requirements,
your README.md file will look something like this:
# Project 0: An Unskippable Tutorial
A tutorial implementation by (Your Name Here).
This project follows the
[Your First Game tutorial from
godotengine.org](https://docs.godotengine.org/en/stable/getting_started/first_2d_game/index.html).
## Self-Evaluation
I have completed all of the criteria and have therefore earned an A.
## Third-Party Assets
- "art/House In a Forest Loop.ogg" Copyright © 2012
[HorrorPen](https://opengameart.org/users/horrorpen), [CC-BY 3.0:
Attribution](http://creativecommons.org/licenses/by/3.0/). Source:
https://opengameart.org/content/loop-house-in-a-forest
- Images are from "Abstract Platformer". Created in 2016 by kenney.nl,
[CC0 1.0 Universal](http://creativecommons.org/publicdomain/zero/1.0/). Source:
https://www.kenney.nl/assets/abstract-platformer
- Font is "Xolonium". Copyright © 2011-2016 Severin Meyer
<sev.ch@web.de>, with Reserved Font Name Xolonium, SIL open font license
version 1.1. Details are in `fonts/LICENSE.txt`.
Once you have created the README.md file, remember to use git status
to see that it is not yet tracked by git.
Follow the steps above to add this file to git, commit your changes,
and push the latest changes to GitHub.
Make sure you follow the style guide requirements
for your commit message as we did above.
Evaluation
- D-1: Your repository is in the course organization.
- C-1: The repository contains your solution to the tutorial.
- C-2:
Your repository contains a top-level
README.mdfile that includes a self-evaluation.
- A-1:
The licenses of third-party assets are correctly included in the
README.mdfile.
Exercise 1, Increment 1: 2D Physics-Based Gameplay
Overview
This is the first of a multi-part project in which you will build a 2D physics-based action game along the lines of Angry Birds. This first part focuses on core physics-based gameplay. Future parts will build upon this to improve the player experience.
You have creative freedom to choose a theme for your game. In my sample solution, I have been inspired by Kenney’s Physics Assets pack.
Iteration 1 features
The first iteration is all about getting the core gameplay working. In the previous project, you controlled the location sprites manually using GDScript. In this project, you will use the 2D physics system built in to Godot Engine. By the end of the first iteration, you will have a projectile that the player can launch across the screen at a target. You will be able to play this tech demo on the Web. That’s essentially it for the first iteration: the other niceties can wait for the next iteration.
Angry Birds uses a cleverly-designed touch interaction to launch birds from a slingshot. It is sufficient for us—and a lot simpler—to use keyboard controls. If you were pursuing this as a final project, you might aim a bit higher, but keyboard input is perfectly appropriate for now.
For this first iteration, you do not need any images at all: you could
just have every visual node draw itself by overriding the _draw function.
That said, in some ways, it is easier to bring in images as you did in
the previous project than it is to make self-drawing sprites.
Either approach is fine for the first iteration.
I recommend that you try to get as far as you can using the official documentation and your experience in the previous project. This will help you think about the extents of your current understanding. I have a video from Fall 2020 that shows the first few steps of the project, but again, I would treat that as a safety net rather than a tutorial. (Also, the video uses an older version of Godot Engine.) Keep in mind that there are always more than one way to approach game programming problems.
Style
From this exercise until the end of the semester, you are accountable for following the standards articulated in our style guide. It behooves you to review that page, ask about anything that is unclear, and use peer review to help catch errors.
Helpful Links
- Physics introduction at GodotEngine.org
- Kenney.nl has a wealth of high-quality public domain assets
Suggestions
The projectile should be a RigidBody2D since it will be controlled by the
physics system. It will have a child which is a CollisionShape2D. If you are
using sprite images, then it will also have a child which is a Sprite2D.
Use apply_impulse
to give a one-time boost of force (“impulse”) to the projectile.
An easy way to make the ground is with a StaticBody2D.
An alternative is to use a TileMap,
although this requires many more steps. If you go this way, make sure you have
collision boxes set up correctly.
In order to get notification of a physics collision, you need to set the
contact_monitor property and non-zero contacts_reported property of a
RigidBody2D, as explained in the Godot Engine physics introduction.
Only then will the body_entered signal be emitted.
I find that some of the most useful mathematical functions in game development
are clamp
lerp
and remap.
If you find yourself writing some ugly mathematical transformations, see if perhaps one of these three methods expresses your need more cleanly.
Evaluation
- D-1:
The repository has a
README.mdfile that contains a self-evaluation.
- C-1: The project follows our style guide.
- C-2: The player can fire the projectile.
- C-3: The player can control the angle at which the projectile is fired.
- C-4: There is a “ground” that stops the projectile.
- C-5:
Controls are documented either in the
README.mdor in the game. - C-6: The projectile's flight is affected by gravity using Godot's physics system.
- B-1: The player can adjust their firing angle smoothly between 0° (straight forward) and 180° (straight up).
- B-2: There is a non-ground target that the projectile can hit.
- A-1: The player can modify the strength of the projectile's firing.
- A-2: When the target is hit, there is some kind of feedback—even just a print statement for now.
Exercise 1, Increment 2: Game Logic, Graphics, and Sound
Overview
This builds on last week’s exercise. Now that you have the core gameplay in place, it’s time to add some features to make it more playable. You will limit the number of projectiles that the player can fire, and you will incorporate appropriate graphics and sound effects.
Graphics
If you didn’t already do so, it’s time to add images in all the appropriate places. This minimally includes the projectile, the target, the background, and the ground.
Never underestimate the power of good audio to improve the player experience. At a minimum, we want to have some kind of sound when the player launches the projectile. You can make your own sound effects, and there are plenty of places on the Web where you can find public domain and attribution-licensed assets. Personally, I am fond of freesound, which makes it easy to filter by license. For homemade sounds, I like the old-school sounds generated through the sfxr plugin in to LMMS. There’s an online sfxr port called jsfxr. Chiptone is more modern, but I have not used it myself.
The AudioStreamPlayer node provides an easy way to play sound effects. You can
specify the audio asset to play in the Inspector and then call play when you
want it to play. Sound effects should be .wav files. If you want to incorporate
music, those audio files should be Ogg Vorbis files (.ogg), and you will probably want
to set them to looping in the import settings. (This happened by default in
older version of Godot Engine.)
Limited ammunition
One of the goals for this iteration is to ensure the player is only launching
one projectile at a time. A problem you may run into here is determining when a
projectile stops rolling after hitting the ground. Depending on your
implementation, one approach is to listen for the RigidBody’s
sleeping_state_changed signal. A physics body “sleeps” when no forces are acting
on it. This saves the engine the trouble of processing that object each frame.
You listen for the sleeping_state_changed signal to determine when a physics
body has gone to sleep and use this in your game logic.
What happens if your projectile falls off the end of your world? If it falls
forever, it will never change its sleeping state. A common solution to this
problem is to set a “kill” line: if any object falls below that line, it is
destroyed. This can be done by checking the Y coordinate of the projectile in
the _physics_process method. Another approach is to add something like an
Area2D to the level that can watch for overlapping projectiles and handle them
appropriately, but this can be error-prone if a projectile overshoots your area.
To successfully complete this iteration, you need to be able to spawn multiple projectiles, one at a time, in succession. Defining the projectile in its own scene is an important step here. Remember: a Godot Engine scene is like a class in object-oriented languages. Once you have a scene (class) defined, you can make as many instances (objects) as you need. Of course, if you create projectiles programmatically, you will also need to connect their signals programmatically; you can read more about this in the signals documentation.
You might consider a flow of logic like the following.
-
Specify a spawn point as a
Marker2D. At the start of the game, the main level’s script instantiatesprojectile.tscnand places it at the spawn point. -
When the projectile is fired, the main level script listens for its
sleeping_state_changedsignal or fortree_exitedif it is killed by passing the kill line. -
When either signal is received, as long as there are projectiles remaining in the inventory, instantiate a new one at the spawn point and decrement the inventory.
Keep in mind that there are two ways to listen for signals. One is to use the Node dock within the editor, and the other is via scripting. Read more about this in the signals documentation.
HUD
The Heads-Up Display (HUD) is a trope of video game design through which the internal state of the game is exposed to the player. You have already done some work with Godot’s UI system in the first exercise. I encourage you to read about sizes and anchors and containers so that you understand the fundamentals of Godot’s UI system.
For this project, your HUD does not have to be fancy: simple, static labels are
sufficient. The main idea for now is to move anything that the player needs to
know away from print statements and into the HUD. Your HUD should show how many
projectiles the player has remaining. You might also use it to show a score,
firing angle, or firing power.
Evaluation
- D-1:
The repository has a
README.mdfile that contains a self-evaluation.
- C-1: The project follows our style guide.
- C-2: The game uses imported graphics for the projectile and launcher.
- C-3:
The game plays a sound (
.wav) when the projectile is launched.
- B-1: Earn one star.
- A-1: Earn three stars.
- ⭐ The player has a limited number of projectiles, and they are fired one at a time.
- ⭐ The background and ground use imported graphics.
- ⭐ The HUD shows how many projectiles are remaining.
Exercise 1, Increment 3: Titles and Animation
Overview
In this final iteration, you will pull all the pieces together to make something that feels like a finished game. We are also going to step up the quality of our implementations to match the richness of our understanding.
Title Screen
A common novice mistake is to create a game in the same order that a player experiences it. For example, one start by making a title screen or main menu because that’s what the player sees first. If you look back on the steps of this project, you will notice that we did not do it that way: instead, we created features in the order of increasing value. This is an important perspective that is informed by the spirit of Agile software development.
Now it is time to add some of those conventional niceties. To wit, it is time to add a title screen that establishes the name of the game, which in turn sets up the expectations for the player. I recommend keeping your title screen in a separate scene from the rest of the game. This gives it isolation from other scenes, breaking potential dependencies that could cause headaches later. A straightforward way to approach this is to create a new scene and drop the logo for your game in as a Sprite. Give a prompt to the user about what button to press to start the game, write a script that listens for that, and then replace the title scene with the game scene.
Animated Logo
There are two common ways to create animations within Godot Engine:
using the AnimationPlayer node
or by tweening.
If your animation depends on the dynamic state of the game, then the latter
is the best approach.
Evaluation
- D-1:
The repository has a
README.mdfile that contains a self-evaluation.
- C-1: The project follows our style guide.
- C-2: The game starts on the title screen, and a player's action moves the player to the gameplay screen.
- C-3: The player has an achievable goal, and the game ends.
- B-1: Earn one star.
- A-1: Earn two stars.
- ⭐ When the game is over, allow the player to go back to the title screen, from which the game can be played again.
-
⭐ Use
AnimationPlayeror tweening to add some pop to the player experience.