Tutorial on Processing: translate, rotate, TextField, quad ...



Tutorial on Processing: translate, rotate, quad plus calculations with PI, sin, cos, keyPressed, and with and without TextField

This tutorial describes cannonball, a 2D ballistics simulation in which a ball is shot out of a cannon, traveling through the air in a parabolic arc, and either hitting the ground or hitting a target. The player can change the speed out of the cannon and the angle of the cannon.

I wanted the user/player to be able to change the speed and the angle. My first approach used text fields. This works in the Processing environment, but the exported applet did not work: the text fields did not appear. In their place, I used the arrow keys: left and right to modify the speed, and up and down to modify the angle. This required changes in the coding to display the values and show the changed values and the cannon.

The initial screen using Text Fields is the following:

[pic]

The initial screen using arrow keys is

[pic]

Here is a screen shot in which the cannon angle has been modified as shown by the cannon rectangle and the number, and the speed also has been modified.

[pic]

Notice that the ball does not appear until the cannon is fired. This was easier to do when I needed to re-draw the display screen after changing the cannon angle and the text fields indicating speed and angle and I also decided it was an improvement.

I will continue the explanation using the text field screen shots. All the coding for both versions is included in this document.

Here is a screen shot of the ball in flight with the call the background commented out so you can see the arc of travel:

[pic]

After the player [the author] changes the Speed and Angle, the ball hits the target with the following result:

[pic]

The tutorial suggests a way to make the program adaptable to different targets.

The critical features for this Processing sketch are

• Positioning shapes using the translate and rotate commands

• Managing changes in the coordinate system using pushMatrix and popMatrix.

• Using the draw function for computer animation of the ball. This includes using the background command to erase the prior images

• Obtaining player/user input with TextFields

• Obtaining player/user input using arrow keys

• Determining if the ball has reached the ground or if the ball has hit the target.

• Firing the cannon

Position and orientation of cannon and ball

Processing positions shapes based on a coordinate system. The translate and the rotate commands change the coordinate system, translate moves the origin and rotate changes the angles. These are exactly what is needed to place the rectangle that represents the cannon on the display screen at the specified angle.

The rotate command in Processing requires the unit for angles to be radians as distinct to degrees. A full circle is 360 degrees. A right angle is 90 degrees. In radians, a full circle has 2*pi radians. This means the conversion calculation is

angle_in_radians = PI * angle_in_degrees / 180

Many computer languages use radians for at least some of the built-in functions. This application takes the typical approach of having the player use degrees, with the coding handling the conversion. A different, but similar issue, is that the calculation also requires a sign change for the angle.

The cannon is represented by a rectangle, using the rect command. The rect command's parameters are x, y, width and height. You may ask, since the rect command provides a way to position the rectangle somewhere different from the origin, why is it necessary to use translate? The answer is that I also need to rotate the rectangle and the rotation is done at the origin.

The cannonball is represented by a circle. This is produced by the ellipse command, parameters x, y, width and height. When the width and height are the same, a circle is produced.

The trajectory of the cannonball is calculated based on a simple ballistics model. The ball leaves the cannon with the speed and angle specified by the numbers in the interface. The vector representing the initial situation is resolved into its horizontal and vertical components. The ball continues with the same horizontal speed. Another way to say this is that the model does not represent air resistance or anything like it. The vertical speed, however, is changed so the application simulates the effects of gravity. A new vertical speed is calculated at each iteration and the vertical displacement at each iteration is calculated using the average of the old and new vertical speeds. These calculations are shown in detail later in this document. They are done in terms of the original coordinate system, not the coordinate system for drawing the positioned and rotated cannon.

NOTE: given the translate and rotate features of Processing, it may be worthwhile to explore changing the coordinate system to the traditional one of analytical geometry in which the vertical values increase moving up the screen. However, since I am so acclimated to working with the standard computer screen, I chose not to do this.

Managing the coordinate systems

Processing provides a way to store and restore coordinate systems. This is done using what is called the matrix stack. A matrix is the mathematical entity for geometric transformations such as translation and rotation. A stack is a computing term for storing information so that items that are put into storage are removed from storage in what is called Last In First Out order. The image you should have is a stack of plates in a spring-loaded tray. The pushMatrix() stores the current coordinate system and popMatrix() removes the mostly added coordinate system and makes it the current system. This means that you can save the current coordinate system; use translate and rotate and then restore the system.

It is possible to produce the same effects as pushMatrix and popMatrix by using translate and rotate. That is, after

translate(cannonx, groundlevel);

rotate(angler);

undo these changes (note the reversed order) using the statements:

rotate(-angler);

translate(-cannonx, -groundlevel);

The pushMatrix and the popMatrix means I can use

pushMatrix();

translate(cannonx, groundlevel);

rotate(angler);

and to undo:

popMatrix();

This is still 4 lines of code, but if there were more translate statements and rotate statements, the undo code would remain 1 statement.

Animation

The animation for the cannonball simulation uses the draw function, which, conveniently, is invoked according to the frame rate. Recall from previous tutorials or other experience with Processing that draw is a function recognized by the Processing system that the programmer defines. What I want to have happen is for the ball to be displayed in a new position. To accomplish this, the draw function uses the background command to erase everything on the display screen and issues commands and calls functions to re-draw the components on the screen: cannon, the advancing ball, ground, target, and labels for text fields. As it turns out (see below), the input text fields do not need to be re-drawn.

Because much of the time, the ball is not in motion, I use a Boolean variable named inflight to detect if the draw function needs to do anything.

Input text fields

Processing provides the text command for writing text on the display screen. This application requires something in addition: a way to get user input. The feature described here, TextField, works. It appears to be something from Java, rather than Processing and I could not find complete documentation.

