OpusScript Tutorial:

Bouncing a Ball

Part 1: Simulating Gravity and Bounce

Overview of the Tutorial

In this tutorial, we will explore how to create a simple physics engine which will move and accelerate a vector object as if it were affected by gravity. We will find out how to make the object bounce against a surface and gradually come to rest. We will then expand on this to allow the object to be thrown around the page, bouncing off all four 'walls' of the publication. Finally, we will 'prettify' the publication and give the bouncing ball a realistic shadow which moves, scales and fades in relation to the ball's height and position.

Please note that a working example of the publication created by this tutorial can be downloaded from the links at the side of this page. Should you encounter any problems following the steps in this tutorial, or if your publication does not behave in the expected fashion, please download and examine this publication and see if you can find any discrepancies or errors in your script.

This tutorial is suitable for Opus Pro from v4 onwards. Note that some of the dialogues and toolbar graphics illustrated here vary between versions but the key features indicated should still be present.

Setting up the publication

The first step is to launch Opus Pro and create a blank new publication.

Now click Edit > Chapter Properties and select the General tab. For the purposes of this tutorial ensure that the page size is set to 800 x 600. (If you want the publication to fill the screen whatever size check both 'Pages can be resized' checkboxes so they are enabled but make sure the 'Maintain aspect ratio' is also enabled or your ball will appear elongated - especially on modern "widescreen" screen resolutions). For this tutorial we have assumed the publication is fixed, thus the Chapter Properties should match the following:

Now click Apply and OK to return to the editor.

I would also recommend turning on the dotted page grid if this is not already showing. To do this, click View > Grid > Dots.

We will now create the ball object. Please select the Vector drawing tool . In the Draw Tools toolbar, click on the arrow to the right of the Curved Shapes icon and select the Circle shape (indicated below):

Now draw a circle shape on the page measuring 50 pixels x 50 pixels. You can change the fill colour of the circle once it has been created by simply left-clicking on a colour in the Palette bar. You can also change the outline of the circle by right-clicking in the Palette bar.

Now please rename the vector object (which will probably be named 'Vector 1') by right-clicking on the vector object in the Organiser pane and selecting Rename, as shown below:

Please rename the object to Ball, ensuring that the letter B is upper-case and all other letters are lower case. Please also ensure that there are no trailing spaces or other punctuation in the filename. When you are happy with the changes, press Enter on the keyboard to confirm.

We need to give our ball enough space to drop, so please drag the Ball up to the top of the page, then horizontally-centre the object by clicking Arrange > Centre Objects > Horizontally. Your page should now look like the following:

Simulating gravity

We can now start work on our physics engine. Please click the Script Object icon to create a new script object named Script 1.

Gravity is a force which acts upon the vertical motion of an object causing vertical acceleration. To model this, we need to move our Ball object down the page, but steadily increase the rate of motion (thereby 'accelerating' the object vertically). We therefore need to create a variable named 'speed' which will increase as time progresses. Let's declare this variable and give it an initial value of zero (i.e; the ball is at rest).

speed = 0

We will set 'gravity' to a constant value of 1:

gravity = 1

We now need to create a loop which will increase the 'speed' variable by the 'force' of gravity, then move the object down the page based on the current 'speed'. The easiest way to create an infinite loop is:

while (true) {

We will now increase the 'speed' of the object by the value of 'gravity':

speed = speed + gravity

Now move the object vertically by the value of 'speed':

Ball.MoveY(speed)

With any looped actions, it is recommended to add a wait() command to give the processor a 'breather'. Otherwise, the publication will flood the processor with requests and the publication may lock up. Let's set a delay of one hundredth of a second:

wait(0.01)

Now ensure that you close the set of looped actions by adding a right curly bracket:

}

Your script object should now read the following:

speed = 0
gravity = 1
while (true) {
  speed = speed + gravity
  Ball.MoveY(speed)
  wait(0.01)
}

Now preview the publication. The Ball object should drop down the page, steadily accelerating, and disappear off the bottom of the screen. You can, if you wish, play around with different values for gravity (simply change the value 1 to a different number or decimal) to see how this affects the rate at which the object drops. Increasing the force of gravity will result in a quicker acceleration and a more rapid descent, whereas decreasing gravity will slow the ball's descent. Set the gravity constant back to 1 when you are done.

Creating a 'floor'

A falling object is all very well, but we want to keep the ball on-screen at all times. We therefore need to implement a way of setting a 'floor' to the publication, past which the ball cannot travel. To do this, we will first need to determine the y-coordinate of the 'floor'. We can then constantly monitor the current position of the ball using a GetPosition() function. Finally, we will compare the current vertical position of ball to our predetermined 'floor' coordinate to see if the ball has reached the floor.

So, what is the position of the floor? As the publication is 600 pixels in height, you may think that this is simply 600. However, the GetPosition() function we are going to use to find the current position of the ball calculates the position from the object's mid-point, not from its bottom edge. If we allowed the object to drop to a y-coordinate of 600, half of the ball would have descended past the bottom edge of the publication. When the ball is resting on the bottom edge of the publication, its vertical position is actually 575 pixels, as the following diagram hopefully demonstrates:

