5: Side Scrollers

What We Will Cover


Illuminations

Questions from last class or the Reading?

Homework Questions?

  • Lab 4: White Blood Cell (2/21/17)
    Q4: Finishing Touches (2/23/17)
  • Please do not put spaces in folder names of zip files turned in for homework
  • The Java compiler has problems with spaces in folder or file names
  • Did anyone attempt XC 2? (populate world from array using a loop)

5.1: Creating a Scrolling world

Learner Outcomes

At the end of the lesson the student will be able to:

  • Create a scrolling world scenario
  • Automatically places tiles in a world
  • Scroll tiles as the scenario runs

5.1.1: Scrolling Worlds

  • The White Blood Cell (WBC) scenario is an example of a scrolling video game

    Scenario file: WBC.gfar.

  • The first scrolling video game was Kee Games Super Bug released in 1977
  • "Super Bug" in this case refers to the Volkswagen Beetle, which was often referred to as a "bug"

WBC Character Movement

  • WBC action is viewed from a side-angle view
  • The main player character (PC) stays mostly stationary
  • To create the illusion of motion, the background and other onscreen actors move
  • Actors move by calling the setLocation() method in combination with getX() and getY() like:
    setLocation(getX() - speed, getY());
    
  • The getX() and getY() commands return the current (x, y) coordinates
  • Recall that Greenfoot Actors are located by a coordinate system that starts in the upper left-hand corner (see below)
  • By adding or subtracting an amount of pixels to the current coordinates, the characters moves
  • The movement is independent of the direction the character is pointing

Character Location

Actor movement

Methods Controlling Movement

Method Description
getX() Return the x-coordinate of the actor's current location.
getY() Return the y-coordinate of the actor's current location.
move(distance) Move the actor the specified distance in the direction it is currently facing.
setLocation(x, y) Move the actor to the specified location.

Check Yourself

  1. True or false: the coordinate system used by Greenfoot is the same as that used in algebra.
  2. The origin of the (x, y) coordinate system is located at the ________.
    1. upper left-hand corner of the window
    2. upper right-hand corner of the window
    3. lower right-hand corner of the window
    4. lower left-hand corner of the window
  3. True or false: in the coordinate system used by Greenfoot, locations shown in the window are always positive numbers.
  4. To set the location of an actor we call the ________ method, passing arguments for the (x, y) coordinates

5.1.2: Creating a Scrolling World

  • In this section we create our own scrolling world game named scroller
  • The first step is to decide on your theme, like Space
  • Once we have settled on a theme, we create a World subclass
  • We open the editor for "MyWorld" and change it to something appropriate like "ScrollWorld"
  • We leave the world with no background image ("No image")
  • Some scrolling games do have a background image, like WBC
  • However, we will supply the background image using scrolling tiles

Unbounded Worlds

  • By default, Greenfoot does not allow actors to go outside the world
  • In our scrolling world game, actors appear on the right and disappear on the left
  • This behavior means we will see background actors suddenly appear and disappear at the edges
  • WBC solved the problem by adding a border at the edge that hid the odd behavior
  • Another option is to change the default behavior and allow actors to move outside the world
  • Then we add and remove background actors off screen
  • We allow actors to go outside the world by changing our call to super() in our World subclass
  • For instance, in our ScrollWorld we can write
    super(600, 400, 1, false);
    
  • The fourth variable, false, is added to let actors move outside the boundaries of the world

Adding a Player Character

  • We continue setting up our game by placing a Player character in the game as a reference
  • Choose a player character image, any desired image, like rocket.png.
  • We typically place the character on the left side of the game for a side scroller
  • We will add player movement after we have set up the background
  • Once we have the player positioned, we right-click on the world background and select the Save the World function
  • This creates a prepare() method in our world and saves the location of our player

Scrolling Backgrounds

  • For a scrolling background, we need actors that serve as the background of the game
  • The background actors move across the screen to create the scrolling effect
  • In the next sections, we will create a tile map for our scrolling background

