Notes: 03. Build the Model
The parameters of the Creature constructor should be var to prevent the “Cannot find setter for field error.”
I have the starter project for the course open up here in Android Studio 3.1.4.
The starter project has three packages: app, model, and view.
The starter code is there to give us a head start on building out the Creaturemon app using MVVM. The app package has an Application subclass for the app, and a file with extension functions for some Kotlin classes.
The view package has Activity, Adapter, and other classes that make up the app UI. We’ll talk about the View classes in a later video.
In this video, we’ll build out the classes in the model package. The starter project includes some code for persisting to a Room database, which we’ll also do in a later video.
There are some classes that we’ll use for creature attributes, and some empty classes that we’ll start filling out in this video.
I’ll build and run the starter app now to get a sense of what we want the app to look like. The first screen will later be used to show the list of creatures that we’ve created. There’s a menu option we’ll use later use to clear all creatures.
Hitting the floating action button, we see the Add Creature screen, which is where we’ll work for most of the course. You see we can tap near the top of the screen to choose an avatar for the creature.
We can assign a name to the creature, as well as intelligence, strength, and endurance attributes. There’s a spot at the bottom to show the creature HitPoints value, based on the chosen attributes. And there’s a button we’ll use to save the new creature.
We’re going to build up the model classes we need for our Creature data. The main class is Creature, which has a set of CreatureAttributes and some other properties for each creature.
Back in Android Studio now, open up the CreatureAttributes file.
This is a simple data class with an Int value for each of the three Creature attributes. Next, open the Creature file to see the empty Creature class in the starter project.
Let’s convert this model class to a data class, and add properties for the Creature attributes, hitPoints, name,
and also an Int for the avatar drawable value.
data class Creature(
val attributes: CreatureAttributes = CreatureAttributes(),
val hitPoints: Int = 0,
val name: String,
val drawable: Int = 0
)
We’re also going to need a class in our Model to generate a creature based on the values input by the user on the Add Creature screen.
In particular, we need to calculate the hitpoints value for a creature based on this formula. Hitpoints is equal to 5 times the intelligence attribute, plus 3 times the strength attribute, plus 4 times the endurance attribute. The Creaturemon game favors intelligence over all else.
For the CreatureGenerator, we’ll use Test-Driven Development or TDD and write our test first for the class.
If you’ve not done TDD before, just know that TDD is a test-first approach we’re you peform a Red-Green-Refactor cycle.
Red means you first write a failing test, and then write the code that makes the test Green by passing. You follow up with refactoring to make the code you’ve added as clean as possible.
In the test package, create a new package named model. Now add a new Kotlin file to the package named CreatureGeneratorTest.
class CreatureGeneratorTest {
}
Create the test class and add a CreatureGenerator property to it.
CreatureGenerator does not exist yet, so we’ll see some compiler errors.
private lateinit var creatureGenerator: CreatureGenerator
We’ll initialize creatureGenerator in a setup() method tagged with the @Before JUnit annotation:
@Before
fun setup() {
creatureGenerator = CreatureGenerator()
}
Let’s now go into the model package in the app and create the CreatureGenerator class to clear the compiler error.
class CreatureGenerator
Back in the test class, add the test for the hit point calculation. We first arrange the expectedCreature from the generator.
@Test
fun testGenerateHitPoints() {
val attributes = CreatureAttributes(
intelligence = 7,
strength = 3,
endurance = 10
)
val name = "Rikachu"
val expectedCreature = Creature(attributes, 84, name)
}
We use an intelligence value of 7, strength of 3, and endurance of 10.
The resulting hitPoints from the hitPoint formula are 84, so we can create an expectedCreature that we give a name of Rikachu, a raywenderlich version of Pikachu. We can now perform the action we’re testing on the generator, and assert that the result is equal to expectedCreature.
assertEquals(expectedCreature, creatureGenerator.generateCreature(attributes, name))
In the CreatureGenerator class, create a shell of the generateCreature() method so that we can run the failing test.
class CreatureGenerator {
fun generateCreature(attributes: CreatureAttributes, name: String = "", drawable: Int = 0): Creature {
return Creature()
}
}
The creature constructor has default values for it’s properties. We can run the test class now and see the expected failure, since we’ve not added the hitPoints calculation yet. Now, we can add the hitPoints calculation to CreatureGenerator and return the generated Creature.
val hitPoints = 5 * attributes.intelligence +
3 * attributes.strength +
4 * attributes.endurance
return Creature(attributes, hitPoints, name, drawable)
Finally, we can run our CreatureGenerator test again, and see a green passing test. With our Creature model class setup, in the next video, we’ll start building out the repository
in which we’ll save the Creature data.