Saint Louis University |
Computer Science 150
|
Dept. of Math & Computer Science |
The goal of this assignment is to create, document and implement a new class, Ball, which simulates the movement of a ball under the effects of gravity. For this assignment, we will provide all of the other portions of the code, including a driver for gathering input from the user as well as all of the necessary graphics for visualizing the simulation. However you must define and implement the Ball class properly for the simulation to be complete.
For this assignment you must work individually in regard to the design and implementation of your project.
Please make sure you adhere to the policies on academic integrity in this regard.
Your main task is to implement and document a Ball class, described briefly with the following class diagram:
Our software will explicitly rely on each of the above methods, so you must be careful to accurately reflect the given specifications. For most, the desired behavior should be self-evident from the method names. The last method, however, warrants further explanation. Your Ball objects will live in a World which has been created by our part of the software. The World is built as an extension of a Canvas but has additional code which acts as a clock in some sense. For each tick of the clock, the world will call the method update method for each object in the world, sending a reference to the world as a parameter. The behavior of the method for a given object should be to update the state of that particular object for one simulated timestep.
In the case of a Ball you will need to update the position and velocity accordingly. For desired precision, please make sure that you initialize your instance variables to use the float data type (rather than an integer data). When drawn on the screen, the ball's position will actually be rounded to the nearest pixel, but you will still find a more accurate simulation by using floating point calculations to represent the ball internally.
For the sake of completeness, we next review some elementary physics to explain the desired behavior.
Not only do we want a working implementation, but for full credit your code must adhere to the good software practices as described in Chapter 6. Specifically,
Follow the naming conventions of Chapter 6.3
Provide documentation for your class as outlined in Chapter 6.4
Use "private" data attributes, as described in Chapter 6.5
Provide your own Unit Testing within Ball.py, as described in Chapter 6.7.
To be clear, typing python Simulation.py will run the full-blown graphical simulation based on our software. However you should be able to have your code so that typing python Ball.py provides some simple testing of the functionality of your ball implementation. Demonstrate use of all of the basic methods, and perhaps a couple of interesting examples of the update method.
Since that update method depends upon a world, you will need to provide a placeholder for that class which has the simple functionality needed. A simple way is to include the following class definition within your unit test.
class _SimpleWorld: def __init__(self, g): self._gravity = g def getGravity(self): return self._gravity earth = _SimpleWorld(9.8) # instantiate one of these for unit testingYou do not have to worry about properly documenting this class.
position
In real life, the position would be measured in terms of a
unit of of distance such as a meter; here we represent the position in terms
of pixels or fractions thereof. The position of the ball is relative
to the world's coordinate system, namely with the positive
Y-axis oriented downward. For simplicity, we suggest that you
represent the position vector as two separate values, separately
representing the X- and Y-components of the position (though it
would be possible to define a vector class if we wished).
velocity
A velocity is not simply a representation speed, but also of direction
of motion. Therefore, a velocity is also represented by a pair
of coordinates.
In the real world, a velocity might be measured in units
such as meters per second (m/s); in our world, we will
measure velocity in terms of pixels per tick. Therefore, if
a ball had a constant velocity of
gravity
By the law of inertia, in the absence of any outside forces
the velocity would remain unchanged. Yet gravity is such an outside
force. At each clock tick, the gravity does not directly effect the
position of a ball, but it will directly effect the velocity of the
ball.
In general, such a force should also be represented as a vector, and thus have separate X- and Y-coordinates. For simplicity, we assume that gravity in our world is aligned with the Y-axis so that there is only one coordinate. A positive value for the gravity means that balls are being pulled downward (i.e., along the positive Y-axis); in contrast, a negative gravity value would be interpreted as balls being pulled upward.
As for gravity, we felt that it was a more natural model to keep gravity as an attribute of the world rather than of an individual ball. Yet for the ball to be able to update itself, it must be aware of the gravity setting. For this reason, notice that the update(world) method takes the world as a parameter. Though you do not need to fully understand the World class, what is important is that you may call world.getGravity() to get the current setting.
We are providing a driver titled Simulation.py. Your Ball class definition, in isolation, is not a complete program. To test your code, run the simulation program with the command python Simulation.py. Please note, you do not need to understand our part of the sourcecode. In fact, you would be wise not even to read it.
This text-driven software first directs you through a series of questions to define the characteristics of the World. After setting up the world, the driver prompts you to introduce a ball with a given set of initial characteristics. It then simulates the motion of that ball so long as the ball remains in the visible portion of the world. Once the ball leaves the world it is destroyed and the driver will again prompt you to create a new ball.
You should note that our driver intentionally suggests default responses for each question posed, and you may signify that you are willing to accept the default by simply pressing return. This should make it much easier for you to repeat certain tests by a series of accepted defaults.
Notice also that the driver allows you to add a sequence of identical balls to the screen (in a staggered fashion) rather than simply one ball at a time. By using a sequence of balls, you can get a more interesting visual trail of the traveling balls, as shown in the following diagram
You will need to have the file Simulation.py in the same
location in your account as the file Ball.py which you are
expected to write. To copy that file to your own directory, type the
following from the terminal:
If you are working on your own machine, you may download Simulation.py here.
cp ~goldwasser/public/Simulation.py .
You must make sure that you create a file Ball.py which defines the Ball class as described precisely in the earlier diagram.
Ideally, you may as well document your class right away. You know how you want everything to behave, even if you haven't implemented it all.
For the ball to appear properly on the screen, you will already need to use instance variables and to successfully implement the methods to set and get the Ball's position.
Start to implement the update routine, ignoring gravity for the time being. You should use the velocity to control the movement of the ball's position.
Finally, take gravity into account and put everything together.
You should create a new file, Ball.py, which contains all of your own code. This file must be submitted electronically. You should also submit a separate 'readme' text file.
Please see details regarding the submission process from the general programming web page, as well as a discussion of the late policy.
The assignment is worth 10 points. The grade will be based upon evaluation of the correctness of your implementation as well as the quality of your software practices.
We will award one additional point to students who successfully meet the following challenge.
The interface we provided also allows you to add a Star to the world. Adjust your update routine so that the ball is properly affected by the gravity of the Star.
Physics 102:
Incorporating the gravity of a star is more complicated than the gravity of a world, for two reasons. Both the strength of the gravity and the direction of the force depend on the relative position of the ball and the star. For comparison, the gravity of the world was assumed to be a constant force, aligned along the Y-axis, thus of the form (0,g) for some value g. The gravity between the star and a ball should be a vector pointing from the ball towards the star. The magnitude of that force should depending upon the mass of the star and the distance between the center of the ball and the center of the star. Specifically, the magnitude of the force equals the star's mass divided by the square of the distance between the star and ball's centers.
Coding Issues:
There are some additional issues to cope with, though this is extra
credit after all.
For simplicity, at most one star can exist in the world at any given
time. You can query the world to return this star to you through the
method
star = world.getStar();
if star:
// star exists. Add your code here to adapt.
A star's position and mass can be queried through the use of methods getPositionX(), getPositionY() and getMass().
You may find need to compute a square root. A function for computing
a square root is included in the math library of Python. You
may use it by stating
If you have everything implemented correctly and use the default parameters for the extra credit, you will get an orbit as shown in the following figure