9: Planetary Bodies

What We Will Cover


Illuminations

Cybersession Schedule

Questions from last class or the Reading?

Homework Questions?

9.1: Reviewing Newton's Lab

Learner Outcomes

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

  • Describe vectors
  • Work with an abstract class
  • Discuss mixed mode arithmetic
  • Write overloaded constructors and methods
  • Prevent shadowing of variables
  • Use this() within a constructor

9.1.1: Interacting Objects and Abstraction

  • The book scenario is a simulation of bodies in a solar system
  • Lets download and unzip the second completed scenario:

    Scenario file: Newtons-Lab-2.gfar.

  • Download the file to a convenient location like the Desktop
  • Double-click the file to start Greenfoot and open the scenario.
  • By right-clicking on the background, we can see a list of three simulations
  • Before we continue, lets review some key concepts from the chapter

Concept Review

  • Abstract class: a superclass that cannot be instantiated (SmoothMover)
  • Constant variable: a variable that you cannot change (Body)
  • Collection: a type of object that can hold many other objects
  • Generic type: a type that needs a second type name as a parameter (Body)
  • List: a type of collection where objects are stored in an order (Body)
  • null: a special word for "no object" (see lesson 8.1.3)
  • Overloading: having the same method name for two different methods or constructors (SmoothMover)
  • this(): used to call one constructor from another (Body)

Reviewing the Newton's Lab Scenario

  • The main types of bodies in the solar system include the sun, planets and moons
  • Each of these bodies vary in size, mass, composition and velocity
  • However, these bodies are similar in many ways
  • Because each body has a size, mass and velocity, we can use abstraction to program a Body class
  • The Body class, or its superclasses, has variables to store size, mass and velocity
  • To set each characteristic, we have a parameter in the Body class constructor

    public Body(int size, double mass, Vector velocity, Color color)

Abstract Classes

  • The scenario uses two helper classes: SmoothMover and Vector
  • SmoothMover is the superclass of Body
  • If we right-click on SmoothMover, we notice that we cannot create an object
  • Examining SmoothMover, we see that it has a new keyword in the header: abstract
  • We declare classes abstract when we do NOT want to create objects directly from them
  • Abstract classes serve only as superclasses for other classes

Check Yourself

  1. When we simplify a set of real objects, like astronomical objects, to basic shared characteristics, like a Body class, we are using a process known as ________.
    1. abstraction
    2. an abstract class
    3. characterization
    4. summarization
  2. True or false: we can use a parameter in a constructor to customize how an object operates.
  3. True or false: An abstract class can be created by right-clicking on the class in Greenfoot.
  4. True or false: All abstractions are composed in abstract classes.

9.1.2: Vectors

  • Objects that move (for example planets) have a velocity
  • Velocity is both a speed (such as 100 MPH) and a direction (such as up)
  • Because of these two aspects, velocity is often represented as a vector
  • A vector is a geometric object with both direction and length (magnitude)

Representations of Vectors

    A vector with direction and length

  • The above representation is known as polar coordinates
  • Another way to represent a vector is as a pair of distances (dx, dy)
  • The d in (dx, dy) stands for delta, a Greek letter used in science and engineering to mean a change
  • Here is the same vector using (dx, dy):

    A vector with (dx, dy)

  • This second image is called the Cartesian representation
  • The book used a separate Vector class to work with vectors
  • The Vector class is used by the SmoothMover class to control velocity

Activity: Check It! (3m)

  1. Answer the following questions.
  2. Before pressing the Record button, verify your answers with another classmate.
  3. Press the Record button to submit your work.

Check Yourself Questions

  1. A geometric object with both direction and length is called a(n) .
  2. Specifying a vector using direction and length is known as the representation.
  3. Specifying a vector as a pair of distances (dx, dy) is known as the representation.
  4. vector 55 degrees 2.3 magnitude

    For the vector to the right, its direction and magnitude respectively is ________, ________.
  5. If a car moves 30 miles east and 40 miles north in one hour, its vector is ________

9.1.3: Smooth Moving and Type double

  • The purpose of SmoothMover is to position and smoothly move objects on the screen
  • It works by using floating-point (decimal) numbers rather than the usual integers
  • For example, SmoothMover can have the x-coordinate 21.3
  • The important thing to notice is the decimal point
  • If we move an actor along the x-coordinate in increments of 0.7 we have:
    21.3, 22.0, 22.7, 23.4, 24.1, 24.8, 25.5 ...
    
  • Since a screen only allows integer numbers, we have to convert the numbers to integers:
    21, 22, 22, 23, 24, 24, 25 ...
    
  • Even though the numbers are rounded down for the screen, the visual effect is smoother movement

Floating-Point Data Types

  • Let us discuss more about floating-point numbers
  • In lesson 4.3.3, we learned that Java has two general types of numbers: integers and floating-point
  • Furthermore, Java has two floating-point number data types: float and double
  • Type float uses 4 bytes of storage and type double uses twice as much (hence the name)
  • Since type double uses twice as much memory it is more precise that float
  • As with type int, we can declare variables of type float or double:
    double total;
    float away;
    
  • At this point in your programming career, you should always use type double for decimal numbers
  • The additional memory use is small and the extra precision is usually helpful

Converting Numeric Types

  • We can convert one number type into another using a process known as typecasting

    Typecast (or just cast): convert one data type into another

  • For example, the following converts a double into an int:
    double x = 12.34;
    int y = (int) x;
    System.out.println(x + " " + y); // prints 12.34 12
    
  • The data type in parenthesis "(int)" changes the type of the value read from the variable that follows
  • Without the (int) portion, the code would not compile:

    Incompatible type: possible lossy conversion from double to int

  • When the type changes from double to int, the decimal portion is discarded
  • The (int) part of x is then assigned to y
  • Notice that the value stored in x does not change, only the temporary x value in the expression

Mixed-Mode Arithmetic

  • Remember from lesson 4.4.3 that different data types are stored in different forms
    • An int is stored in 4 bytes in a binary format
    • A double is stored in 8 bytes using a floating-point format defined by IEEE 754
  • The computer needs both numbers in the same form before it can do arithmetic
  • If one operand is different than the other, the compiler converts it to the wider of the two types
  • For example:
    2 + 2.3
    • The first number (2) is an int
    • The second number (2.3) is a double
  • Java will automatically convert the int to a double (2.0)
  • Then the computer knows how to do the arithmetic to produce a result of 4.3
  • Remember that the result of an arithmetic operation with an int and a double is always a double

