This assignment is a sequel to the Ball assignment. Our driver has added four walls into the World, and your goal will be to modify your Ball's doTick(World w) method so that the ball will check for potential collisions with the walls, and act accordingly.
Note Well: If you were never able to correctly implement the behavior for the original Ball assignment, please make sure to seek the help of the instructor before attempting to add the additional functionality for the Bounce assignment.
For this assignment, you are allowed to work with one other student if you wish (in fact, we suggest that you do so). If any student wishes to have a partner but has not been able to locate one, please let the instructor know, so that we can match up partners.
In this regard, please make sure you adhere to the policies on academic integrity.
We have placed a template copy of the project, Bounce, in each of your home directories on patel2.slu.edu.
There exists a class BounceDriver for this assignment which is quite similar to the BallDriver for the earlier assignment. It too relies on a class Ball which you must provided. However rather than defining this new class from scratch, you should use your completed class Ball from the earlier assignment as your starting point. The suggested way to do this in BlueJ is to open the Bounce project and then from the "Edit" menu, select "Add Class from File..." and then navigate to select the file "Ball.java" located in your previous Ball project. This has the effect of making a new copy of the file in the Bounce project (while leaving your original copy unchanged in the Ball project).
Next, you must make some modifications to the class Ball.
You may notice that in the earlier assignment, the radius of the ball
was irrelevant to your class and thus not provided. For this
assignment, you must consider the radius of the ball in order to
effectively determine when the ball collides with another object. For
this reason, you should add a new instance variable to represent the
radius of the ball and you should write a new constructor for your
class which takes the radius of the ball as a parameter of type double
(e.g., a constructor of the form:
At this point, you should be able to compile and run the driver. You will notice that the driver for this assignment places four "walls" within the original World. Based on your original code, the ball should move through the world as expected, except that it will continue moving through the walls, since your doTick() routine does not yet consider the presence of walls. Rewriting your doTick() routine accordingly is the primary task of this assignment.
From within your doTick(World w) routine, you will need to query the given World to find references to the four Blocks which represent the walls. This can be done by using four additional methods of class World, getTopWall(), getBottomWall(), getLeftWall(), and getRightWall().
The keys to this assignment will be to:
In modeling the physics, we will assume that our collisions are "elastic" in that no energy is lost. Therefore, the ball's speed (i.e., magnitude of the velocity) should be equal before and after the collision. Of course the direction of the veloicty will have changed. In particular, when the ball hits an edge, its velocity should be reflected symmetrically along the perpendicular between the ball's center and the edge. For example, the following is a time-lapse figure of a ball's trajectory during a collision with a wall:
To simluate the collision properly, you need to determine not only that a collision exists, but specifically the exact location of the ball at the moment of impact. We will let you work on the precise characterization of how the state of the ball should change.
Hopefully, after some amount of work, you should be able to get a reasonable simluation of the collisions with the various walls. Yet there are a few additional subtleties that you will want to consider to get a more accurate simulation.
Creating your own private method for generality
There are two possible high-level approaches to completing this
assignment. The most obvious is to write code that deals specifically
with the left wall; then to write code that deals specifically with
the top wall; etc. If you wish to take this approach this is
acceptable.
However, there are clear similarities to the tasks; a much better approach in terms of programming style is to create a new method which checks for a collision between the ball and any given Block (identified as a parameter to the method). In later assignments, we will discuss more thoroughly the advantages to writing such additional methods to avoid duplication of similar code. But for now, we'll leave this as a mere suggestion and not a requirement. (see extra credit for additional discussion)
This is a discrete simulation
During a single call to doTick() you are supposed to advance
your ball a certain distance based on the velocity at that time. For
example, if your ball has a large velocity, say (20,0), then it should
travel 20 pixels during that clock tick. This means that if the
ball were to collide with the right wall after only 5 pixels of
motion, then you should still move an additional 15 pixels in the
direction of the velocity after the collision. So in this case, the
ball which started with its edge 5 pixels away from the right wall
would end up with its edge 15 pixels away from the right wall, and
moving in the opposite direction, by the end of a correctly
implemented tick.
Corners offer additional complications
If the ball is headed, with a large enough velocity, near a corner,
think about what should happen. If the ball collides with one wall
during the tick, and there remains additional distance to travel after
the collision, it could be that this additional travel causes yet
another collision. For example, consider the following time-lapse
figure, but assume that the entire motion was to have happened in a
single clock tick.
Simultaneous collisions
With just the right settings, it may even appear, with the original velocity vector, that a collision with two different walls is imminent. If this is the case, you would like to know which collision would happen first (or break the tie, if needed), so that you can process one collision effectively, and the go on to consider whether a secondary collision occurs.Gravity!
If you had gravity working in your previous assignment, you should be able to see the effects of gravity in this new assignment as well. The change on the velocity as effected by gravity is somewhat independent of the possible change due to a collision. Position (420,200); Velocity (20,0)
The fourth tick is the interesting one.
Position (374,100); Velocity (20,30)
The sixth tick is the interesting one.
Position (80,82); Velocity (-20,-20)
The fourth tick is the interesting one.
Position (82,80); Velocity (-20,-20)
The fourth tick is the interesting one.
Position (80,80); Velocity (-20,-20)
The fourth tick is the interesting one.
Please see details regarding the submission process from the general programming web page, as well as a discussion of the late policy.
If working as a pair, only one student should submit the project, but please make sure that you clearly document the existence of both authors.
The assignment is worth 10 points.
We will award one additional point to students who successfully meet the following challenge.
Earlier in the assignment writeup, we commented on the better approach of writing a single method that compares the ball to a given Block, in evaluating the potential for a collision. Implement a robust such method.
Specifically, our driver allows you to add one additional Block to the world, with coordinates chosen by the user. Select "Block" from the menu which by default reads "Ball" at the right of the program controller, and then click the "Add" button to bring up a dialog box for specifying the Block. From your doTick method, you can access this additional block using the World's getSpecialBlock() method.
Please note that there are several additional complexity for such an interior block.
Because the walls enclosed the original world, their edges could be treated as infinite lines rather than limited segments. For example, if the right wall had a left edge at coordinate X=450, then you could be sure that a ball would collide withh that wall if the right edge of the ball ever had coordinate greater than 450.
With an interior block, the right edge of the ball may greater than the left edge of the block, because the ball is going completely above or below the block, rather than colliding with the block. You will need to detect these differences.
Worse yet, you need to more carefully check for the possibility that a
ball collides with a corner of a block rather than an edge. (Note,
this was a non-issue for the required assignment because the walls
were placed along the perimeter, thus with no exterior corners
exposed). For example. consider the following figure:
Lastly, when you detect a collision with a corner, you must handle the
reaction appropriately.
you must first
determine the precise placement of the ball at the time it first makes
contact with a corner. The second issue is the reflection of the
velocity vector. Specifically, the velocity should be reflected
symmetrically across the line between the center of the ball and the
corner (e.g., the red line in the following diagram):