You will continue to add functionality to your existing project from the previous task. There is no new repository to clone.
Video link: https://youtu.be/GSQh2a7hF30
Another video for Task 3! Yippee!
As before, watching this video is optional, and all of the information you need for this task is contained within this page. However, you may find it helpful for getting a better understanding of the task, and what is expected of you
Rather than completing functionality of the game engine as was the focus of the previous tasks, this task will mainly be focused on building new features. In order to do so, we'll need to tell the game engine what sprites to load for the new objects. While you don't need to understand how the game engine does this, we will briefly explain how to assign new sprites.
Everything in game that can have a sprite (e.g. GameObjects, DynamicGameObjects) has instance variables
called
spriteSheetFilename
and defaultSpriteLocation
. In most
2D games, rather than storing each individual sprite as its own file, we store groups of sprites together in
a single file called a spritesheet, then tell the engine which sprite on the sheet to load.
spriteSheetFilename
is a String that represents the filename containing the spritesheet
with the desired sprite in it. defaultSpriteLocation
takes in a SpriteLocation
object.
For the sake of this task, all you need to know about the SpriteLocation
class is that it has
a constructor taking in the row and column of the desired sprite in the spritesheet (feel free to look
through
the data directory to understand what these files look like).
So, to add a sprite to an object, we just need to set values to these instance variables in the constructor. For example, this is how the Wall class sets the sprites:
this.spriteSheetFilename = "Ground/Cliff.png";
this.defaultSpriteLocation = new SpriteLocation(3, 0);
Any time anything you add needs a sprite, the handout will specify what the filename and location should be to load a good sprite for the object. We will not test which sprites you use, so if you wish you may use different sprites. All of the suggested sprites already exist in the project, but the sprite sheet linked below has some additional sprites that you may wish to use; if you choose to, you should save this image into the data directory of your project, by right clicking and pressing "Save Image as..."
You may also want to visit the link in the "data/sprites.txt" file to find the source of all sprites used in this project and download any sprites that interest you.
In this task, you will implement the following specs. Once all of these are complete, you will have created a platformer game using the same game engine we built for the top-down game. In this new game, your character will be able to jump around a level with a side-view while avoiding spikes.
While implementing the functionality in this task, you will use much of the existing inheritance structure of the project. You should take some time to look through the code and explore all the inheritance usage to give more context for the new classes/methods you'll create.
Potion
(app.games.commonobjects.Potion)
commonobjects
package, create a new class called Potion that
extends DynamicGameObject.
spriteSheetFilename
to "User
Interface/Icons-Essentials.png"
defaultSpriteLocation
should be a
SpriteLocation at column 0, row 1
(see the "Using the Graphics Engine" section of the handout)
defaultSpriteLocation
should
be a SpriteLocation at column 1, row 1.
This turns the potion into a poison
spriteSheetFilename
and
defaultSpriteLocation
are protected variables meaning you can access them using this.
even though they are not defined in this class
collideWithDynamicObject
method. If the object being collided with
is a Player, you should add the amount to heal (from the constructor) to the Player's HP, then
call
this.destroy()
to remove the Potion from the level. If the other object is not a
Player, this method does nothing
isPlayer
method on it.
SampleTopDownGame
class and add a new Potion object to the Level's
DynamicGameObject ArrayList
(follow the process the given code uses to add an Enemy to the level, but with a Potion
constructor instead.)
The remainder of this task will be implementing a new physics engine. While the physics engine you wrote in task 1 was designed for top-down levels where you freely move around a 2D space, this new physics engine will be designed for 2D platformer levels where your movement is constrained to moving left, right, and jumping.
DynamicGameObject
- Platformer Preparation (app.gameengine.model.gameobjects.DynamicGameObject
)
false
isOnGround
that takes no parameters and returns a boolean. Add
a
method called setOnGround
that takes in a boolean and returns void. These should be
the getter and setter for the previously described instance variable
PhysicsEngineWithGravity
(app.gameengine.model.physics.PhysicsEngineWithGravity
)
PlatformerWall
(app.games.platformerobjects.PlatformerWall
)
app.games.platformerobjects
package and add a class named
PlatformerWall
in it
that extends Wall
PlatformerWall
. These should be passed into the super constructor.
collideWithDynamicObject
method to have the following behavior:
super.collideWithDynamicObject
Spike
(app.games.platformerobjects.Spike
)
collideWithDynamicObject
method to have the following behavior:
destroy
method on it.
Otherwise, do nothing
PlatformerLevel
(app.games.platformerobjects.PlatformerLevel
)
app.gameengine.Level
, but with PlatformerWalls rather than Walls.
gameControls
with a new
PlatformerMovement object.
jumpButtonPressed
method
from the Level class. This will be called whenever your character jumps (press up or w) in a
PlatformerLevel
Finally, you will create a new Game subclass that will be used to play Levels using these new features. You're welcome to create your own Levels, but we will also be providing Levels via the course Piazza.
Game
(app.gameengine.Game
)
init
. This method
should do nothing and only exists to be inherited and overridden
init
methodPlatformerGame
(app.games.PlatformerGame
)
To actually play your game, update the switch statement in GameFactory
(in the
app.games
package) to have a case for "platformer game". In this case, it should assign game
to a new PlatformerGame object, then break. You can then replace the game String in
Configuration
in the app
package with "platformer game". After that, running StartGame will load up your new
game.
Note: You can see feedback in Autolab for your tests without completing the programming portion of this task, but you must at least create every class/method from this specification. You can "stub out" these methods by having them always return a fixed value, but they must exist so the grading code, and your tests, can compile and run.
There is no testing utility for this task.
Create a class named TestTask3
in the tests
package.
You will write tests for the following functionality from the specification:
PlatformerWall
collideWithDynamicObject
. You do not need to test that the position
is being updated correctly (as you know the base Wall class is already functional). You
only need to test that the velocity and isOnGround is getting set correctly.
Implement all the functionality from the specification.
The feedback in Autolab will be given in 3 phases. If you don't complete a phase, then feedback for the following phase(s) will not be provided.
Once you complete all 3 phases, you will have completed this Task and Autolab will confirm this with a score of 1.0 for complete.