Activity: Check It! (3m)

  1. Answer the following questions.
  2. Before pressing the Record button, verify your answers with another classmate.
  3. Press the Record button to submit your work.

Check Yourself Questions

  1. The difference between an integer and a floating point data type is the ability to hold a decimal .
  2. : type casting permanently changes the type of a variable being cast.
  3. What is the data type of the calculation for the following arithmetic expressions?
    1. 1 + 2
    2. 1.2 + 3.4
    3. 1 + 2.3

Click to show answer

9.1.4: Overloading Constructors and Methods

  • In the Body class, notice that there are two different constructors:

    public Body()
    public Body(int size, double mass, Vector velocity, Color color)

  • Notice the similarities and differences between these two signatures
  • These two constructors allow us to create a new Body object in two different ways
  • For example:

    Body b1 = new Body();
    Body b2 = new Body (50, 240.0, new Vector(270, 0.03), new Color(255, 216, 0));

  • When there is more than one constructor in a class, the constructor is said to be overloaded

    Overloading: having the same name for two different constructors or methods.

  • When constructors or methods are overloaded, they must have different parameter lists
  • The first constructor has no parameters and is called a default constructor
  • A default constructor sets instance variables to default values

Method Overloading

  • We can have multiple methods with the same name as well
  • The name of the method is overloaded because it refers to more than one method
  • We see an example of method overloading in the SmoothMover class:
    public void setLocation(double x, double y)
    public void setLocation(int x, int y)
    
  • The names are the same but the parameters are different -- how?
  • The following method calls invoke different methods:
    setLocation(1.2, 2.3); => setLocation(double, double)
    setLocation(1, 2);     => setLocation(int, int)
    
  • Which method gets called depends on the data types of the arguments
  • We can see which method is selected by placing a different print statement inside each setLocation() method:
    System.out.println("setLocation(double, double)"); // one method
    System.out.println("setLocation(int, int)"); // the other method
    
  • Then in a Body constructor we call each version of setLocation() like:
    setLocation(1.2, 2.3);
    setLocation(1, 2);
    
  • When we place a body into the world, the constructor is called automatically
  • Notice that calling setLocation(double, double) also calls setLocation(int, int) -- why?

Check Yourself

  1. When two or more constructors or methods in the same class have the same name, this is known as ________.
    1. overriding
    2. overloading
    3. overwhelming
    4. not possible
  2. When different constructors or methods have the same name, they must have different ________.
  3. Of the following methods within a single class, ________ and ________ cannot compile together.
    1. public int foo(int a)
    2. public int foo(int a, int b)
    3. public int foo(double a)
    4. public int foo(double a, double b)
    5. public int foo(int b)

9.1.5: More About this

  • Remember from lesson 6.2.3 that the keyword this means this current object
  • Sometimes the keyword this is used to avoid a problem known as shadowing

Shadowing

  • Recall our discussion of shadowing in lesson 7.2.5
  • Shadowing is when a local variable or parameter has the same name as a member variable of a class
  • Local variables or parameters with same name as a member variable hide the member variable
  • Hiding means that the member variable is ignored and the local variable is used
  • One way to solve the hiding problem is to use the keyword this
  • For example, look at the following constructor from SmoothMover:
    private Vector velocity;
    // ....
    public SmoothMover(Vector velocity)
    {
        this.velocity = velocity;
    }
    
  • What happens if we remove the keyword this?
  • The problem is that velocity is both the name of a member variable and parameter
  • We should avoid giving the same name to both member variables and parameters
  • If we feel they must be the same, then we use this to clarify which variable is the instance variable

Another Use for this

  • Recall our discussion on chaining constructors in lesson 7.4.5
  • Notice the other constructor from SmoothMover:
    public SmoothMover()
    {
        this(new Vector());
    }
    
  • The body of the constructor has code that looks like a method call: this(new Vector())
  • However, the code uses the keyword this as the name of a method
  • What is happening is that this() calls another constructor in the same class
  • Java matches the constructor based on the types of the parameters
  • Note that if this() is used, it must be the first statement within a constructor

Check Yourself

  1. The problem with the following code is ________.
    private int bar;
    public void foo(int bar)
    {
        bar = bar;
    }
    
  2. Two ways to correct the above problem are ________ and ________.
  3. In the following code, this() is used to ________.
    public Baz()
    {
        this(42);
    }
    

Exercise 9.1: Explore Newton's Lab (12m)

In this exercise, we explore the new concepts in our scenario. As we do, you will need to record all the stated questions and their answers in a text file using a text editor.

Specifications

  1. Using a text editor, like TextPad, create a text file named questions.txt and copy the questions listed below into the file as you come to them. Also, record answers to all the questions in the file under the question.
  2. Download the Newtons-Lab-2 scenario file, save it to a convenient location like the Desktop and unzip the file.

    Scenario file: Newtons-Lab-2.gfar.

  3. Double-click the project.greenfoot file in the unzipped folder to start Greenfoot and open the scenario.
  4. Run the scenario and remember how it operates by trying out the three initializing methods:
    • sunAndPlanet()
    • sunAndTwoPlanets()
    • sunPlanetMoon()
  5. Locate the SmoothMover class and try to create a new SmoothMover object.

    Q1: Were you able to construct an object?

  6. Open the editor for the SmoothMover class and remove the word abstract from the class signature:
    public abstract class SmoothMover extends Actor
    
  7. Try to compile the modified SmoothMover class.

    Q2: Were you able to construct an object after removing the abstract keyword?

    Q3: Why would you declare a class abstract?

  8. Restore the SmoothMover class to its original condition.

    Compile the class and verify there are no errors. Resolve any errors you find, getting help from a classmate or the instructor as needed.

  9. Examine the code for the SmoothMover class and find all the overloaded constructors and methods.

    Q4: Which constructors and methods were overloaded (list their names)?

    For more information see lesson: 9.1.4: Overloading Constructors and Methods.

  10. In the SmoothMover class, find the following code in the first constructor:
    this.velocity = velocity;
    

    Change the code by removing the "this." so it looks like:

    velocity = velocity;
    
  11. Compile and run the scenario to see how it changed.

    Q5: What error did you see?

    Q6: Why did this error occur?

    Hint: remember that null means "no object" and Java initializes instance variables to null when the variable is a reference (class) type.

  12. Restore the SmoothMover class to its original condition.

    Compile the class and verify there are no errors. Resolve any errors you find, getting help from a classmate or the instructor as needed.

  13. Review your questions.txt file answers with another student in the class and correct any mistakes.
  14. Add a comment to the top of the file that contains the name of the person with whom you reviewed the questions, like:
    Reviewed with Jane Programmer
    
  15. Save the questions.txt file so you can submit it to Canvas as part of assignment 6.

