Properties that control the spread
Later on, I will explain the properties that control the spread of the disease. Some sets of property
values produce results similar to those shown above where the disease gains a foothold, spreads
for awhile killing many sprites, and then recedes without killing the entire population.
Other sets of property values end up with all of the sprites having died.
Still other sets of property values end up with the disease being unable to gain a foothold and
spread beyond just a few individual sprites.
What you have learned
You have learned how to use a basic Slick2D game engine to create simulations involving
thousands of sprites, collision detection, and sound.
What you will learn
In this module, you will learn how to use what you have previously learned to write a relatively
complex (but somewhat simplified) simulation of a real-world pandemic.
If you were to study the characteristic of pandemics, you could probably upgrade this program to
produce a better model of a pandemic. For example, an interesting student project would be to
allow healthy sprites to reproduce when they come in contact based on a random probability
function. This would allow the population to be growing at the same time that it is dying off due
to the disease. Of course, it may then be necessary to deal with the effects of a population
explosion.
13.4. General background information
This program simulates the spread of a fatal communicable disease within a population.
A single infected sprite is introduced into a population of sprites. The disease is spread by
physical contact between a healthy sprite and an infected sprite.
You can watch as the disease either spreads and kills the entire population or spreads for awhile,
then recedes and dies out.
Infected sprites are colored red. Healthy sprites are colored green. A sound is emitted (simply to
demonstrate how to emit sounds) each time there is contact between an infected sprite and a
healthy sprite.
The final outcome
The final outcome is determined both by chance and by several factors including:
The life expectancy of an infected sprite.
The probability of infection due to contact with an infected sprite.
The degree of mobility of both infected and healthy sprites.
The population density of sprites.
The actual values for the first three factors for each individual are determined by a maximum
value multiplied by a random number between 0 and 1.0.
Experimentation
Instance variables are provided for all four of these factors. You can modify the values and
recompile the program to experiment with different combinations of the factors.
A good exercise for a student would be to create a GUI that allows the factors to be entered more
easily without having to recompile the program for purposes of experimentation.
13.5. Discussion and sample code
The class named Sprite01
The class named Sprite01 is shown in Listing 9 . There is nothing new in Listing 9 that I haven't explained in earlier modules.
The class named Slick0220
Will explain in fragments
A complete listing of the class named Slick0220 is provided in Listing 8 . I will break the code down and explain it in fragments.
Beginning of the class named Slick0220.
The beginning of the class named Slick0220 , down through the main method is shown in Listing
public class Slick0220 extends BasicGame{
//The values of the following variables can be changed
// to effect the spread of the disease.
//Set the life expectancy of an infected sprite
// in frames.
int infectedSpriteLife = 96;
//Set the maximum fraction of exposed sprites that will
// become infected.
float probabilityOfInfection = 0.5f;
//Set the maximum step size that a sprite will move in
// one frame.
float maxStepSize = 1;
//Set the initial number of sprites in the population.
int numberSprites = 1000;
//References to Sprite01 objects are stored here.
ArrayList <Sprite01> sprites =
new ArrayList<Sprite01>();
//These variables are populated with references to Image
// objects later.
Image redBallImage;
Image greenBallImage;
//This variable is populated with a reference to a Sound
// object later.
Sound blaster;
//These variables are populated with information about
// the background image later.
Image background = null;
float backgroundWidth;
float backgroundHeight;
//This object is used to produce random values for a
// variety of purposes.
Random random = new Random();
//This is the frame rate we would like to see and
// the maximum frame rate we will allow.
int targetFPS = 24;
//----------------------------------------------------//
public Slick0220(){//constructor
//Set the title
super("Slick0220, baldwin");
}//end constructor
//----------------------------------------------------//
public static void main(String[] args)
throws SlickException{
AppGameContainer app = new AppGameContainer(
new Slick0220(),500,500,false);
app.start();
}//end main
Figure 13.4. Listing 1. Beginning of the class named Slick0220.
Listing 1. Beginning of the class named Slick0220.
There is nothing new in Listing 1 , so there should be no need for an explanation beyond the embedded comments.
The init method
The init method begins in Listing 2 .
public void init(GameContainer gc)
throws SlickException {
//Create Image objects that will be used to visually
// represent the sprites.
redBallImage = new Image("redball.png");
greenBallImage = new Image("greenball.png");
//Create a Sound object.
blaster = new Sound("blaster.wav");
//Create a background image and save information
// about it.
background = new Image("background01.jpg");
backgroundWidth = background.getWidth();
backgroundHeight = background.getHeight();
//Add a red sprite as the first element in the
// ArrayList object. This sprite carries the disease
// into the population.
//Put it in the center of the game window. Make the
// direction of motion random. Make the speed of
// motion (step size)random. Make the size random.
// Specify a white (do nothing)color filter.
sprites.add(new Sprite01(
redBallImage,//image
backgroundWidth/2.0f,//initial position
backgroundHeight/2.0f,//initial position
(random.nextFloat() > 0.5) ? 1f : -1f,//direction
(random.nextFloat() > 0.5) ? 1f : -1f,//direction
0.1f+random.nextFloat()*2.0f,//step size
0.1f+random.nextFloat()*2.0f,//step size
0.5f+random.nextFloat()*0.5f,//scale
new Color(1.0f,1.0f,1.0f)));//color filter
//This is an infected object. Set its life
// expectancy.
sprites.get(0).setLife(
(int)(random.nextFloat()*infectedSpriteLife));
Figure 13.5. Listing 2. Beginning of the init method.
Listing 2. Beginning of the init method.
Sick but not yet dead
The only new code in Listing 2 is the call to the setLife method at the end. In the previous
module , the life property of a sprite was always either 0 or 1. A sprite with a life property value of 0 was dead. A sprite with a life property value of 1 was alive.
This program is more nuanced and uses values other than 0 and 1 for the infected red sprites. A
value of 0 still means that a sprite is dead. Any other positive value means that the sprite is sick
and dying but not yet dead.
The value assigned to the life property for this sprite is a random value between 0 and
infectedSpriteLife . This is one of the property values that has an impact on the extent to which
the disease spreads through the population. The longer an infected sprite lives after becoming
infected, the more healthy sprites it will infect and the more aggressive will be the disease.
You can modify this value (see Listing 1 ) and recompile the program to experiment with different values.
Remainder of the init method
The remainder of the init method is shown in Listing 3 .
//Populate the ArrayList object with green sprites.
// Make the initial position random. Make the initial
// direction of motion random. Make the speed
// (step size) random. Make the size (scale) random.
// Make the color filter white (do nothing).
for(int cnt = 0;cnt < numberSprites;cnt++){
sprites.add(new Sprite01(
greenBallImage,//image
backgroundWidth*random.nextFloat(),//position
backgroundHeight*random.nextFloat(),//position
(random.nextFloat() > 0.5) ? 1f : -1f,//direction
(random.nextFloat() > 0.5) ? 1f : -1f,//direction
random.nextFloat()*maxStepSize,//step size
random.nextFloat()*maxStepSize,//step size
1.0f,//scale
new Color(1.0f,1.0f,1.0f)));//color filter
}//end for loop
gc.setTargetFrameRate(targetFPS);//set frame rate
}//end init
Figure 13.6. Listing 3. Remainder of the init method.
Listing 3. Remainder of the init method.
A population of healthy sprites
Listing 3 uses a for loop to add numberSprites (see Listing 1 ) healthy sprites to the population.
This is another property that has an impact on the spread of the disease. Everything else being
equal, the more sparse the population, the more difficult it is for the disease to get a foothold in
the first place and the more difficult it is for the disease to spread if it does get a foothold.
The frame rate
Listing 3 also sets the frame rate to the value of targetFPS (see Listing 1 ) . Note that I slowed this program down to the standard movie frame rate of 24 fps (as opposed to the typical 60 fps)
mainly because I wanted to run the simulation more slowly. In other words, I wanted it to be
possible to see the disease spread through the population. Also, it is a fairly demanding program
so it may not run at 60 fps on some machines.
End of the init method
Listing 3 also signals the end of the init method.
The update method
The update method begins in Listing 4 . This is the method where most of the added complexity in this program resides.
public void update(GameContainer gc, int delta)
throws SlickException{
//Move all the sprites to their new positions.
for(int cnt = 0;cnt < sprites.size();cnt++){
//Get a reference to the current Sprite01 object.
Sprite01 thisSprite = sprites.get(cnt);
//Ask the sprite to move according to its
// properties
thisSprite.move();
//Ask the sprite to bounce off the edge if necessary
thisSprite.edgeBounce(
backgroundWidth,backgroundHeight);
}//end for loop
Figure 13.7. Listing 4. Beginning of the update method.
Listing 4. Beginning of the update method.
Nothing new in this code fragment
The is nothing new in the code fragment shown in Listing 4 . The new code begins in Listing 5 .
An overview of the code
Before getting down into the details of the code, I will give you a descriptive overview.
In the outer-most layer, the program uses a for loop to examine every sprite in the population
looking for red or infected sprites.
When it finds an infected sprite, it decreases the value of its life expectancy. Then it uses an inner
for loop to test that sprite against every sprite in the population looking for collisions.
Ignore collision with an infected red sprite
If the infected sprite collides with another infected sprite, it ignores the collision and keeps
searching the population, looking for collisions with healthy sprites.
Collision with a healthy green sprite
If the infected sprite collides with a healthy (green) sprite, it causes that sprite to become exposed
to the disease and plays a sound effect. (As you will see later, sprites that are exposed to the
disease don't always contract the disease.)
The state of the population
When the infected sprite has been tested for a collision with every healthy sprite, four kinds of
sprites exist in the population:
1. Healthy sprites that have not been exposed to the disease.
2. Healthy sprites that have been exposed to the disease.
3. Infected sprites that still have some remaining life.
4. Infected sprites whose life property is less than or equal to zero, meaning that they are dead.
A cleanup pass
An Iterator is used to make a cleanup pass through the population.
Exposed sprites are either converted to infected sprites or cleared of the exposure on the basis of a
random value that has a maximum value of probabilityOfInfection (see Listing 1 ) .
Dead sprites are removed from the population.
The code to accomplish all of this begins with the for loop in Listing 5 .
//Search for and process collisions between
// infected (red) sprites and healthy (green)
// sprites. Declare the green sprite to be exposed to
// the disease when a collision occurs.
for(int ctr = 0;ctr < sprites.size();ctr++){
//Get a reference to the Sprite01 object.
Sprite01 testSprite = sprites.get(ctr);
if(testSprite.getImage().equals(redBallImage)){
//This is an infected sprite. Reduce its life.
testSprite.setLife(testSprite.getLife() - 1);
// Do the following for every sprite in the
// ArrayList object.
for(int cnt = 0;cnt < sprites.size();cnt++){
//Get a reference to the Sprite01 object.
Sprite01 thisSprite = sprites.get(cnt);
//Test for a collision between this sprite and
// the infected test sprite.
boolean collision =
thisSprite.isCollision(testSprite);
//Process a collision if it has occurred.
// Exclude collisions between the testSprite
// and itself and with other infected sprites.
if((collision == true)&&(!thisSprite.getImage().
equals(redBallImage))){
//A collision has occurred, set exposed to true
thisSprite.setExposed(true);
//Play a sound to indicate that a collision
// has occurred.
blaster.play();
}//end if
}//end for loop
}//end if on redBallImage
Figure 13.8. Listing 5. Process collisions.
Listing 5. Process collisions.
You should have no difficulty matching up the code in Listing 5 with the verbal description given above.
Make a cleanup pass
The code in Listing 6 uses an Iterator to make the cleanup pass described above.
//Make a cleanup pass through the ArrayList object
Iterator <Sprite01> iterB = sprites.iterator();
while(iterB.hasNext()){
Sprite01 theSprite = iterB.next();
//Cause a percentage of the exposed objects to
// contract the disease. Clear the others.
if((theSprite.getExposed() == true) &&
(random.nextFloat() < probabilityOfInfection)){
theSprite.setImage(redBallImage);
theSprite.setLife((int)(
random.nextFloat()*infectedSpriteLife));
theSprite.setExposed(false);
}else{
//Eliminate the effects of the exposure
theSprite.setExposed(false);
}//end else
//Remove dead sprites
if(theSprite.getLife() <= 0){
iterB.remove();
}//end if
}//end while loop
}//end outer for loop
}//end update
Figure 13.9. Listing 6. Make a cleanup pass.
Listing 6. Make a cleanup pass.
Once again, you should have no difficulty matching up the code in Listing 6 with the verbal description given above.
The render method
The render method is shown in Listing 7 . There is nothing new in Listing 7 .
public void render(GameContainer gc, Graphics g)
throws SlickException{
//set the drawing mode to honor transparent pixels
g.setDrawMode(g.MODE_NORMAL);
//Draw the background to erase the previous picture.
background.draw(0,0);
//Draw every sprite in the ArrayList object.
for(int cnt = 0;cnt < sprites.size();cnt++){
sprites.get(cnt).draw();
}//end for loop
//Display the number of sprites remaining.
g.drawString(
"Sprites remaining: " + (sprites.size()),100f,10f);
}//end render
}//end class Slick0220
Figure 13.10. Listing 7. The render method.
Listing 7. The render method.
13.6. Run the program
I encourage you to copy the code from Listing 8 and Listing 9 . Compile the code and execute it, making changes, and observing the results of your changes. Make certain that you can explain why
your changes behave as they do.
13.7. Summary
In this module, you learned how to write a program that simulates the spread of a fatal
communicable disease within a population.
13.8. Conclusion
Although I may come back and add more modules later, for now, this will be the final module in
this collection.
The objective of the collection was to explain the anatomy of a game engine. I believe I have
accomplished that objective and have also provided sample programs to illustrate the use of the
game engine.
It is worth pointing out that BasicGame is not the only game engine architecture available with
Slick2D. The Slick2D user Manual refers to BasicGame as a game container and indicates that several others are available including:
Applet Game Container
ApplicationGDXContainer/AndroidGDXContainer
The documentation also describes a class named StateBasedGame , which provides a different
anatomy than BasicGame . Bucky Roberts provides a series of video tutorials on state based
games using Slick2D at http://www.youtube.com/watch?v=AXNDBQfCd08
13.9. Miscellaneous
This section contains a variety of miscellaneous information.
Housekeeping material
Module name: Slick0220: Simulating a pandemic
File: Slick0220.htm
Published: 02/07/13
Disclaimers:
Financial : Although the Connexions site makes it possible for you to download a PDF file for
this module at no charge, and also makes it possible for you to purchase a pre-printed version
of the PDF file, you should be aware that some of the HTML elements in this module may not
translate well into PDF.
I also want you to know that, I receive no financial compensation from the Connexions
website even if you purchase the PDF version of the module.
In the past, unknown individuals have copied my modules from cnx.org, converted them to
Kindle books, and placed them for sale on Amazon.com showing me as the author. I neither
receive compensation for those sales nor do I know who does receive compensation. If you
purchase such a book, please be aware that it is a copy of a module that is freely available on
cnx.org and that it was made and published without my prior knowledge.
Affiliation : I am a professor of Computer Information Technology at Austin Community
College in Austin, TX.
13.10. Complete program listing
Complete listings of the code discussed in this module are provided in Listing 8 and Listing 9 .
/*Slick0220.java
Copyright 2013, R.G.Baldwin
This program simulates the propagation of a fatal
communicable disease within a population.
A single infected sprite is introduced into a large
population of sprites. The disease is spread by physical
contact with an infected sprite.
You can watch as the disease either spreads and kills the
entire population or spreads for awhile, then recedes and
dies out. Infected sprites are colored red. Healthy
sprites are colored green. A sound is emitted (for drama)
each time there is contact between an infected sprite and
a healthy sprite.
The final outcome is determined both by chance and by
several factors including:
-The maximum life expectancy of an infected sprite
-The maximum probability of infection due to contact with
an infected sprite
-The ma