To set up a text field for the user/player to input text requires a TextField variable. It also requires the use of the add command to place the variable on the display screen.

The statements:

TextField inputSpeed = new TextField("20",3);

TextField inputAngle = new TextField("65",3);

declares two variables of datatype Textfield, one named inputSpeed and the other named inputAngle. These declarations also initialize the TextFields. The inputSpeed one will display the (character string) "20" initially. This can be changed by the user/player. The second parameter, 3, controls the size of the field. The statements:

fill(255,0,250);

text("Speed",330,50);

add(inputSpeed);

text("Angle",410,50);

add(inputAngle);

place the text that serves as labels and the input text fields, 4 things, on the display screen. These statements are part of the setup function. The draw function, as was indicated earlier, includes the following statements after the background statement

fill(255,0,250);

text("Speed", 330, 50);

text("Angle", 410, 50);

The input text fields are not erased and so do not need to be re-drawn.

Input using arrow keys

The application using text fields to display and change speed and angle uses the arrow keys to move the cannon horizontally on the screen. The involves changing the cannonx variable. The keyPressed function is

void keyPressed() {

if (keyCode==LEFT) {

cannonx -=5;

}

if (keyCode==RIGHT) {

cannonx +=5;

}

}

An alternative to input text fields is for the user/player to alter the speed and angle values using arrow keys. The values of the speed and angle are maintained as variables and displayed on the screen. The left and right arrows will modify the speed and the up and down arrows will modify the angle. The horizontal movement of the cannon is dropped as a feature.

Capturing key presses requires use of the keyPressed method. This is another function like setup and draw. The name is 'known' to the Processing language. The programmer defines the method and Processing invokes it. The coding makes use of the built-in variable keyCode. This is compared to UP, DOWN, LEFT and RIGHT, built-in constants representing the value of those keys.

The modification of the speed and of the angle are by fixed amounts, kept as variables deltas and deltaa. This can be viewed as less flexible than letting the player type in a value, especially since it could be a floating point number. In order to emphasize that the increments are small, the code displays the integer conversion of the floating point numbers.

The keypressed function determines from keycode what is pressed, makes the appropriate change, and then re-displays everything: cannon, ground, target, triangle serving as the fire button, and the text information on the speed and the angle.

void keyPressed() {

if (keyCode==UP) {

angle +=deltaa;

}

if (keyCode==DOWN) {

angle -=deltaa;

}

if (keyCode==RIGHT) {

speed +=deltas;

}

if (keyCode==LEFT) {

speed -=deltas;

}

background(102,255,255);

fill(255,0,250);

text("Speed ",330,50);

text(int(speed),390,50);

text("Angle ",460,50);

text(int(angle),500,50);

positioncannon();

// know that this has changed coordinate system

popMatrix();

drawtarget(); // this will draw original target

}

It is important to provide feedback to the player/user. This means changing the displayed values and, in the case of angle, changing the angle of the cannon itself. In Processing, this means that the whole screen must be re-drawn.

Checking on the ball hitting the ground or the target

Determining if the flight of the cannonball is complete requires two calculations: has it hit the ground and has it hit the target. The calculation for the ground is relatively simple. [This may be considered a pun.] The variable posy will hold the vertical position for the ball. If its value is greater than the variable groundlevel, then the ball has reached the ground. Keep in mind that the vertical values increase moving down the screen.

Hitting the target is more complex. The target shown here is a rectangle. I chose to encapsulate each aspect of the target in a function. The functions are createtarget, drawtarget, hittarget and explodetarget. If someone wants to design a different shaped target and/or one with different behavior on being struck, this approach eases the development. The function for determining if the cannonball has struck the target is called by the advanceball function. The function definition is

boolean hittarget(float posx,float posy) {

if ((posx>targetx)&&(posxtargety)&&(posy=groundlevel) {

inflight = false;

}

if (hittarget(posx,posy)) {

explodetarget();

inflight = false;

}

else {

positionball();

}

}

void mousePressed() {

if (ontriangle()) {

angle = parseFloat(inputAngle.getText());

speed = parseFloat(inputSpeed.getText());

angler = -PI*angle/180;

hspeed = speed * cos(angler);

vnewspeed = speed * sin(angler);

voldspeed = vnewspeed;

posx = cannonx + 100*cos(angler);

posy = groundlevel + 100*sin(angler);

inflight = true;

targetok = true;

}

}

void createtarget() {

targetx = 600;

targety = groundlevel-100;

targetw = 30;

targeth = 100;

drawtarget();

}

void drawtarget() {

fill(250,250,0);

rect(targetx,targety,targetw,targeth);

}

boolean hittarget(float posx,float posy) {

if ((posx>targetx)&&(posxtargety)&&(posy700)&&(mouseX(groundlevel+10))&&(mouseY=groundlevel) {

inflight = false;

}

if (hittarget(posx,posy)) {

explodetarget();

inflight = false;

}

else {

positionball();

}

}

void mousePressed() {

if (ontriangle()) {

angler = -PI*angle/180;

hspeed = speed * cos(angler);

vnewspeed = speed * sin(angler);

voldspeed = vnewspeed;

posx = cannonx + 100*cos(angler);

posy = groundlevel + 100*sin(angler);

inflight = true;

targetok = true;

}

}

void createtarget() {

targetx = 600;

targety = groundlevel-100;

targetw = 30;

targeth = 100;

drawtarget();

}

void drawtarget() {

fill(250,250,0);

rect(targetx,targety,targetw,targeth);

}

boolean hittarget(float posx,float posy) {

if ((posx>targetx)&&(posxtargety)&&(posy700)&&(mouseX(groundlevel+10))&&(mouseY ................
................

In order to avoid copyright disputes, this page is only a partial summary.

Google Online Preview   Download