PART EIGHT
PLANTING
SEEDS
Adding Seeds
Create a new package called item
Inside this package, add the following classes:
Item
Seed (extends Item)
CropSeed (extends Seed)
CornSeed (extendsCropSeed) and PotatoSeed (extends CropSeed)
Abstract Classes
All of these classes except for CornSeed and PotatoSeed should be abstract. You'll find it's a common pattern that all of your classes that aren't at the "bottom" of a hierarchy are abstract.
Item and Subclasses
Since we're farther into this project, these instructions are going to start being a little higher level and vague on purpose. Good luck, young coder.
You'll need to create an image variable in Item and set the image in the appropriate subclasses
ITEMBAR
ItemBar Class
The ItemBar class is going to represent a list of all of the items your farmer has (currently just seeds).
It should contain an ArrayList of class Item. Start it with a few corn and potato seeds.
In Game, declare and initialize an ItemBar.
PROJECT ORGANIZATION
Composition "has-a"
Game
World
Entity (ArrayList)
Cell (2D Array)
Terrain
ItemBar
Inheritance "is-a"
Terrain
Dirt
Grass
Water
Entity
Plant
Crop
Corn
Potato
Item
Seed
CropSeed
CornSeed
PotatoSeed
Rendering
In class Item, let's add a render method. It needs two parameters: a graphics object and an index. Based on the index, space your drawing a certain amount to the right.
Draw each image at a size of 64 x 64
image.draw(x, y, 64, 64);Hint: Adding will indent by an amount, while multiplying by index will scale the distance between items.
Make sure you also display a number equal to index + 1 above each item for indices 0 to 8.
This will later be used as a hotkey.
In class ItemBar, write a render() method which calls render on each Item with the appropriate index.
In class Game, make sure to render() the itembar.
You'll want something that looks like this. Experiment to find the right spacing and placement.
CHECKPOINT
Run your code and see...
Your program should be displaying an itembar at the bottom of the screen
SELECTION FRAMEWORK
Selection
In class ItemBar
Create an integer called selectedIndex, and start it at -1. We'll use the code -1 to mean "no item selected."
Create accessor method hasSelectedItem(). Return false if selectedIndex is out of bounds.
Create accessor method getSelectedItem(). Return null if the there is no selected Item, using the method you just wrote.
Write a method called clearSelection() that sets selectedIndex to -1.
In class Item
Modify the render() method to take selectedIndex as an additional parameter. If the index equals selectedIndex, have it draw a white box around itself.
CHECKPOINT
Run your code and see...
Hardcode in a few different selectedIndex values and test if it highlights items.
Hotkeys
In class ItemBar, write a keyPressed() method and have it called by Game's keyPress method.
Manage keypress events for 1-9. Note that is a clever way to do this using math if you observe the values of KEY_ONE to KEY_NINE. Remember that we’re off by one.
Warning - If you are being clever and using the key's ID value and some math, you'll want to be careful here to *only* process keys that correspond to an appropriate index. We don't want to translate space bar into an index position.
If you select a new key, change the selection to that key
If you select the same key, clear the selection
If you select an invalid key, clear the selection
CHECKPOINT
Run your code and see...
Pressing different keys should allow you to change which key is currently selected, as well as unselecting any item by choosing it twice.
CHANGING THE CURSOR
Game Container
In a moment, we'll be adding coding code to change the cursor based on the item that is selected. To do so, we'll need access to the GameContainer in a few different parts of our program.
By default, Slick 2D limits which methods access to this variable. Since Game is a singleton, we'll make a public static reference to it that we can use in other parts of our program.
In the Game class, declare and assign a public static variable for gc.
SetCursor
In class ItemBar, write a method:
public void setCursor()
If it does not have a selected item, set the default cursor
Otherwise, set the cursor to the image of the selected item and scale it to 32 by 32.
This needs to be in a try catch to handle the Exception.
Since this code is a bit clunky, I've provided it on this page as a reference.
CHECKPOINT
Run your code and see...
When you have selected an item, it now appears as the cursor! Shiny!
PLANTING CROPS
Making Crops
In the CropSeed class, create an abstract method called makeCrop()
In the CornSeed class, implement this by returning a new Corn() object. Repeat this process for the PotatoSeed class.
Adding Parameters
Look through World, Cell, and Terrain. Each method that deals with "mousePressed" or "clicked" needs to take an Item as a parameter. As usual, we'll have World call Cell which calls Terrain.
In your Game class, call the World's mousePressed method with getSelectedItem() as a parameter.
In the World class, make cells, entities, inBounds(), and addEntity() static.
We're only okay with using static here because World is a singleton.
We're going to allow objects to directly add Entities to World, and do not want to have to pass the World everywhere.
This code is in Game, which will start everything rolling by passing the appropriate item to the world's click method.
Planting In Dirt
We're finally there . Write code in Dirt's click method to bring it together.
First, check if three conditions are met.
Is there soil?
Does the cell have an entity?
Is the item a cropSeed?
If so...
Store the Crop created by that Seed
Note, you'll need to cast the Item to a CropSeed
Add the new crop to the world at the cell's location
Finally, make sure the other functionality of dirt only happen if you aren't planting a crop.
CHECKPOINT
Run your code and see...
You can plant crops now!
Seeds aren't expended when used.
CONSUMING SEEDS
Expiration
Add an expired value to Item. Follow the same process you did in Part Seven to remove expired entities, but with items this time.
Rather than having World manage it, we'll put our cleanup() method in ItemBar. Just make sure it's being called by the Game class.
If the item you remove is the selected index:
Set selectedIndex to -1
Call setCursor()
As always, makes sure you don't skip items in your removal code.
Add a public method called expire() which sets expired to true
In the Dirt class, mark the passed item as expired when creating a crop.
CHECKPOINT
Run your code and see...
Seeds are removed from your inventory when clicked