GitHub Repository link: https://github.com/CSE-116/CSE116-GameEngine
Once you have the project opened in IntelliJ, you'll see a src folder which contains another folder called main, which contains another folder called java. Inside this folder is the Java package app which contains all the code for the project. The starter code contains many Java classes needed for the engine to run.
Don't panic about the number of files. For now, you can safely ignore most of them. If you ever have trouble finding a specific file, you can press shift twice to open a convenient search window that'll direct you to the desired class.
For this task, you will be writing code in the following classes:
DynamicGameObject
, located in the package app.gameengine.model.gameobjects
Wall
, located in the package app.games.commonobjects
PhysicsEngine
, located in the package app.gameengine.model.physics
TestTask1
, located in the package app.tests
You will also need to use the provided Vector2D
and Hitbox
classes from the app.gameengine.model.physics
package for this task. These classes will not be modified, though you should read them to understand how
they work.
To submit your project, create a zip file containing your entire project and submit it to Autolab. (Click file -> export -> Project to Zip File, though there may be slight differences to this across OSes and versions). If this option is not available, you may need to install the "Android" plugin through the settings menu
Throughout this semester, you will be building a game engine along with a game that will utilize this engine. All 6 tasks (excluding task 0) will build on this project and add more features to the engine and game. After cloning the repo, you should run "StartGame". When you do, a new window should open showing a 2d pixel-art top-down view game.
As you can see, it's basically a marvel of modern graphics. You probably thought this was photograph of cosplayers at a medieval festival, but it's actually in game graphics from this project.
When you run the game, you'll notice that you can't actually do anything. That's because major components of the game engine are missing. Your job is to complete it. In this task, you will add player movement, collision detection, a few smaller features to the game.
The coordinate system use for computer graphics might be different than you used to. We'll use the standard coordinate system that is typically used in video games.
The origin of the system is at the top-left of the screen/window/level with positive x going right and positive y going down. This image shows the same information as the one above, but with the coordinate system labeling all the tiles in the game. You can see that "G" (The goal) is at location (6, 2).
Objects (and hit boxes) in our game have two components: location and dimensions, both represented as 2-dimensional vectors (x, y). All objects/hit boxes will be rectangles and their location is the location of their upper-left corner. Their dimensions are the length and width of the rectangle. For example, the goal has a location of (6, 2) since that's the location of its upper-left corner, and it has dimensions (1, 1) since it's exactly 1 tile in size.
Locations and dimensions do not have to be whole numbers. In the image below, the player character is at [roughly] location (1.5, 1.0) with dimensions (1.0, 1.0).
Note: All methods are public and non-static, unless otherwise noted, from this point forward in the course. It is recommended you follow the spec in the order it is written in.
PhysicsEngine
- updateObject
PhysicsEngine
class, complete the method called updateObject
that takes
in a DynamicGameObject
and a
double representing the change in time. This method
should update the location vector of the DynamicGameObject
based on the value of
its velocity vector.
Vector2D
objects and the DynamicGameObject
contains getter methods for both of them. Note that you never have to set the vector objects themselves, and should
instead set the x and y components of the existing vectors using the provided setters. This will
modify x and y of the Vector2D
objects and that change will be made on the heap (If
you don't understand what this means, it may help to do a memory trace on your code for this method to better
understand what is happening in the stack and heap).
DynamicGameObject
class
DynamicGameObject
constructor to initialize instance variables for the following:
Vector2D
representing the orientation the object is facing. This should
be initialized to x = 0.0, y = 1.0.
super(location)
. This must be the first line of the method and all code you
add should go below it. More details on this when we cover inheritance in lecture.
getHP
setHP
setHP
is called, add some logic that will prevent HP from exceeding the Max HP.
If the parameter exceeds the Max HP, HP should be set to the Max HP.
getMaxHP
getOrientation
takeDamage
that takes in an int and returns void. This
method should
subtract the current HP instance variable by the amount specified in the parameter.
PhysicsEngine
- detectCollision
detectCollision
method that takes in two Hitboxes and returns a
boolean. The boolean
should return true if the two Hitboxes are colliding (ie. overlapping) and false otherwise. Two
hitboxes are overlapping if any portion of the boxes overlap
Vector2D
objects. To visualize when 2 hitboxes collide, it's
recommended
that you sketch out hitboxes and their location/dimension vectors and write test cases
for a variety of situations before diving deep into the code
Wall
class
collideWithDynamicObject
that takes in a [reference to a]
DynamicGameObject
and returns void. This method should modify the state of the
DynamicGameObject
such that it cannot pass through the wall. This method will be
called by your physics engine whenever the player collides with a wall and prevent them from
clipping out of bounds
TestTask1
which can use to be sure
that you're implementing the method according this spec without having to submit to
Autolab
For this task, and all future tasks, you will be required to write test cases for some of the functionality.
You will also often be asked to write a testing utility method to assist you with writing thorough and
clean tests.
This utility should be written in the TestTask1
class in the tests package. (Note: Do not add
the @Test annotation to any testing utility methods since they
are not tests)
comparePlayers
- Write a method named comparePlayers
in the tests.TestTask1 class that:
comparePlayers
method even though it itself is not a test method
(ie. This method can call compareEquals on each pair of values that are expected to be the
same).
Note: You still have to create every class and method from the specification before getting feedback on your submission in Autolab since the grader will not be able to compile if those classes/methods do not exist. You don't have to implement them yet, and they can all return a default value
Write JUnit tests for the following methods from the specification in the TestTask1 class. These tests should be annotated with @Test:
DynamicGameObject
DynamicGameObject
setHP
getHP
returns the expected value
takeDamage
getHP
returns the expected value
PhysicsEngine
updateObject
detectCollision
Wall
collideWithDynamicObject
method. Tests are provided for
you
in the TestTask1
class, which you may use to help you write the method itself
Implement all the methods from the specification.
The feedback in Autolab will be given in 4 phases. If you don't complete a phase, then feedback for the following phase(s) will not be given.
Once you complete all 4 phases, you will have completed this Task and Autolab will confirm this with a score of 1.0 for complete.