Activity: Starting the Scenario (4m)

  1. Choose a theme for a scrolling world game and create a new scenario named "scroller".

    Please use the specified names if you want credit because it makes grading easier.

  2. Open the editor for the world subclass and change the class name and constructor name to ScrollWorld like:
    public class ScrollWorld extends World
    {
    
        /**
         * Constructor for objects of class ScrollWorld.
         *
         */
        public ScrollWorld()
        // other code omitted
    
  3. In addition, set the world to an unbounded state by changing the call to super() like:
    super(600, 400, 1, false);
    
  4. Create a player character and position it in the world.
  5. Right-click on the world background and select the Save the World option.
  6. Save your scenario so you can update it in future exercises.

Check Yourself

  1. True or false: by default, Greenfoot prevents actors from moving outside the world boundaries.
  2. If you want an unbounded world, set the fourth parameter of the World constructor, which is called using super(), to ________.
  3. True or false: "off screen" means an actor is outside what can be seen on the game screen.
  4. The default background color of a world when no images are selected is ________.

5.1.3: Tiles and Tile Maps

  • A common approach for developing game worlds is to use tile maps
  • A tile map is a technique for generating large graphics from a number of smaller graphics
  • Tile maps have been used for many years in games such as the early Legend of Zelda games
  • The technique is still popular today because:
    1. Tile maps save main computer memory
    2. Tile maps increase real-time rendering performance

Laying Out Tile Maps

  • A tile map breaks down a game world into a grid as shown in the diagram below
  • Each cell in the grid contains either a small tile object or nothing

  • Tile-based maps are like creating a game world with building blocks
  • We use only a few different blocks but we can use as many of each block as we want
  • Each tile object in the map contains a reference to the image that belongs in a cell of the grid
  • When Greenfoot draws the tile at a location, it takes the referenced image and draws it on the screen
  • The program thus uses the same image at many places on the screen
  • By reusing the image many times, the program needs to store fewer images
  • Thus we only need a few small images to draw an entire scenario

Check Yourself

  1. For the above image, and ignoring the grid lines, to draw the tile map you need ________ image(s).
  2. In the above tile map, the number of time the same image is displayed is ________.
  3. Of the following statements, the one that correctly describes how a tile maps saves memory space is ________.
    1. tiles are arranged in a two-dimensional grid to create a larger image.
    2. not all grids locations are filled with tile objects.
    3. the program draws the same small image at multiple places in the world
    4. each tile object is smaller than the entire world.

More Information

5.1.4: Tiles and Constant Variables

  • In this section we create a tile background for our scrolling game
  • The first step is to create a Tile actor and assign it an image
  • For example, for our space game we choose the space.jpg background for the tile

Finding the Image Size

  • Once we choose the tile background, we need to know the size of the image
  • We will be using the image size to calculate where to place the images in our scenario
  • We can usually discover the image size by looking in our scenario's image folder
  • Another way to discover the size is to temporarily add the following code to the act() method of the Tile class
    GreenfootImage img = getImage();
    System.out.println("Width: " + img.getWidth());
    System.out.println("Height: " + img.getHeight());
    
  • By adding a tile to the world and pressing the Act button once, the terminal window displays the image size like:
    Width: 64
    Height: 64
    
  • The size of the image should be small to conserve memory and increase performance

Constant Variables

  • Once we know the size of the background image we need to save its size for use in some calculations
  • One good way to save the size is to use a constant variable
  • A constant variable (or constant) is a variable that cannot change after being assigned a value
  • A constant variable seems oxymoronic, but is actually quite useful
  • To declare a constant in Java, we use the keyword: final
    public static final int WIDTH = 64;
    public static final int HEIGHT = 64;
    
  • We must assign a value when the constant is declared
  • If we tried to assign a value in a later statement, we get a compile-time error
  • Notice that the name is all uppercase letters with an underscore separator
  • This is a common coding convention that professional programmers follow and you should as well
  • The advantage of saving the size in a variable is we can easily change the tile image
  • When we make a change, all we will need to do is update the constant and our calculations still work

Keyword static

  • We usually make a constant an instance variable and use the keyword static
    public static final int WIDTH = 600;
    public static final int HEIGHT = 400;
    
  • When used with a variable, the keyword static makes a single copy of the variable available to all objects of a class
  • The static keyword is used because only one constant value is needed for all objects
  • After creating the constant variable, we substitute it for all numbers like:
    super(WIDTH, HEIGHT, 1, false);
    
  • Then if we ever decide to change the height we can adjust by changing a single number
  • Another advantage of using constants is that you can easily tell what the number is for
  • Using a constant variable instead of a literal number is a way of documenting what the number means
  • Yet another advantage of a constant is that we can declare them public if necessary
  • Since constants cannot change it is acceptable programming practice to declare them public
  • When declaring public constants, other classes can know the value without causing problems
  • Thus in the case of the world size, other classes can easily know the size of the world class using code like:
    int worldWidth = SrollingWorld.WIDTH;
    

Activity: Adding Constants (4m)

  1. Start Greenfoot and open the scrolling world scenario from the last Activity.
  2. Open the ScrollWorld class and record the width and height of the world using two public static constant variables like:
    public static final int WIDTH = 600;
    public static final int HEIGHT = 400;
    
  3. Now update the world size command to use these constant variables in the world constructor like:
    super(WIDTH, HEIGHT, 1, false);
    
  4. Next create a Tile subclass of Actor and assign it an image.
  5. Find the width and height of the tile image you chose
  6. Record the width and height in two public static constant variables in the Tile class like:
    public static final int WIDTH = 64;
    public static final int HEIGHT = 64;
    

    Your WIDTH and HEIGHT values will depend on the image you selected. We can use the same constant names since we are declaring the variables in different classes.

  7. Compile your scenario to make sure the changes were made correctly.

    If you have problems, ask a classmate or the instructor for help as needed.

  8. Save your scenario so you can update it in future exercises.

Check Yourself

  1. A better solution than adding the same number to several places in a class is to add a __________ variable.
  2. The keyword Java uses to make a variable constant is __________.
  3. True or false: you should use named constants rather than literal numbers in your code so you can easily tell what the number means.
  4. True or false: constants should be written in lower case letters so you cannot easily tell the variable is constant.

5.1.5: Placing Tiles

  • Now that we have a tile for the background we need to place the tiles
  • We could manually place all the tiles and call the Save the World function
  • However, manual placement is a tedious and error prone activity
  • Also, what if we decide to change the tile image?
  • A better approach than manual placement is to add code that automatically place tiles

Calculating Tile Position

  • The first tile we want to place is in the upper-left-hand corner of the screen
  • We carefully place the tile and check its (x, y) coordinates
  • When checking, notice that the coordinates of the first tile are ½ the tile width and height
  • This is because Greenfoot calculates the position of an actor from the center of its image
  • Thus we can calculate the position of the first tile by adding the following code to the prepare() method:
    int leftX = Tile.WIDTH / 2; // leftmost x-coordinate for a tile
    int topY = Tile.HEIGHT / 2; // highest y-coordinate for a tile
    addObject(new Tile(), leftX, topY);
    
  • Notice the use of the new operator: new Tile()
  • As we discussed in lesson 4.2.3, we are constructing a new Tile object
  • The keyword new tells Java to construct a new object from the class
  • We use the World method addObject() to add the new tile object to the world
  • To add more tiles, we would place them exactly one tile width to the side until the row is complete
  • Then we would add the next row and repeat the placement process to position all the tiles in the world

for-loop syntax

Repeating Calculations with the for-Loop

  • We need to repeat our calculation for tile locations and place additional tiles
  • To repeat code we use for-loops and arithmetic to calculate locations
  • We can visualize the for-loop as a series of steps to reach a goal
  • In this case, the steps to reach our goal are the placement of tiles within the grid system of our world
  • Recall from lesson 4.2.4 the syntax of the for-loop:
               ❶    ⇛    ❷   ⇚   ❸
    for (int i = start; i < end; i = i + 1) {
        ...
    }
    
  • Where:
    • i: the name of a counter variable
    • start: the initial starting value
    • end: the final ending value
  • As an example, we could place a row of tiles in the world by adding the following code to the start of the prepare() method:
    int leftX = Tile.WIDTH / 2;  // leftmost x-coordinate for a tile
    int topY = Tile.HEIGHT / 2;  // highest y-coordinate for a tile
    int tilesHorz = WIDTH / Tile.WIDTH + 2; // number of tiles across
    for (int x = 0; x < tilesHorz; x++)
    {
        int tileY = topY;
        int tileX = leftX + Tile.WIDTH * x;
        addObject(new Tile(), tileX, tileY);
    }
    
  • The first two lines calculate the position of the first tile
  • The third line calculates the number of tiles needed across the screen
  • We add an extra tile to allow tiles to be off screen when being added to or removed from the world
  • The for-loop counts the number of tiles across one at a time
  • Inside the for-loop we calculate the new tile's x-coordinate on the first line:
    int tileX = leftX + Tile.WIDTH * x;
    
  • The last line of the for-loop adds a new tile at the calculated position
  • Lets trace the calculation of the x-coordinate of the tile

Activity: Tracing the Loop (4m)

int leftX = Tile.WIDTH / 2; // leftmost x-coordinate for a tile
int topY = Tile.HEIGHT / 2; // highest y-coordinate for a tile
int tilesHorz = WIDTH / Tile.WIDTH + 2; // number of tiles across
for (int x = 0; x < tilesHorz; x++)
{
    int tileY = topY;
    int tileX = leftX + Tile.WIDTH * x;
    addObject(new Tile(), tileX, tileY);
}

For the above code, trace the loop and enter the first three values of tileX and tileY into the following table. Assume that Tile.WIDTH == 64 and Tile.HEIGHT == 64. Press the Submit button to record your answer.

Tracing the Loop
x tileX tileY
0
1
2

Testing Our Trace

  • We should always test to verify our understanding
  • In general, we should test our code every time we add a few lines
  • To test our tile placement, we right-click a Tile object and select Inspect

    Inspectint the bug

Filling the Screen

  • To finish filling the screen with background tiles we need to calculate the y-coordinate as well the x-coordinate
  • First we need to calculate the number of tiles to place vertically:
    int tilesVert = HEIGHT / Tile.HEIGHT + 1; // +1 for top/bottom buffer
    
  • We simply divide the world height by the tile height
  • Unless the world height is an exact multiple of the tile height, we need to add one more tile
  • Once we know the number of tiles, we add another loop around the existing loop as shown below

Example Code to Place Tiles in the World

int leftX = Tile.WIDTH / 2; // leftmost x coordinate for a tile
int topY = Tile.HEIGHT / 2;    // highest y coordinate for a tile
int tilesVert = HEIGHT / Tile.HEIGHT + 1; // +1 for top/bottom buffer
int tilesHorz = WIDTH / Tile.WIDTH + 2;   // +2 for scrolling buffer
for (int y = 0; y < tilesVert; y++)
{
    int tileY = topY + Tile.HEIGHT * y;
    for (int x = 0; x < tilesHorz; x++)
    {
        // int tileY = topY;
        int tileX = leftX + Tile.WIDTH * x;
        addObject(new Tile(), tileX, tileY);
    }
}

Nested Loops

  • Notice that the above code has a for-loop nested inside another for-loop
  • By analogy, nested loops are like an odometer on a car
  • The numbers to the right loop completely before the number to the left increments by one

    odometer

  • The inner loop is like the numbers to the right in the odometer
  • An inner loop runs to completion every time the outer loop executes once

Analyzing a Nested Loop

  • The best way to understand nested loops is to work from the inside out
  • The inner loop in our example places all the tiles in a row
    for (int x = 0; x < tilesHorz; x++)
    {
        int tileX = leftX + Tile.WIDTH * x;
        addObject(new Tile(), tileX, tileY);
    }
  • The outer loop moves the y-coordinate from one row to the next
    for (int y = 0; y < tilesVert; y++)
    {
        int tileY = topY + Tile.HEIGHT * y;
        // inner loop here or call placeRow()
    }
    
  • Oftentimes people place inner loops inside a method to clarify the logic

Check Yourself

  1. Instead of repeating statements we can often use a ________.
  2. When you clap your hands 10 times:
    1. You know when to stop because you ________
    2. Every time you clap, the count ________.
  3. For the example loop shown below, the loop repeats ________ times.
    for (int counter = 0; counter < 5; counter++)
    {
        System.out.println(counter);
    }
    
  4. True or false: the purpose of the variable counter in the above loop is to keep track of the number of repetitions.
  5. True or false: a loop can be nested inside another loop.
  6. By analogy to an odometer, an inner loop is like the digits to the ________.
  7. Every time an outer loop iterates once, an inner loop runs ________.
    1. completely
    2. incrementally
    3. partially
    4. twice

5.1.6: Moving the Tiles

  • We can now automatically place the background tiles
  • To create the illusion of motion, we move the background tiles
  • The player character is more or less stationary
  • The tiles move in the opposite direction we want the player character to seem to move

Moving the Tiles

  • To move the tiles we call setLocation() from the act() method of Tile
    private static final int SPEED = 1; // some values leave gaps
    
    public void act()
    {
        setLocation(getX() - SPEED, getY());
    }
    
  • With the above code, every call to the act() method moves the tile to the left

Wrapping the Tiles

  • Within a short time, the tiles will all move left off the screen
  • To keep the illusion going, we need to add tiles to the right of the screen
  • We can delete old tiles and make new ones as needed, which is the approach used in WBC
  • Another technique is to reuse the tiles

Reusing Tiles

  • To reuse the tiles, we add an if-statement to test when the tiles goes off screen
  • When the tile goes off screen, we reposition it off screen to the right
  • As the act() method executes, the repositioned tile eventually moves on screen
  • We can see the complete act() method in the following code example

Example Tile Code for Horizontal Scrolling

public void act()
{
    if (getX() <= -WIDTH / 2)
    {
        // Reposition tile to use again at the right edge off-screen
        int newX = (ScrollWorld.WIDTH / WIDTH + 1) * WIDTH + WIDTH / 2;
        setLocation(newX, getY());
    }
    setLocation(getX() - SPEED, getY());
}

Exercise 5.1: Scrolling the Background (5m)

In this exercise, we do scroll the background of our scrolling world.

Specifications

  1. Start Greenfoot and open the scroller scenario from the previous Activities:
    1. Activity: Starting the Scenario
    2. Activity: Adding Constants
  2. Open the editor for the ScrollWorld class and add the following code to the beginning of the prepare() method:
    int leftX = Tile.WIDTH / 2; // leftmost x coordinate for a tile
    int topY = Tile.HEIGHT / 2;    // highest y coordinate for a tile
    int tilesVert = HEIGHT / Tile.HEIGHT + 1; // +1 for top/bottom buffer
    int tilesHorz = WIDTH / Tile.WIDTH + 2;   // +2 for scrolling buffer
    for (int y = 0; y < tilesVert; y++)
    {
        int tileY = topY + Tile.HEIGHT * y;
        for (int x = 0; x < tilesHorz; x++)
        {
            int tileX = leftX + Tile.WIDTH * x;
            addObject(new Tile(), tileX, tileY);
        }
    }
    
  3. Compile the scenario and verify there are no errors.

    You should see the background of the world fill completely with tiles. Resolve any errors you find, getting help from a guild member or the instructor as needed.

  4. Open the source code editor of the Tile class and add the following constant to the class:
    private static final int SPEED = 1; // some values leave gaps
    
  5. Also in the Tile class, update the act() method as shown below:
    public void act()
    {
        if (getX() <= -WIDTH / 2)
        {
            // Reposition tile to use again at the right edge off-screen
            int newX = (ScrollWorld.WIDTH / WIDTH + 1) * WIDTH + WIDTH / 2;
            setLocation(newX, getY());
        }
        setLocation(getX() - SPEED, getY());
    }
  6. Compile and run your scenario to verify all the changes work well.

    You should see the background scroll to the left with the player character stationary. If you have problems, ask a classmate or the instructor for help as needed.

  7. Save a copy of your final scenario with all the changes made to upload to Canvas as part of the next lab.

    We will be adding more code to these files in subsequent exercises, so it is not time to submit them to Canvas yet. However, it is a good idea to have a backup copy in case of problems later in development.

When finished please help those around you.

5.2: Moving the Player

Learner Outcomes

At the end of the lesson the student will be able to:

  • Add animation to the player character
  • Make use of logical operators
  • Code if-statements with multiple conditions

5.2.1: Animating the Player

Scenario file: scroller1.gfar.

  • We want to add animation to our player as we discussed in lesson 4.3
  • For the example, the instructor will be using these two images:
    Rocket with longer flame Rocket with shorter flame
    rocket.png rocket2.png
  • The flame of the second rocket is shorter than the flame of the first

Adding the Animation Images

  • To add the animation we first declare instance variables for the images in the Player class
    private GreenfootImage img1, img2;
    
    • Remember to ALWAYS declare instance variables as private
    • Otherwise it becomes hard to change code as projects grow larger
  • Second we add a constructor that initializes the image variables
    public Player()
    {
        img1 = new GreenfootImage("rocket.png");
        img2 = new GreenfootImage("rocket2.png");
    }
    
  • Recall that the constructor is called automatically whenever an object is constructed
  • Thus when the ScrollWorld constructs a new Player, the constructor method is called
    Player player = new Player(); // calls Player constructor
    

Coding the Animation

  • An animation requires us to alternate images
  • To alternate the images we use an if-else statement
  • The if-else statement allows us to choose between two actions
  • If a condition is true
    • then do this
  • Otherwise it is false
    • so do something else
  • Recall the syntax of the if-else statement:
    if (test) {
       statements1
    } else {
       statements2
    }
    
  • Where:
    • test: the test condition to evaluate
    • statementsX: the statements to execute depending on the test
  • Our example animation alternates two images so we code:
    if (getImage() == img1) {
        setImage(img2);
    }
    else
    {
        setImage(img1);
    }
    
  • We package the animation in a method and call the method from act()

Example Animation Method

public void updateImage()
{
    if (getImage() == img1) {
        setImage(img2);
    }
    else
    {
        setImage(img1);
    }
}

Check Yourself

  1. True or false: an if-else statement allows the programmer to select between two alternatives.
  2. What is wrong with the following if-else statement? (answer)
    if (7 == guess) {
        msg = "*** Correct! ***";
    } else (7 != guess) {
        msg = "Sorry, that is not correct.";
    }
    
  3. If the current image displayed is image1, the image displayed after the following code fragment runs is ________.
    if (getImage() == image1)
    {
        setImage(image2);
    }
    else
    {
        setImage(image1);
    }
    
  4. What is the value of x after the following code segment? (answer)
    int x = 5;
    if (x > 3) {
        x = x - 2;
    } else {
        x = x + 2;
    }
    

5.2.2: Logical Operators

  • Our player character can move four different directions in the scenario
    • right
    • left
    • forwards
    • backwards
  • By using multiple if statements we can select between multiple alternatives
  • However, our movement could go outside the world
  • If we are close to the edge, we no longer want to allow movement
  • Thus we will need to check for two conditions with each if statement:
    • if the correct key is pressed
    • if we are far enough away from the edge to move
  • To make multiple decisions with each if-statement, we will use logical operators

Logical Operators

  • Recall that we test is a key is currently being pressed using Greenfoot.isKeyDown()
  • Sometimes we want to test if a keyboard key is pressed but only if another condition is true as well
  • A logical operator, or Boolean operator, is an operator that connects two Boolean test conditions
  • We use logical operators to combine multiple Boolean expressions into one Boolean result
  • For example, we want to test if the "up" key is pressed and our y-coordinate is greater than 25
  • We write this in Java code like:
    if (Greenfoot.isKeyDown("up") && getY() > 25)
    
  • The && is how we spell "and" in Java
  • Java has several logical operators, but we only need to use three to create any possible test condition
  • These three operators are:
    • && (and)
    • || (or)
    • ! (not)
  • We discuss all three operators below

Truth Tables

  • When we discuss logic we often use truth tables
  • A truth table is a list of input values and the resulting output
  • We can see truth tables below starting with the truth table for logical "and"

Truth Table for && (and) Operator

If cond1 is... And cond2 is... Then cond1 && cond2 is... Example Result
false false false 5 > 10 && 5 < 2 false
false true false 5 > 10 && 5 > 2 false
true false false 5 < 10 && 5 < 2 false
true true true 5 < 10 && 5 > 2 true
  • The && operator returns true if both operands are true and returns false otherwise
  • Activity: construct a truth table for the following test conditions
    if (Greenfoot.isKeyDown("up") && getY() > 25)
    

Truth Table for || (or) Operator

If cond1 is... || cond2 is... Then cond1 || cond2 is... Example Result
false false false 5 > 10 || 5 < 2 false
false true true 5 > 10 || 5 > 2 true
true false true 5 < 10 || 5 < 2 true
true true true 5 < 10 || 5 > 2 true
  • The || operator is true when either or both operands are true
  • Only when both operands are false is the entire || statement false
  • Activity: construct a truth table for the following test conditions
    if (Greenfoot.isKeyDown("up") || getY() > 25)
    

Truth Table for ! (not) Operator

If cond is... Then ! cond is... Example Result
false true !(5 < 2) true
true false !true false
  • The ! operator negates the meaning of a logical expression

Another Look at Truth Tables

  • Note that most computers store true as 1 and false as 0
  • If we substitute 1 for true and 0 for false, we have these truth tables:

two value logic tables

  • With this substitution we see that the AND operation is the minimum of the operands
  • Conversely, the OR operation is the maximum of the operands
  • The NOT operator simply reverses its operand

More Information

Check Your Understanding

  1. Of the following groups ________ is larger.
    1. Students wearing denim
    2. Students wearing denim AND corrective lenses
  2. Of the following groups ________ is larger.
    1. Students wearing denim
    2. Students wearing denim OR corrective lenses
  3. Of the following groups ________ is larger.
    1. Students wearing denim
    2. Students wearing denim AND NOT corrective lenses
  4. Of the following logical expressions, the one that tests to see if x is between 1 and 10 (including 1 and 10) is ________ .
    1. (x >= 1 && x <= 10)
    2. (1 <= x and x <= 10)
    3. (x >= 1 || x <= 10)
    4. (1 <= x or x <= 10)

5.2.3: Implementing Player Movement

  • Now that we can test two conditions with each if-statement we can implement player movement
  • Remember we will need to check for two conditions with each if-statement:
    1. if the correct key is pressed
    2. if we are far enough away from the edge to move
  • When the "up" key is pressed we also make sure our y-coordinate is greater than half the height of our image
  • We write this in Java code like:
    if (Greenfoot.isKeyDown("up") && getY() > 25)
    
  • When both these conditions are true, we move our player character upwards like:
    setLocation(getX(), getY() - 4);
    

Activity: Logical Operators (4m)

Remember that Greenfoot.isKeyDown() checks if a key is currently being pressed and that our ScrollWorld has two public constants WIDTH and HEIGHT. Assuming our image is 100 pixels wide by 50 high, what test conditions do we write for the following:

Logical Tests
Keypress Logical Operator Edge Check
Greenfoot.isKeyDown("up")
Greenfoot.isKeyDown("down")
Greenfoot.isKeyDown("left")
Greenfoot.isKeyDown("right")

Writing the Code

  • Once we have the test conditions for our if statements, we can complete the code
  • The following example shows how to control player movement Click to show example
  • The code is in its own method: checkKeyPress()
  • We must call the checkKeyPress() method from the act() method

Exercise 5.2: Adding Player Movement 5m)