We therefore need to create a new constant named 'floor' set to 575. Let's put this at the beginning of the code:

floor = 575
speed = 0
gravity = 1
while (true) {
  speed = speed + gravity
  Ball.MoveY(speed)
  wait(0.01)
}

We now need to add a GetPosition() function to our main loop to check the position of the ball object and store this to a variable. Let's put this before the wait() action:

floor = 575
speed = 0
gravity = 1
while (true) {
  speed = speed + gravity
  Ball.MoveY(speed)
  pos = Ball.GetPosition()
  wait(0.01)
}

After the GetPosition() function, we need to add an If statement which will see if the ball's vertical position is greater than the 'floor' constant:

if (pos.y > floor) {

As the ball is likely to be moving at a fair rate of knots by the time it reaches the floor, it is possible that the last MoveY() action moved the ball 'past' the floor. The If statement checks to see if the ball's position is greater than the floor, but we still need to ensure that the ball is positioned inside the publication. Let's place it back on the floor:

Ball.SetPositionY(floor)

Now add a right curly bracket to close the If statement. Your script object should resemble the following:

floor = 575
speed = 0
gravity = 1
while (true) {
  speed = speed + gravity
  Ball.MoveY(speed)
  pos = Ball.GetPosition()
  if (pos.y > floor) {
    Ball.SetPositionY(floor)
  }
  wait(0.01)
}

Now preview the publication. The ball will again fall and accelerate towards the floor, but will now stop dead when the floor is reached.

Simulating a bounce

Unless the ball is made of lead, you would not expect it to come to a complete standstill when it hits the floor. Instead, you would expect the object to bounce a number of times before coming to rest. We therefore need to find a way of reversing the direction of the object when it reaches the floor to simulate a bounce. Fortunately, we have already done most of the groundwork for this and it is now very simple to control the ball's direction of movement.

First, ask yourself this question - why does the ball currently move down the screen and not upwards? The answer is that the Ball is moved using a MoveY() function, which in turn uses the 'speed' variable to determine how far the object should be moved. The 'speed' variable is a positive integer (i.e; a whole number greater than zero) and, in an Opus publication (as in many other applications), increasing the Y position of an object moves it DOWN, rather than up, the screen. Conversely, moving an object vertically by a negative integer will move it UP the screen. The following diagram hopefully makes this distinction clear:

So, all we need to do to reverse the direction of the ball is to convert its current speed from a positive integer into a negative one, and the easiest way to do this is to multiply the speed by -1. Edit the code to read the following:

floor = 575;
speed = 0;
gravity = 1;
while (true) {
  speed = speed + gravity;
  Ball.MoveY(speed);
  pos = Ball.GetPosition();
  if (pos.y > floor) {
    Ball.SetPositionY(floor);
    speed = speed * -1;
  };
  wait(0.01);
}

Now preview the publication. The ball should now fall, hit the ground, then bounce back up to its starting position before falling again. The reason the ball falls again (rather than shooting off the top of the publication) is because the speed is still being increased by the effect of gravity. By the time the ball has risen back up to the starting position, its speed is no longer a negative integer, but has resolved back to zero. The speed then increases further, becomes a positive integer, and the ball drops back to the ground. This cycle of events will repeat indefinitely.

The only remaining problem is that the bounce is not particularly realistic. You would not expect a ball to bounce to the same height every time and never come to rest. We therefore need to implement a way of reversing the direction of the ball, but also to decrease its speed slightly, so that some momentum is sapped from the ball. Fortunately, this is also very simple to achieve. Instead of multiplying the speed by -1, we simply need to multiply it by less than -1, for example, -0.5.

Let's try this:

floor = 575;
speed = 0;
gravity = 1;
while (true) {
  speed = speed + gravity;
  Ball.MoveY(speed);
  pos = Ball.GetPosition();
  if (pos.y > floor) {
    Ball.SetPositionY(floor);
    speed = speed * -0.5;
  };
  wait(0.01);
}

Now preview the publication. The ball should only bounce a couple of times before coming to rest. This is obviously a lot more realistic, but it would be nice for the ball to bounce a few more times. Let's change that -0.5 value to something a little closer to the original -1:

floor = 575
speed = 0
gravity = 1
while (true) {
  speed = speed + gravity
  Ball.MoveY(speed)
  pos = Ball.GetPosition()
  if (pos.y > floor) {
    Ball.SetPositionY(floor)
    speed = speed * -0.9
  }
  wait(0.01)
}

Preview the publication and the ball should now bounce around 15 times before coming to rest. We can tidy up the code a little and make it easier to edit the code later by making this 'bounce' value a constant which is declared at the start. For example:

floor = 575
speed = 0
gravity = 1
bounce = 0.9
while (true) {
  speed = speed + gravity
  Ball.MoveY(speed)
  pos = Ball.GetPosition()
  if (pos.y > floor) {
    Ball.SetPositionY(floor)
    speed = speed * -bounce
  }
  wait(0.01)
}

In the next tutorial, we will introduce horizontal motion into our model and make the ball bounce realistically off the 'walls' of the publication.

tutorial to create a bouncing ball simulation in Opus Pro