As time permits, be prepared to answer the Check Yourself questions in the section: 9.1.6: Review.

9.1.6: Review

  • In this lesson we looked at the Newton's Lab Scenario
  • We started by looking at vectors, which is a geometric object with both direction and length (magnitude)
  • After vectors we looked at the SmoothMover class as a way to control movement of actors to partial pixels.
  • The technique is to store the location in variables of type double:
    private double exactX;
    private double exactY;
    
  • As the actor moves, SmoothMover updates and stores its location in these two variables
  • To position the actor, SmoothMover translates the floating-point numbers to integer values as needed by the display screen
    super.setLocation((int) exactX, (int) exactY);
    

Answer these questions to check your understanding. You can find more information by following the links after the question.

  1. Reducing a concept or idea to the most simple or basic shared characteristics is known as ________________. (9.1.1)
  2. True or false: All abstractions are composed in abstract classes. (9.1.1)
  3. To make a class from which you cannot instantiate an object use the keyword _________. (9.1.1)
  4. A geometric object with both direction and length is called a(n) _________. (9.1.2)
  5. Specifying a vector using direction and length is known as __________ representation. (9.1.2)
  6. Specifying a vector as a pair of distances (dx, dy) is known as __________ representation. (9.1.2)
  7. Which of the following is a valid declaration of a floating-point variable: (9.1.3)
    1. double scoop;
    2. float boat;
    3. int double;
    4. totally double;
  8. True or false: Of the two floating point types, the type you should normally use is double. (9.1.3)
  9. When adding an int and a double together, the resulting number is of type: (9.1.3)
    1. double
    2. int
    3. float
    4. that depends on the number
  10. When different constructors or methods have the same name they are said to be __________________. (9.1.4)
  11. Within a single class, which of the following methods can exist at the same time? (9.1.4)
    1. public int foo(int a)
    2. public int foo(int a, int b)
    3. public int foo(double a)
    4. public int foo(double a, double b)
    5. public int foo(int b)
  12. Which is an example of overloading the method that follows? (9.1.4)
    public int calcValue(double number) {...}
    
    1. public double calcValue(double number) {...}
    2. int calcValue(double num) {...}
    3. int calcValue(double number, int value) {...}
    4. All of these
  13. True or false: Shadowing is when a local variable or parameter has the same name as a member variable of a class. (9.1.5)
  14. What are two ways to avoid shadowing? (9.1.5)
  15. True or false: the following code calls another constructor in the same class: (9.1.5)
    public SmoothMover()
    {
        this(new Vector());
    }
    

9.2: Applying Forces

Learner Outcomes

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

  • Write psuedocode to describe algorithms.
  • Write method stubs.
  • Write code to work with lists in Java.
  • Write enhanced for loops to process items in a list.

9.2.1: How a Body Moves

  • In this section we continue working with the Newton's Lab scenario:

    Scenario file: Newtons-Lab-2.gfar.

  • The class SmoothMover has two variables to smoothly track the position of a subclass
    private double exactX;
    private double exactY;
    
  • In addition, SmoothMover has a Vector that determines the amount and direction to move
    private Vector velocity;
    
  • By changing the velocity vector, we can move smoothly -- even in a circle
  • The move() method of SmoothMover updates and sets the location of the subclass
    public void move()
    {
        exactX = exactX + velocity.getX();
        exactY = exactY + velocity.getY();
        super.setLocation((int) exactX, (int) exactY);
    }
    
  • The act() method in the Body subclass calls the move() method of SmoothMover
    public void act()
    {
        applyForces();
        move();
    }
    
  • However, before the body moves we must apply the gravitational forces of all the other bodies in space
  • We need to develop code to apply the forces

Algorithms and Psuedocode

  • When faced with a computational problem like this we develop a computer algorithm to solve it

    Computer algorithm: Precise instructions for a computer to follow to accomplish a task.

  • In other words, we must develop a procedure for the computer to follow in solving the problem
  • A common approach is to use psuedocode to describe the solution
  • We discussed psuedocode in lesson 4.2.7
  • Psuedocode is an informal description of the steps for solving a problem
  • Rather than worrying about details of syntax, we use a mixture of English and Java to write the solution in a code-like way
  • For example, here is a psuedocode description of the solution to the problem

Psuedocode Description of an Algorithm to Apply Gravity

Apply forces from other bodies:
   get all other bodies in space;
   for each of those bodies:
      apply gravity from that body to our own;

Check Yourself

  1. A list of precise instructions to accomplish a task is called a(n) ________.
  2. The advantage of using psuedocode, instead of Java code, to describe an algorithm is we can omit the ________ details.
  3. The line of the above psuedocode that describes a loop is ________.
  4. Use psuedocode to describe the algorithm for the move() method.
    public void move()
    {
        exactX = exactX + velocity.getX();
        exactY = exactY + velocity.getY();
        super.setLocation((int) exactX, (int) exactY);
    }
    

    One possible answer

9.2.2: Implementing the applyForces Algorithm

  • Once we have worked out the algorithm to solve the problem, we need to translate the psuedocode into computer code
  • We start by writing a method stub, like:
    private void applyForces()
    {
    
    }
    
  • A method stub is a syntactically correct method with few or no program statements inside the method
  • We add method stubs to our code as a placeholder until we write the method body
  • If a return value is required, a method stub just returns a "dummy" fixed value like 0 or null
  • Since our particular method stub has a void return type, we do not need a return statement
  • After adding a method stub, our code should compile
  • Another thing to notice is that the method is private
  • Mark a method private when it is not intended for use outside the class
  • When a method is intended for use outside the class, mark it public

Implementing the Algorithm

  • One way to implement algorithms is to write them into our code as comments like:
    //Apply forces from other bodies:
    private void applyForces()
    {
       //get all other bodies in space;
       //for each of those bodies:
          //apply gravity from that body to our own;
    }
    
  • Then we refer to the comment as we translate the algorithm to code
  • When we are finished, we can remove the comments
  • Usually we only keep the comments if the algorithm is tricky