In this exercise, we do implement movement for our player character.

Specifications

  1. Start Greenfoot and open the scroller scenario from the last exercise.
  2. Open the editor for the player character and add the following checkKeyPress() method:
    private void checkKeyPress()
    {
        // add other code here
    }
    
  3. Add a call to the checkKeyPress() in the act() method.
  4. Complete the checkKeyPress() method, adding appropriate movement for your player character.

    For more information see lesson 5.2.3: Implementing Player Movement.

  5. Compile and run your scenario to verify all the changes work well.

    If you have problems, ask a classmate or the instructor for help as needed.

  6. Optionally, add animation to your Player class as discussed in 5.2.1: Animating the Player
  7. Save a copy of your scenario with all the changes made to upload to Canvas as part of the next lab.

    We will be adding more code to these files in subsequent exercises, so it is not time to submit them to Canvas yet. However, it is a good idea to have a backup copy in case of problems later in development.

When finished please help those around you.

5.2.4: Review

  • In this section we continued developing our side scroller
  • First we animated our player by alternating two images, which we have done before
  • Our example animation alternated two images though we could add more images:
    if (getImage() == img1) {
        setImage(img2);
    }
    else
    {
        setImage(img1);
    }
    
  • Next we looked at how to code more complex conditions by using logical operators
  • A logical operator, or Boolean operator, is an operator that connects two Boolean test conditions
  • Java has several logical operators, but we only need to use three to create any possible test condition
  • These three operators are:
    • && (and)
    • || (or)
    • ! (not)
  • The logical operators AND, OR and NOT are shown in the following table

  • We looked at Java code examples with complex conditions to control player movement like:
    if (Greenfoot.isKeyDown("up") && getY() > 25)
    

