You will continue to add functionality to your existing project from the previous task. There is no new repository to clone.
In addition to setting static sprites, the provided graphics engine also has capabilities to display animations. As with static graphics, understanding exactly how the graphics engine works is not necessary, and we will provide any information you need.
Every GameObject (and thus, any child class of GameObject) has an instance variable called animations
,
which is a HashMap mapping String to ArrayList of SpriteLocation. The String represents the name of the animation
(e.g. "default"), and the ArrayList represents the series of locations in the spritesheet that will be cycled through
while the object is animating (see task 3 handout for refresher on SpriteLocations). Along with storing various
unrelated sprites in a spritesheet, common practice for games of this sort is to store every frame of an object's
animations in the same spritesheet.
Thus, you can add new animations to a GameObject by calling put
on this HashMap with a name for
the animation and an ArrayList of SpriteLocations representing each frame of animation.
When a GameObject is created, it'll have the default animation state of "default", so if you have an animation
named "default" in your animations HashMap, that animation will automatically play when the object is created.
If you have multiple animations, you can call setAnimationState
on the object and pass in the name
of the animation you wish to play at that moment. You can call freezeAnimations
on an object to
stop the object from animating until setAnimationState
is called again.
From here, everything else is handled completely automatically. The engine will progress each frame once per every the interval stated in Configuration.java.
As with setting sprites in general, if an animation is recommended we will specify the inputs you should use. Animations will also not be tested.
In this task, you will implement the following specs.
In the app.games.topdownobjects
package, add the following methods to the Projectile class:
getDamage
: this method should take no parameters and return an int. It should return the value of the damage instance variable.setDamage
: this method should take in an int and return void. It should set the value of the damage instance variable to the parameter.In the app.games.topdownobjects
package, create a class named PlayerMagicProjectile
that extends
Projectile
. This class should have a constructor that takes in a Vector2D representing location.
In the app.games.topdownobjects
package, create a class named PlayerAxeProjectile
that
extends Projectile
. This class should also have a constructor that takes in a Vector2D representing location.
In the app.gameengine.model.gameobjects
package, create an abstract class named CollectibleGameObject
that
extends DynamicGameObject
.
getItemID
that returns
the ID of the item that was passed in the constructor.
use
that takes in a Level and returns void.
In the app.gameengine.model.gameobjects
package, make the following additions to the
DynamicGameObject class to implement a functioning inventory system:
addInventoryItem
that takes in a CollectibleGameObject
and returns
void. This method should add the object from the parameter to the DynamicGameObject
's inventory.
removeActiveItem
that takes no parameters and returns void. This method should
remove whatever the currently active item is from the DynamicGameObject
's inventory.
getActiveItem
that takes no parameters and returns a CollectibleGameObject.
This method should return whichever CollectibleGameObject in the inventory is active.
getActiveItemID
that takes in no parameters and returns a String.
cycleInventory
that takes no parameters and returns void. This method will
cycle through the inventory, changing the item currently marked as active.
The Player class already contains a cycleInventory
method that does nothing. With the cycleInventory
method implemented in DynamicGameObject, you can now remove the method in Player to use the inherited one instead.
If you do not, whenever you have a Player object, this method will be called instead, and your code will fail our
tests
Return to the CollectableGameObject
class and add the following behavior:
collideWithDynamicObject
method to add the current CollectableGameObject to the
DynamicGameObject's inventory by calling addInventoryItem
. It should then destroy itself. It
should only do these two things if the DynamicGameObject is the player (i.e. isPlayer
returns true).
Now, you will write a method to fire projectiles from a DynamicGameObject. In the DynamicGameObject
class, write a method called fireProjectile
that returns void and takes in (in this order) a Projectile, a double
representing speed, and a Level.
getDynamicObjects
.
Level
class.
Now that the functionality for firing projectiles is in the DynamicGameObject class, you will replace the
action button functionality in the Level
class to be based off of the Player's active item.
actionButtonPressed
method in Level to call the use
method on the Level's Player's currently
active object.
getPlayer
method
At this point, the engine's collectable functionality is built up enough that you can now add new, interactable
collectables to the game. You may wish to edit the getUI
method in the Game class to show the
currently active item using the getActiveItemID
method, otherwise there will be no way to tell
which item is equipped.
In the app.games.topdownobjects
package, create a class called MagicPickup that extends
CollectibleGameObject.
use
method from CollectibleGameObject. This method should access
the Player from the Level parameter and call the fireProjectile
method
on said Player.
In the app.games.topdownobjects
package, create a class called AxePickup that extends
CollectibleGameObject.
use
method from CollectibleGameObject. This method should access
the Player from the Level parameter and call the fireProjectile
method
on said Player.
In the app.games.topdownobjects
package, create a class called PotionPickup that extends
CollectibleGameObject.
use
method.
removeActiveItem
on the player.
There is no testing utility for this task.
In the app.tests
package, create a class called TestTask5
and test the following:
DynamicGameObject
addInventoryItem
and cycleInventory
:
cycleInventory
will go through every added
CollectableGameObject and wrap around to the beginning
removeActiveItem
:
removeActiveItem
properly removes the active item from
the inventory and sets the new active item.
Implement all the classes/methods described in the Specification section. As you're implementing inventory, you should run your tests to see how you are progressing. It's recommended that you write your tests first, submit to Autolab to make sure you have good testing, then use those verified tests, along with the debugger, to check your code.
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.