TopFallingObject exampleOverriding

Overriding

Let's create another extension of our fallingObject. This is a weird storm and in addition to leaves and sleet, tomatoes are falling from the sky. Adding these tomatoes (red ovals) as a third option isn't too hard - we just extend FallingObject once again and this time draw red ovals in the constructor. We also modify the Tree to create leaves, sleet, or tomatoes.

But tomatoes don't just disappear when they hit the ground. While we could reasonably imagine leaves and sleet decomposing or melting when it hits the ground, we might want to make our tomatoes splat when they reach the ground.

The important difference here is that after the usual falling, done by the start method of fallingObject, we want to show the tomato splat. Here, we only replace the circle by an elongated oval.

We can achieve this by overriding the start method from fallingObject with a tomato-specific version in Tomato.

We can tell Grace to execute super.start to execute the start method of the superclass, fallingObject. This drops the object and removes it from the canvas. Then we create a new filledOval to represent the tomato getting squished. However, this won't really work properly because the system will show the splatted tomato before the original one hits the ground - all because we can't place that code in a finally clause of the while loop.

You might also wonder if other things that could fall from clouds might also have some special behavior when they're done falling. Perhaps in some cases, we don't want the object that was falling to be removed from the canvas at all (maybe we want our leaves and sleet to accumumulate).

We can modify our fallingObject class to allow for these possibilities, while still retaining its original functionality.

class fallingObject.rate(yChange: Number) until (stopHeight: Number) -> Animated {

    def pauseTime: Number = 33

    var theObject: Graphic2D

    method start -> Done {
        animator.while{theObject.y < stopHeight} pausing (pauseTime) do {
           theObject.moveBy(0, yChange)
        } finally {
           hitBottom
        }
    }
    
    method hitBottom -> Done {
      theObject.removeFromCanvas
    }
}

Notice that the method hitBottom is called in the finally clause of the while loop. For things like leaves and hail, we can leave that method alone, but with something like a tomato, we can override the hitBottom method and get the behavior we desire.

Demo: FallingObjectsWithCows
Which of our solutions for specifying the "hit bottom" behavior, or other "enhanced" behaviors, is better? It depends. In many cases, either approach will work, but one or the other results in clearer or less complex code.


TopFallingObject exampleOverriding