5.3: Non-Player Characters

Learner Outcomes

At the end of the lesson the student will be able to:

  • Discuss what is meant by an NPC
  • Reference the current world
  • React to collisions
  • Use the World act() method to create new objects

5.3.1: Adding Non-Player Characters

Scenario file: scroller2.gfar.

  • Our player characters is all alone in the scenario
  • To make the scenario more interesting, we add non-player characters (NPCs)
  • A non-player character is any character not controlled by a human player
  • In a video game, the NPC is usually controlled by the computer
  • We will want two types of NPCs in our scenario:
    1. One to collect
    2. One to avoid
  • We will develop these NPCs in the following sections

NPCs to Collect

  • We often have objects to collect in a game
  • For example we may collect score for finding certain items such as we do in WBC
  • Other collectibles may include power-ups
  • A power-up is a game object that provides some benefit or extra ability

NPCs to Avoid

  • Many games are filled with NPCs to avoid
  • NPCs may cause damage or reduce the player score
  • For example, touching the Virus in WBC subtracts 100 from the score and may end the game

Check Yourself

  1. Of the following, ________ is an NPC.
    1. a player character
    2. a sprite controlled by the game player
    3. a sprite controlled by the computer
    4. a background image like a sign
  2. True or false: all NPCs should be avoided in a game.