Finding All the Bodies

  • Our first task is to get all the bodies in Space
  • Since Space is a subclass of World, we look in the World documentation to see how to get access
  • The most promising method is getObjects(), which returns a list of all objects in the world (or space)
    java.util.List getObjects(java.lang.Class cls)
    
  • The parameter is of type Class, which allows us to restrict the output to a certain class of objects like Body
  • We saw this type of parameter before in lesson 2.4.3
  • To call the method, we add a ".class" to the name of the class, like:
    getObjects(Body.class)
    
  • If we want all types of objects, then we use the special keyword null as the parameter:
    getObjects(null)
    
  • Remember that null means "no object"
  • We can only call the getObjects() method with a World object
  • To obtain the World object, we call the getWorld() method of Actor:
    getWorld().getObjects(Body.class)
    
  • The return type of getObjects() is a List, which implies there is a List type in Java
  • We will look at List in the next section

Check Yourself

  1. A method ________ is just enough code to allow the method to compile.
  2. True or false: we add method stubs to our code as a placeholder until we write the method body.
  3. The keyword null means no ________.
  4. True or false: mark a method private if it should not be called outside the class.
  5. Rewrite the following code in one statement rather than two:
    World w = getWorld();
    List<Actor> bodies = w.getObjects(Body.class);
    

    answer

9.2.3: Exploring Lists

  • When we work with collections of items, a natural approach is to use a list
  • We have used lists before when working with arrays in lesson 7.3.5
  • Also, we worked with the List type in lesson 8.1.4
  • Java has several other ways for working with lists of data including:
    • ArrayList: resizable arrays
    • LinkedList: nodes grouped to make a sequence
    • Stack: last-in-first-out (LIFO) sequence of items
  • These list types shown above have a common supertype called List
  • Different list types have characteristics that make them better choices in certain applications
  • For example, Greenfoot has chosen a list type to keep track of actors added to a world
  • We do not know, or need to know, what list type Greenfoot has chosen
  • However, we need to work with the List type to make use of some Greenfoot features

List Types

  • The Greenfoot feature we are interested in using is getObjects()
  • Method getObjects() of the World class gets a list of all the objects in the world
  • Since getObjects() returns a List, we look at the Java API for List
  • When we examine the API, we see that List is an interface and not a class
    Interface List<E>
  • The List interface is a way for Java to specify a common set of methods for many different list classes
  • Which underlying list class the getObjects() method returns is not important
  • We just use the methods of the List interface as a common abstraction of the list classes
  • The following are some commonly used methods of List

Some Commonly Used Methods of List

Method Description
add(item) Adds the specified item to the end of the list.
add(index, item) Adds the specified item at the specified index of the list.
get(index) Retrieves the item at the specified index in the list.
remove(index) Removes the item at the specified index in the list.
set(int index, item) Replaces the item at the specified index in the list.
size() Returns the number of items in the list.

Generic Types

  • Let us look at the description of the list interface again:
    Interface List<E>
  • Notice the <E> after the word List
  • This is known as a generic type
  • When we use a generic type, we must include a data type inside the angle brackets: <E>
  • The "E" is a place holder name and is like a parameter for the data type
  • The actual type we want to store in the list is substituted for the "E"
  • For example, if we had a list of strings we would declare a list like:
    List<String> names;
    
  • Notice that the class name "String" replaced the "E" in the type name
  • In our case we have a list of Body objects and declare a list like:
    List<Body> bodies;
    
  • Since we are getting a list from the getObjects() method we write:

    List<Body> bodies = getWorld().getObjects(Body.class);

Check Yourself

  1. To add an item to a List, call the method ________.
  2. To remove an item to a List, call the method ________.
  3. To find out how many items a List contains, call the method ________.
  4. Write an assignment statement that declares a variable names and calls the following method, saving the returned value in the variable.
    List<String> getNames() { /* ... */ }
    

    answer

9.2.4: Applying Gravitational Forces

  • Recall our algorithm for applying gravity:
    Apply forces from other bodies:
       get all other bodies in space;
       for each of those bodies:
          apply gravity from that body to our own;
    
  • We now have a list of all the bodies in Space to implement our algorithm

    List<Body> bodies = getWorld().getObjects(Body.class);

  • We now need to apply gravity from each body to our current body
  • We do this by going through the list of bodies one by one and apply the force in turn
  • If the force is from our current body, we skip applying the force
  • We can step through each item in a list using a loop as shown below

Method applyForces()

private void applyForces()
{
    List<Body> bodies = getWorld().getObjects(Body.class);
    for (Body body : bodies)
    {
        if (body != this)
        {
            applyGravity (body);
        }
    }
}

Enhanced for Loop

  • Notice the for-loop in the above code
  • The loop is the enhanced for loop we discussed in lesson 8.1.5
  • Officially this loop is known as the enhanced for loop
  • However, most people call this loop the for-each loop
  • The for-each loop is specially designed to work with lists of data, including arrays
  • It reads each item in a list and provides a variable of the list item type to work with
  • Syntax:
    for (itemType variableName : listName) {
        // statements to execute
    }
    
  • Where:
    • itemType: the data type of all the list items
    • variableName: the name to use for each variable
    • listName: the name of the list
  • Note that we do not code initialization, test and increment statements
  • Instead, we declare a variable that refers to each array element
  • Within the loop, we use this variable to access each array element
  • For comparison we rewrite the applyForces() method using a standard for loop

Comparison of applyForces() with a Standard for Loop and a for-each Loop

private void applyForces()
{
    List<Body> bodies = getWorld().getObjects(Body.class);
    for (int i = 0; i < bodies.size(); i++)
    {
        Body body = bodies.get(i);
        if (body != this)
        {
            applyGravity (body);
        }
    }
}
private void applyForces()
{
    List<Body> bodies = getWorld().getObjects(Body.class);
    for (Body body : bodies)
    {
        if (body != this)
        {
            applyGravity (body);
        }
    }
}