5.3.2: Referencing the World

  • The World class has many useful methods like
    • addObject()
    • removeObject()
    • showText()
  • We often run into situations where an actor wants to call one of these methods
  • However, an actor cannot just call these methods because they are world methods and not actor methods
  • We can only directly call methods of our own class

Calling getWorld()

  • Fortunately, the Actor class has a method to get a reference to the world

    getWorld(): returns a reference to the world the actor lives in.

  • We can save the world reference in a variable like:
    World w = getWorld(); // called from an actor
    
  • We discussed reference variables in lesson 4.3.5: Constructors and Reference Variables
  • A reference has access to all the methods of an object
  • Thus when we get a reference to the world we can call its methods like:
    w.showText("Game Over", 300, 200);
    
  • The last two arguments are the (x, y) coordinates

Chaining Method Calls

  • The getWorld() method returns a reference to the world the actor lives in
  • Rather than saving the world reference in a variable, we can access the reference directly like:
    getWorld().showText("Game Over", 300, 200);
    
  • This is known as chaining method calls
  • We first call getWorld() which returns a reference
  • Then we call a method of the reference like showText()
  • Both of these methods calls occur in one statement with dots between them

Check Yourself

  1. True or false: sometimes an actor needs to call methods of the world class.
  2. True or false: getWorld() returns the current world that the actor lives in.
  3. Calling multiple methods in one statement with dots between them is known as ________

5.3.3: Objects to Collect and Avoid

  • We now add a collectible object to our scenario
  • For our example, we will add an Astronaut class
  • For the backstory, a space habitat has sprung a leak and we are collecting baby astronauts
  • The baby astronauts are temporarily surrounded by an emergency bubble but time is running out!

Moving and Turning

  • In the Astronaut class, we add moving and turning in the act() method
    setLocation(getX() - 2, getY());
    turn(1);
    
  • We use setLocation() so the astronaut moves to the left no matter the rotation

Disappearing an Astronaut

  • We need to remove any astronauts that slip past our player character so we do not overload our scenario
  • To make an astronaut disappear we add the following code to the act() method:
    if (getX() == 0)
    {
        getWorld().removeObject(this);
    }
    
  • When the x-coordinate reaches the left side of the screen, we call the removeObject() method of World
  • As an argument we use the special Java keyword this
  • The this keyword refers to the current object that is executing at this moment
  • In essence, the keyword this means "this current object"
  • Thus by using this as an argument, we are telling the astronaut to remove itself from the world

Example Code for an act() Method

public void act()
{
    setLocation(getX() - 2, getY());
    turn(1);

    if (getX() == 0)
    {
        getWorld().removeObject(this);
    }
}

Objects to Avoid

  • In addition to a collectible object, we add an object to avoid
  • For our example, we will add an Asteroid class using the image:

    asteroid image

  • We add similar code to move, turn and disappear the asteroid as we did the astronaut
  • The difference is in what we do when we collide with the object