Try It: Write an Enhanced for-Loop (5m)

  1. Download the following scenario file, save it to a convenient location like the Desktop and unzip the file.

    Scenario file: Newtons-Lab-2.gfar.

  2. Double-click the project.greenfoot file in the unzipped folder to start Greenfoot and open the scenario.
  3. Open the editor for the Space class and add the following import statement at the top.
    import java.util.List;
    
  4. Next, add a listBodies() method to the Space class:
    public void listBodies()
    {
        List<Body> bodies = getObjects(Body.class);
        for (int i = 0; i < bodies.size(); i++)
        {
            Body body = bodies.get(i);
            System.out.println(body);
        }
    }
    

    When we call this method, it will list all the Body objects on the terminal screen.

  5. Test listBodies() method by:
    1. Right-clicking the world background and selecting one of the methods to populate the world, like sunAndPlanet().
    2. Right-clicking the world background and selecting the listBodies() method

    The Terminal window should display a list of Body objects like:

    Body@76f16233
    Body@6134825b
    
  6. Change the regular for-loop to the enhanced for-loop and retest your code.
    for (Body body : bodies)
    {
        System.out.println(body);
    }
    

    Do you see any changes between the two for-loops?

  7. Save your updated scenario as we will be adding to it in the next exercise.
  8. Be prepared to answer the following Check Yourself questions when called upon.

Check Yourself

  1. In the applyForces() method, this (shown below) refers to the ________ Body object.
    if (body != this)
  2. True or false: The method applyForces() applies gravity from every object in Space to the current object
  3. Rewrite the following loop using an enhanced for loop:
    int[] scores = {90, 95, 87, 89, 98};
    for (int i = 0; i < scores.length; i++)
    {
        System.out.println(scores[i]);
    }
    


    Example answer

  4. True or false: the for-each loop typically requires less code to write.

9.2.5: Calculating Gravity

  • We have solved the problem of accessing each object in space
  • However, we still have not applied the actual gravitational force
  • We apply gravity in the applyGravity() method
    private void applyGravity(Body other)
    

About Gravity

  • Gravity is a force of attraction between objects with mass
  • Newton's famous formula for gravity is shown in the following image from Wikipedia:

    F=G(m1 x m2)/r^2

  • Where:
    • F: the force between the masses
    • G: the gravitational constant
    • m1: mass of the first body
    • m2: mass of the second body
    • r: distance between the masses
  • The complete applyGravity() method follows

Method applyGravity()

private void applyGravity(Body other)
{
    double dx = other.getExactX() - this.getExactX();
    double dy = other.getExactY() - this.getExactY();
    Vector dv = new Vector(dx, dy); //sets direction; length to be done
    double distance = Math.sqrt(dx * dx + dy * dy);
    double force = GRAVITY * this.mass * other.mass / (distance * distance);
    double acceleration = force / this.mass;
    dv.setLength(acceleration);
    addToVelocity(dv);
}

Notes on the Code

  • The first two lines calculate the x and y distances between each object
  • Then the code creates a new vector using these values
  • The vector has the correct direction but not the correct length (distance)
  • We calculate the correct length using the Pythagorean theorem:

    a2 + b2 = c2

  • The image below from the textbook (p. 148, 1/e: p. 94) shows the calculation
  • To calculate the square root, we use the Math.sqrt() method from the Java Math class
    double distance = Math.sqrt (dx * dx + dy * dy);
    
  • The next line calculates the strength of the force using Newton's formula
  • The last task is to calculate the acceleration given by Newton's second law of motion:
    F = ma  or  a = F / m
  • This acceleration is used to set the length of the vector force, which is added to the body

Distance in Relation to dx and dy

a^2 + b^2 = c^2

Methods of the Java Math Class

Name Description Example Result
abs absolute value Math.abs(-3.9)
Math.abs(3.9)
3.9
3.9
log natural log Math.log(10.0) 3.20...
pow powers Math.pow(2.0, 3.0) 8.0
sqrt square root Math.sqrt(4.0) 2.0

Check Yourself

  1. ________ is a force of attraction between objects with mass.
  2. True or false: the numbers in applyGravity() need to be type double so they are precise.
  3. The Math.sqrt() method has ________ parameter(s).
  4. If a planet moves 30 miles east and 40 miles north in one hour, its vector is ________
    1. 30 miles per hour northeast
    2. 40 miles per hour northeast
    3. 50 miles per hour northeast
    4. 30 miles per hour east and 40 miles per hour north

Exercise 9.2: Experimenting with Force (10m)

In this exercise, we experiment with how changes in GRAVITY, mass and initial velocity of the bodies affect the stability of the system.