Check Yourself

  1. for an actor to move in one direction no matter the orientation, call the method ________.
  2. To make an object disappear, we call the World method ________.
  3. In the following code, this as an argument means ________.
    getWorld().removeObject(this);
    

5.3.4: Reacting to Collisions

  • Let us look at how to react when we collide with an object
  • The player character will do the reacting, so we add the code in the Player class
  • We call the method checkCollision() and call it from the act() method
  • Inside the checkCollision() method we use the commonly used collision methods shown below
  • When we collide with as astronaut, we rescue them and play a happy sound

    hooray.wav

  • When we collide with an asteroid it is disastrous and we play a crash sound

    crash.wav

Commonly Used Actor Methods for Interaction

Method Description
isTouching(Class cls) Returns true if this actor is touching another object of the given class; otherwise returns false.
removeTouching(Class cls) Removes one object of the given class that this actor is currently touching, if any exist.

Example Method checkCollision()

private void checkCollision()
{
    if (isTouching(Astronaut.class))
    {
        removeTouching(Astronaut.class);
        Greenfoot.playSound("hooray.wav");
    }
    if (isTouching(Asteroid.class))
    {
        Greenfoot.playSound("crash.wav");
        Greenfoot.stop();
    }
}

Check Yourself

  1. True or false: collision detection is generally performed in the class that responds to the collisions.
  2. The methods isTouching() and removeTouching() are defined in the class ________.
  3. True or false: the purpose of method isTouching() is to detect if our actor has touched another actor.

5.3.5: Creating New Objects Automatically

  • A world subclass may have an act() method just like an actor
  • One use of an act() method in the world is to add new objects to our scenario
  • An example act() method for the world class is shown below

Example act() Method for ScrollWorld

/**
 * Create new floating objects at random intervals.
 */
public void act()
{
    if (Greenfoot.getRandomNumber(100) < 3)
    {
        int x = WIDTH - 1;
        int y = Greenfoot.getRandomNumber(HEIGHT - 50) + 25;
        addObject(new Astronaut(), x, y);
    }
    if (Greenfoot.getRandomNumber(100) < 1)
    {
        int x = WIDTH - 1;
        int y = Greenfoot.getRandomNumber(HEIGHT - 50) + 25;
        addObject(new Asteroid(), x, y);
    }
}

Assigning the Coordinates

  • The right-hand side of the screen is always at the WIDTH - 1
  • The reason for the -1 is that we count pixels starting at 0 instead of 1
  • The y-coordinate is a random number like we discussed in lesson 3
  • However, with an unbounded world we must use care when launching an actor off-screen

Check Yourself

  1. True or false: the world may have an act() method just like an actor can.
  2. To appear at the right side of the screen with a world size of 600 x 400 pixels, we set the y-coordinate to ________.
  3. True or false: with an unbounded world we must be careful to not launch objects off screen.

Exercise 5.3: Adding NPCs (5m)

In this exercise, we do add NPCs to our scrolling world scenario.

Specifications

  1. Start Greenfoot and open the scroller scenario from the last exercise.
  2. Add two new classes to the scroller scenario, one to collect and one to avoid.

    For more information see lesson: 5.3.1: Adding Non-Player Characters.

  3. Add code like the following to both of the new classes, such that the actors move from one side of the screen to the other.
    public void act()
    {
        setLocation(getX() - 2, getY());
        turn(1);
    
        if (getX() == 0)
        {
            getWorld().removeObject(this);
        }
    }
    
  4. In the player character class, add a checkCollision() method like the following example. Call the method from the act() method of your player character.
    private void checkCollision()
    {
        if (isTouching(Astronaut.class))
        {
            removeTouching(Astronaut.class);
            Greenfoot.playSound("hooray.wav");
        }
        if (isTouching(Asteroid.class))
        {
            Greenfoot.playSound("crash.wav");
            Greenfoot.stop();
        }
    }
    
  5. Add an act() method to the ScrollWorld class like the following such that both new objects are added to the world at random intervals.
    public void act()
    {
        if (Greenfoot.getRandomNumber(100) < 3)
        {
            int x = WIDTH - 1;
            int y = Greenfoot.getRandomNumber(HEIGHT - 50) + 25;
            addObject(new Astronaut(), x, y);
        }
        if (Greenfoot.getRandomNumber(100) < 1)
        {
            int x = WIDTH - 1;
            int y = Greenfoot.getRandomNumber(HEIGHT - 50) + 25;
            addObject(new Asteroid(), x, y);
        }
    }
    
  6. Compile and run your scenario to verify all the changes work well.

    If you have problems, ask a classmate or the instructor for help as needed.

  7. Save a copy of your completed lesson scenario to upload to Canvas as part of Lab 5. Also, we will add to the scenario next week so bring it to class.

When finished, please help those around you.

5.4: Midterm Preparation

Learner Outcomes

At the end of the lesson the student will be able to:

  • Describe the ground rules for the midterm exam
  • Start preparing for the midterm exam

5.4.1: About the Exam

Important Midterm Exam Information

Date: 3/2/17
Location: Regular classroom
Start time: During the regular class time

  • The exam covers material from the first four lessons
  • Exam question types include multiple choice and short programming problems
  • You will have about 45 minutes to complete the exam

Ground Rules

  • You must attend the exam or you will receive a score of zero (0)
    • Except by prior arrangement with the instructor
  • I am using Canvas to administer the test
  • The exam is closed books and closed notes
    • However, you may have one 3" x 5" card of handwritten notes for the exam
  • You may use a computer from the classroom, but only to take the exam in Canvas
  • You may have blank scratch paper
  • You may NOT use the computer to compile or run programs
  • You may NOT use the computer to view documents on the Internet
  • You may NOT use a cell phone, calculator or other electronic device
    • Thus, you may NOT use your own computer to take the exam
    • If you have a cell phone visible or in use during the exam, you will automatically fail
  • You may NOT communicate with anyone but the instructor during the exam

3"x5" Card Requirements

  • Put your name on your card
  • Maximum card or paper size is 3 inches by 5 inches
  • You may use both sides of the card
  • Notes must be handwritten and NOT photocopied
  • No more than three statements in a sequence on the card — only snippets
  • Any 3" x 5" cards violating these rules will be confiscated before the test
  • You must turn in your 3" x 5" card after the exam in any case

5.4.2: Test Preparation Self Assessment

Follow this link and take two minutes to read and answer the questions. (2m)

Discussions Questions

  • How are these practices beneficial?
  • What are your successful strategies for exam preparation?
  • How much time do you dedicate to test preparation? Click to show answer

5.4.3: How to Study for the Exam

forked road
  • No one can ace a test without studying and understanding the material
  • To get an "A" you need to thoroughly prepare for the test well in advance
  • With the midterm approaching, you have a choice:
    • Study and do well, or
    • Not study and do less than your best
  • Victims are people who let their lives control them, like a pawn on a chessboard
  • Creators are people who controls their own life, like a person playing chess
  • You can take responsibility for studying and do well on a test
  • Or you can make excuses and do less than you are capable of on a test

Boosting Your Performance

Here are some steps you can take to improve your test results:

  1. Compile a list of topics you might be tested on.

    Look over your quests, labs, and lecture notes to determine what we covered. Write a list of topics from these sources.

  2. Make sure you understand all the topics on your list.

    Correct any mistakes you may have made in your quests, labs or boss events.

  3. Identify the most probable exam topics for thorough study.

    To do well, you need deep understanding of the test topics. Gaining a deep understanding takes time. Often you can tell what is on a test simply by which topics the instructor spends the most time talking about.

  4. Create a list of possible test questions.

    Turn headings from the textbook and lecture notes into questions. Look at the section summaries in the lectures and read the Check Yourself questions.

  5. Study your questions over and over until you know them perfectly.

    Make flash cards (or use an app) with questions on one side and answers on the other. Carry the cards with you and review them when you have a few minutes available. Have other people ask you questions from your flash cards. Do practice problems to gain a an even deeper understanding of coding techniques.

  6. Prepare your 3"x5" card of test notes.

    Since the instructor allows a 3"x5" card, make use of it. For the topics you had the most trouble with, write down a short note or summary. If the pressure of the test causes you to forget something, you can refer to your card.

More Information

Exercise 5.4: Preparing Exam Questions (3m)

Take three minutes to review and choose one of the following topics for Lab 5. Post the questions in the Discussions area of Canvas titled "Midterm 1 Study Questions" for XP.

There cannot be more than two posts per topic and all the questions for a post must be unique. Thus if two people select the same topic, the second person who posts on the topic must have different questions than the first person.

Exam Topics

  1. Objects, instances and class diagrams (1.3.4, 2.1.3)
  2. Calling methods and returning values (1.3.5, 3.4.3)
  3. Calling methods with parameters (1.3.6, 3.4.4)
  4. Creating World and Actor subclasses (2.1.3, 2.1.4, 2.1.5)
  5. Actor movement, rotation and API methods (2.2.5, 2.2.6, 2.4.2)
  6. Coding if-statements (2.3.2, 3.2.3, 4.3.6, 4.3.7, 4.4.2)
  7. Errors and debugging (2.3.3, 2.3.4)
  8. Variable declaration, assignment and order (2.4.1, 3.1)
  9. Defining new methods (2.4.2, 2.4.3, 3.4)
  10. Random numbers and applications (3.2.1, 3.2.2, 3.2.4, 3.2.5)
  11. Relational operators (3.2.3, 3.2.5)
  12. Simple actor interaction (3.3)
  13. Strings (3.5.1, 3.5.2)
  14. Responding to keyboard input (3.5.2)
  15. Playing sounds and stopping (3.5.3, 3.5.4)
  16. Coding constructors (4.2.1, 4.3.5)
  17. Creating and adding objects to the world (4.2.3, 4.2.2)
  18. Coding for-loops (4.2.4)
  19. Animation (4.3)
  20. Instance variables versus local variables (4.3.4)
  21. Reference variables (4.3.5)
  22. Counting, numbers and arithmetic (4.4)

5.4.4: More Test Preparation

  • To help you study, you can use this review game: Greenfoot Jeopardy
  • Start the game with the "basics.txt" file

Practice Exam

  • To help your understanding of how the midterm will operate, I am providing a practice exam in Canvas
  • The questions are intended to help you get a "feel" for taking an exam in Canvas
  • The questions are NOT intended to tell you everything that is on the exam
  • Suggestion: prepare first and then try the practice exam
  • This will give you a better understanding of how much more preparation you need

Exam Taking Tips

  • If you get stuck on a question, make your best guess and return later
  • If you are equally uncertain between two choices, go with your first impression
  • When writing code, do NOT add more than the problem asks for
  • You do not need to comment code for tests and exams
    • Unless specifically instructed to in the exam question
  • Use the full time available
    • Check your work if you finish early
  • Any questions?

Wrap Up

Due Next:
Q4: Finishing Touches (2/23/17)
Lab 5: Test Questions (2/28/17)
Q5: Basic Arcane Studies (3/2/17)
  • When class is over, please shut down your computer
  • You may complete unfinished lesson exercises at any time before the due date.
Home | Canvas | Schedule | Syllabus | Room Policies
Help | FAQ's | HowTo's | Links
Last Updated: March 24 2017 @19:28:38