Specifications

  1. Using a text editor, like TextPad, create a text file named settings.txt to record your best settings for the following:
    1. GRAVITY in Body
    2. Mass, direction, velocity for both bodies in the sunAndPlanet() method
    For example, from the initial values:
    GRAVITY = 5.8
    mass1 = 240.0
    direction1 = 270
    velocity1 = 0.03
    mass2 = 4.2
    direction2 = 90
    velocity2 = 2.2
    
  2. Start Greenfoot and open the Newton's Lab 2 scenario from the last exercise. If you did not save it, you can download it again:

    Scenario file: Newtons-Lab-2.gfar.

  3. Run the scenario and remember how it operates by trying out the three initializing methods:
    • sunAndPlanet()
    • sunAndTwoPlanets()
    • sunPlanetMoon()
  4. Change the gravity constant at the top of the Body class and see what happens.
    private static final double GRAVITY = 5.8;
    

    Try changing GRAVITY by 1/2, doubling it, changing it by 1 and by 0.1.

  5. Choose your best value for GRAVITY and record it in your settings.txt file. Then recompile and run the scenario to verify it works well.

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

  6. Open the Space class and experiment with changes to the mass or initial velocity of the bodies in sunAndPlanet():
    addObject(new Body (20, 4.2, new Vector(90, 2.2), ...);
    //                       |               |   |
    //                      mass      direction  speed
    

    When experimenting you should change only one variable at a time.

    Note that you may find it challenging to find a stable system. If so, you may want to read the Wikipedia article: Stability of the Solar System.

  7. Choose your best values for the mass, direction and velocity (velocity) for both objects and record them in your settings.txt file.
  8. Save a copy of your settings.txt file to submit to Canvas as part of assignment 6.

When finished, please help those around you.

9.2.6: Review

  • In this lesson we looked at the SmoothMover class as a way to control movement of actors to partial pixels.
  • The technique is to store the location in variables of type double:
    private double exactX;
    private double exactY;
    
  • As the actor moves, SmoothMover updates and stores its location in these two variables
  • To position the actor, SmoothMover translates the floating-point numbers to integer values as needed by the display screen
    super.setLocation((int) exactX, (int) exactY);
    
  • We then looked at how to simulate gravitation forces on actors
  • To develop our simulation, we used psuedocode to develop a computer algorithm

    Computer algorithm: Precise instructions for a computer to follow to accomplish a task.

  • As an example, we looked at the following psuedocode

Psuedocode Description of an Algorithm to Apply Gravity

Apply forces from other bodies:
   get all other bodies in space;
   for each of those bodies:
      apply gravity from that body to our own;
  • After development, we translated the algorithm from psuedocode to Java code
  • We started by writing a method stub
  • The method stub allows us to compile our program as we translate the psuedocode
  • After developing the stub, we put the psuedocode in comments to make the translation easier
  • Our next step is to translate each statement to Java code

Method Stub with Psuedocode

//Apply forces from other bodies:
private void applyForces()
{
   //get all other bodies in space;
   //for each of those bodies:
      //apply gravity from that body to our own;
}

Check Yourself

Answer these questions to check your understanding. You can find more information by following the links after the question.

  1. What is an algorithm? (9.2.1)
  2. Why do people use psuedocode to describe an algorithm? (9.2.1)
  3. Use psuedocode to describe the algorithm for the following method:
    public void move()
    {
        exactX = exactX + velocity.getX();
        exactY = exactY + velocity.getY();
        super.setLocation((int) exactX, (int) exactY);
    }
    
  4. Write a method stub for an algorithm that gets two numbers, adds them together and returns their sum. (9.2.2)
  5. What is the special word that means, "no object"? (9.2.2)
  6. What line or lines of code will get all the Body objects from within the Body class? (9.2.2)
  7. What methods of the List interface add items to a list? (9.2.3)
  8. What method of the List interface removes items from a list? (9.2.3)
  9. What methods of the List interface finds out how many items are in a list? (9.2.3)
  10. Write a statement that calls the following method and saves the returned value in the variable names: (9.2.3)
    List<String> getNames() { /* ... */ }
    
  11. What does this refer to in the following method? (9.2.4)
    private void applyForces()
    {
        List<Body> bodies =
            getWorld().getObjects(Body.class);
        for (Body body : bodies)
        {
            if (body != this)
            {
                applyGravity (body);
            }
        }
    }
    
  12. Rewrite the following loop using an enhanced for loop: (9.2.4)
    int[] scores = {90, 95, 87, 89, 98};
    for (int i = 0; i < scores.length; i++)
    {
        System.out.println(scores[i]);
    }
    
  13. Which loop requires less code to write: standard or enhanced for loop? (9.2.4)
  14. ____________ is a force of attraction between objects with mass. (9.2.5)
  15. Write a statement that computes the square root of 42. (9.2.5)

9.3: Projectile Motion

Learner Outcomes

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

  • Create a projectile animation.
  • Write code to detect collisions between objects.

9.3.1: Creating a Side-View World

  • Gravity is an important effect in may scenarios
  • Whenever we have creature that walk, jump, throw things or fire projectiles, we need gravity
  • In this section we explore how to fire projectiles using a cannon
  • The same techniques can be used for any projectile: from slingshots to monkeys throwing bananas
  • Lets download and unzip the following starter scenario:

    Scenario file: cannon-lesson.gfar.

  • Download the file to a convenient location like the Desktop and double-click the file to start the project

Creating the World

  • For this scenario we want a side-view world
  • At the bottom of the world we will have a ground for actors to walk and rest upon
  • We construct our ground using a simple tile image:

    ground tile

  • The image does not cover the world so we will need to place the image in multiple places
  • We can place the tiles easily with a loop
  • Since the tile width is 32 pixels, we space the ground tiles using the tile width
  • First we code a method setup(), which is called from the constructor
  • Then we place the following loop in the setup method

Loop to Place Ground Tiles

for (int i = 0; i < 19; i++)
{
    int x = i * 32 + 16;
    int y = GROUND_HEIGHT + 16;
    addObject(new Ground(), x, y);
}

Placing Targets

  • In addition to the ground, we place a few targets on the ground
  • The targets give the projectile something to aim at
  • We place the targets in the world using code like the following:
    addObject(new Target(), 310, GROUND_HEIGHT - 22);
    addObject(new Target(), 530, GROUND_HEIGHT - 22);
    

Try It: Create a Side-view World (5m)

  1. Download the following scenario file, save it to a convenient location like the Desktop and double-click the file to start the project.

    Scenario file: cannon-lesson.gfar

  2. Open the editor for the CannonWorld class, add a method named setup() and call the setup() method from the constructor.
  3. In the setup() method, add the following statements inside the constructor:
    for (int i = 0; i < 19; i++)
    {
        int x = i * 32 + 16;
        int y = GROUND_HEIGHT + 16;
        addObject(new Ground(), x, y);
    }
    
  4. Next, add a few targets to the world using the addObject() method like:
    addObject(new Target(), 310, GROUND_HEIGHT - 22);
    
  5. Save your updated scenario as we will be adding to it in the next exercise.

9.3.2: Projectiles and Gravity

  • In this section we develop the projectile to throw
  • We start by making a Cannonball class as a subclass of SmoothMover
    • Notice the capital "C" on cannonball
    • To look professional, all class names should start with a capital letter in Java
  • The SmoothMover superclass ensures smooth moving of our projectile

The Flight of the Cannonball

  • Projectiles are objects which have only a gravity force acting on them
  • For our example we will use a cannonball:

    Cannonball projectile

  • We track the flight of the cannonball by using a velocity vector of the SmoothMover superclass
    private Vector velocity;
    
  • We specify gravitational force by defining a vector in CannonWorld
    public static final Vector GRAVITY = new Vector(0.0, 0.2);
    
  • As the ball travels we apply the force of gravity in the Cannonball class
    addToVelocity(CannonWorld.GRAVITY);
    
  • Each game cycle increases the downward movement on the projectile as shown in the following diagram

Vector Parabola due to Gravity

vector parabola due to gravity

Making a Cannonball Projectile

  • There are several interesting code bits to the Cannonball class
  • First we add two constructors to the Cannonball class
    public Cannonball()
    {
        this(new Vector(-45, 6));
    }
    
    public Cannonball(Vector velocity)
    {
        super(velocity);
    }
    
  • In addition we override the addedToWorld() method of Actor
    @Override protected void addedToWorld(World world)
    {
        setLocation(getX(), getY());
    }
    
  • Overriding a superclass method allows Java to use the subclass method instead of the superclass method
  • By overriding the addedToWorld() method, we make sure our cannonball is positioned correctly when added to the world
  • Overriding the addedToWorld() method is necessary because SmoothMover is tracking the (x, y)-coordinates with exactX and exactY
  • Notice that when we override a method, common practice is to add an @Override annotation
  • Adding the annotation makes the compiler verify we actually overrode a something
  • To finish the flight of the cannonball, we update the act() method
    public void act()
    {
        addToVelocity(CannonWorld.GRAVITY);
        move();
    }
    
  • Before the cannonball moves, we apply the force of gravity
  • Applying gravity makes our cannonball move like a projectile

Try It: Make a Projectile (4m)

  1. Start Greenfoot and open the Cannon scenario from the last Try It.
  2. Create a Cannonball class as a subclass of SmoothMover and using the cannon_ball.png image.
  3. Open the editor for the Cannonball class and add the following constant:
    private static final int GROUND_HEIGHT = CannonWorld.GROUND_HEIGHT - 6;
    
  4. in addition, add the following two constructors:
    public Cannonball()
    {
        this(new Vector(-45, 4));
    }
    
    public Cannonball(Vector velocity)
    {
        super(velocity);
    }
    
  5. Also, override the addedToWorld() method of Actor to set the location in SmoothMover
    @Override protected void addedToWorld(World world)
    {
        setLocation(getX(), getY());
    }
    
  6. Compile the scenario to ensure you added the changes correctly.
  7. In the act() method of Cannonball, add the following code:
    addToVelocity(CannonWorld.GRAVITY);
    move();
    
  8. Again, compile the scenario to ensure you add the changes correctly.
  9. Test the cannonball by adding one to the world and pressing the Run button.
  10. Save your updated scenario as we will be adding to it in the next exercise.

9.3.3: Shooting a Cannon

  • With our world established, we now add an actor to launch projectiles
  • For our example we will use a cannon

    projectile thrower

Adding a Cannon

  • We add a Cannon class to our scenario
    • Notice the capital "C" on cannon
    • To look professional, all class names should start with a capital letter in Java
  • In the act() method of the cannon, we add controls for aiming the cannon:
    if(Greenfoot.isKeyDown("up")) {
        turn(-1);
    }
    if(Greenfoot.isKeyDown("down")) {
        turn(+1);
    }
    if ("space".equals(Greenfoot.getKey()))
    {
        fire();
    }
    
  • Notice the test condition of the last if-statement:
    "space".equals(Greenfoot.getKey())
    
  • This condition makes sure the cannon fires only once per keypress
  • We then add a method stub for the fire() method
    private void fire()
    {
        // Add projectile throwing code here
    }
    
  • We then compile the scenario to ensure we added the changes correctly.

Throwing the Projectile

  • In the fire() method we add code to throw the projectile
    Greenfoot.playSound("fire.wav");
    int angle = getRotation() - 36; // adjust angle for image
    Cannonball ball = new Cannonball(new Vector(angle, 9));
    getWorld().addObject(ball, getX(), getY());
    ball.setRotation(angle);
    ball.move(42); // clear the cannon barrel
    
  • Within the method we calculate the angle of the cannon
    int angle = getRotation() - 36; // adjust for image
    
  • This allows us to make sure the cannonball clears the cannon barrel by:
    1. setting the rotation of the cannonball
    2. moving the cannonball forward enough to clear the cannon barrel
  • Once we create the cannon, we add one to the world
    addObject(new Cannon(), 60, GROUND_HEIGHT - 24);
    

Try It: Add a Cannon (5m)

  1. Start Greenfoot and open the Cannon scenario from the last Try It.
  2. Add a cannon to the world using the cannon image.
  3. In the act() method of Cannon, add the following code:
    if(Greenfoot.isKeyDown("left")) {
        turn(-1);
    }
    if(Greenfoot.isKeyDown("right")) {
        turn(+1);
    }
    
  4. In addition, add code to move the cannon left or right along the ground, no matter the rotation of the cannon.

    For more information, see 2.2.5: Actor Movement Methods and 3.5.2: Using Strings to Specify Key Presses. Notice that move() does not work when the cannon is rotated. Thus you will need to use setLocation().

  5. Now add code to the act() method for firing the cannon.
    if ("space".equals(Greenfoot.getKey()))
    {
        fire();
    }
    
  6. Add a method stub for the fire() method
    private void fire()
    {
        // Add projectile throwing code here
    }
    
  7. Compile the scenario to ensure you added the changes correctly.
  8. Add the projectile throwing code to the fire() method:
    Greenfoot.playSound("fire.wav");
    int angle = getRotation() - 36; // adjust angle for image
    Cannonball ball = new Cannonball(new Vector(angle, 9));
    getWorld().addObject(ball, getX(), getY());
    ball.setRotation(angle);
    ball.move(42); // clear the cannon barrel
    
  9. Again, compile the scenario to ensure you added the changes correctly.
  10. Add the Cannon to the world in the CannonWorld method setup()
    addObject(new Cannon(), 60, GROUND_HEIGHT - 26);
    
  11. Compile and run the scenario to ensure you made the changes correctly.
  12. Save your updated scenario as we will be adding to it in the next exercise.

9.3.4: Hitting the Ground

  • When our projectiles hit the ground, they just keep going
  • Then the projectile reaches the bottom of the screen and just rolls to the corner
  • A better strategy is to have cannonballs disappear when they hit the ground
  • Also, if the cannonball goes off screen, it should disappear
  • We can use the isTouching() and isAtEdge() methods to test for these conditions
  • Then we can remove the cannonballs from the world
  • The following code placed in the act() method of Cannonball will perform the actions we need

Code in act() for Ground Collision

if (isTouching(Ground.class) || isAtEdge())
{
    CannonWorld world = (CannonWorld) getWorld();
    world.removeObject(this);
}

Try It: Add Collision Detection for Hitting the Ground (2m)

  1. Start Greenfoot and open the Cannon scenario from the last Try It.
  2. Open the editor for the Cannonball class.
  3. Add the following code to the end of the act() method
    if (isTouching(Ground.class) || isAtEdge())
    {
        CannonWorld world = (CannonWorld) getWorld();
        world.removeObject(this);
    }
    
  4. Compile the scenario to ensure you added the changes correctly.
  5. Test your changes by firing the cannon such that the cannonball hits the ground.
  6. Save your updated scenario as we will be adding to it in the next exercise.

9.3.5: Hitting Targets

  • We want something to happened when our projectile hits its target
  • If a cannonball hits a target, it would likely destroy the target
  • We can add a method to react when a projectile hits a target

Method checkHitTarget() of Cannonball

private void checkHitTarget() {
    // To react to only one type (like Enemy) change Actor to that type
    Actor target = getOneIntersectingObject(Target.class);
    if (target != null)
    {
        CannonWorld world = (CannonWorld) getWorld();
        world.removeObject(target);
        world.removeObject(this);
        return; // in case of multiple if statements
    }
}

Method getOneIntersectingObject()

  • We call the method getOneIntersectingObject() because it returns the actor we hit
    Actor target = getOneIntersectingObject(Target.class);
    
  • In our example, the actor is a Target object
  • By saving the Target object in a reference variable, we have access to its methods
  • For example, we can call the actor's getX() and getY() methods
  • If we wrote a custom method, such as hit(), we can call the custom method as well
  • Thus, getOneIntersectingObject() provides more options than the easier isTouching() and removeTouching() methods
  • Note that getOneIntersectingObject() returns null if it is not touching another object
  • This means we need to check that the target is not null before calling methods of the target object
    if (target != null)
    {
        // do something with target
    }
    

When to Call checkHitTarget()

  • We want to call checkHitTarget() when the projectile is flying
  • However, if a cannonball is already removed from the world, then we cannot call checkHitTarget()
  • If we call checkHitTarget() when the cannonball is not in the world, we get a runtime error

    java.lang.IllegalStateException: Actor not in world. An attempt was made to use the actor's location while it is not in the world. Either it has not yet been inserted, or it has been removed.

  • We want to call checkHitTarget() only if the cannonball was not removed from the world
  • We can ensure this condition by using an if-else statement as shown below

Method act() Calling checkHitTarget()

public void act()
{
    addToVelocity(CannonWorld.GRAVITY);
    move();
    if (isTouching(Ground.class))
    {
        CannonWorld world = (CannonWorld) getWorld();
        world.removeObject(this);
    }
    else // only if the cannonball is still in the world
    {
       checkHitTarget();
    }
}

Try It: Add Collision Detection for Hitting a Target (4m)

  1. Start Greenfoot and open the Cannon scenario from the last Try It.
  2. Open the editor for the Cannonball class.
  3. Add the following method to check for target collisions:
    private void checkHitTarget() {
        Actor target = getOneIntersectingObject(Target.class);
        if (target != null)
        {
            CannonWorld world = (CannonWorld) getWorld();
            world.removeObject(target);
            world.removeObject(this);
            return; // in case of multiple if statements
        }
    }
    
  4. Compile the scenario to ensure you added the changes correctly.
  5. Add an else-clause to the end of the if-statement in the act() method
    else // only if the cannonball is still in the world
    {
       checkHitTarget();
    }
    
  6. Compile the scenario to ensure you added the changes correctly.
  7. Test your changes by firing the cannon such that the cannonball hits a target.

    The target should disappear.

  8. Save your updated scenario as we will be adding to it in the next exercise.

9.3.6: Simple Explosions

  • Explosions often add excitement to a game
  • We will go over a simple explosion technique in case you have a game that would benefit from an explosion
  • We start by adding an Explosion class as a subclass of Actor with the explosion1.png image
  • Then we add a constructor to play the explosion sound as shown below

Constructor for Explosion Class

public Explosion()
{
    Greenfoot.playSound("explosion.wav");
}

Processing the Explosion

  • Explosions dissipate over time
  • We add code to the act() method to make the explosion fade over time
  • The fading is controlled by the transparency setting of the image
  • The transparency starts at 255 and diminishes every game cycle
  • When the transparency gets close to zero then we remove the explosion from the world

Method act() of the Explosion Class

public void act()
{
    int alpha = getImage().getTransparency();
    if (alpha > 10)
    {
        getImage().setTransparency(alpha - 10);
    }
    else
    {
        getWorld().removeObject(this);
    }
}

Adding an Explosion in Cannonball

  • Once we have an explosion, we add it to the world when the cannonball hits a target
  • We update the cannonball's checkHitTarget() method to add the explosion as shown below

Updated checkHitTarget() Method in Cannonball

private void checkHitTarget() {
    Actor target = getOneIntersectingObject(Target.class);
    if (target != null)
    {
        CannonWorld world = (CannonWorld) getWorld();
        world.addObject(new Explosion(), target.getX(), target.getY());
        world.removeObject(target);
        world.removeObject(this);
    }
}

Other Applications

  • Note that the explosion technique could be applied whenever a projectile hits an object
  • For example, a tomato projectile may cause a splatter when hitting an object
  • A splatter would be coded similar to an explosion

Try It: Add an Explosion when Hitting a Target (5m)

  1. Start Greenfoot and open the Cannon scenario from the last Try It.
  2. Add an Explosion class as a subclass of Actor with explosion1.png as the image.
  3. Add the following constructor to the Explosion class
    public Explosion()
    {
        Greenfoot.playSound("explosion.wav");
    }
    
  4. Compile the scenario to ensure you added the changes correctly.
  5. To process the explosion, add the following code to the act() method:
    int alpha = getImage().getTransparency();
    if (alpha > 10)
    {
        getImage().setTransparency(alpha - 10);
    }
    else
    {
        getWorld().removeObject(this);
    }
    
  6. Compile and then test the scenario by adding an explosion to the world.
  7. To add an explosion automatically, open the editor for the Cannonball class.
  8. In the Cannonball class, add the following statement to the method checkHitTarget()
    world.addObject(new Explosion(), target.getX(), target.getY());
    
  9. Compile the scenario to verify you added the code in the correct location.
  10. Test your scenario by firing the cannon and watching the pretty explosions.
  11. Save your updated scenario as to submit as part of the next quest.

Exercise 9.3: Projectiles

In this exercise, we experiment with projectile motion.

Specifications

  1. Complete the Try It activities we explored throughout the section including:
    1. Try It: Create a Side-view World
    2. Try It: Make a Projectile
    3. Try It: Add a Cannon
    4. Try It: Add Collision Detection for Hitting the Ground
    5. Try It: Add Collision Detection for Hitting a Target
    6. Try It: Add an Explosion when Hitting a Target
  2. Save a copy of your completed cannon-lesson scenario to upload to Canvas as part of the next lab.

Wrap Up

Due Next:
Q8: Visualize this! (10/26/17)
Lab 9: Asteroids (10/31/17)
Q9: Gravitational Attraction (11/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: November 04 2017 @21:01:25