/** *

Based on the method drawPointsToTarget() this builds upon fuctions already * derived to simulate the movement of a ship through space. The ship has * a minimum turning angle and will animate between its current position and the * target position signified by clicking the mouse.

*/ // Declare colours color black = color(0,0,0); color white = color(255,255,255); color red = color(200, 70, 70); color blue = color(70, 80, 200); color green = color(80, 150, 70); color c_shield = color(255, 50); // Declare vars final float RAD90 = radians(90); float maxTurnSpeed = 20; boolean movingToTarget = false; int target_x, target_y; int TmouseX, TmouseY; // Image vars PImage[] imgs; // Declare objects spaceShip alien1, alien2; // Declare fonts PFont font; void setup() { // Setup scene size(400, 400); // Configure fonts font = loadFont("AcknowledgeTT-BRK--48.vlw"); textFont(font, 24); // Load images imgs = new PImage[4]; imgs[0] = loadImage("smallShip_picture_small.gif"); imgs[1] = loadImage("largeShip_picture_small.gif"); imgs[2] = loadImage("smallShip_picture_large.gif"); imgs[3] = loadImage("largeShip_picture_large.gif"); // Load ships alien2 = new spaceShip(2, imgs[1], 0.5, 10, 10, radians(45), -150, 150, 30); // Set framerate framerate(20); } void draw() { // Set basic draw items reset(); // Set pixel to represent mouse set(mouseX, mouseY, white); if(movingToTarget) { // Run move animation if(alien2.moveTowardsTarget(target_x, target_y)) { // Animate ship movement to target } else { movingToTarget = false; } } else { // Plot movement lines alien2.drawMovementPoints(TmouseX, TmouseY); // Set target if mouse is pressed if(mousePressed) { target_x = TmouseX; target_y = TmouseY; movingToTarget = true; alien2.refreshMovement(); } } // Draw ships alien2.draw(); // Debug message textAlign(RIGHT); fill(black); text("Moving To Target", width/2-20, height/2-20); fill(red); text("Moving To Target", width/2-22, height/2-22); } void reset() { // Clear background and draw gubbins background(blue); stroke(black); strokeWeight(1); line(0, 0, width, height); line(width, 0, 0, height); // Transform coordinate system translate(width/2, height/2); TmouseX = mouseX-width/2; TmouseY = mouseY-height/2; } float turnToTarget(float x1, float y1, float x2, float y2, float direction, float maxTurnSpeed) { // Calculate angle to target float targetAngle = RAD90 + atan((y2-y1)/(x2-x1)); float RADTurn = radians(maxTurnSpeed); if(x2-x1 < 0) { targetAngle += RAD90*2; } // Calculate difference float diff1 = direction - targetAngle; // Normalize angle float diff2 = normalizeRadian(diff1); // Decide whether to turn CW or CCW if(diff2 < 0 && diff2 >= -RAD90*2 || diff2 >= RAD90*2) { if(diff2 > -RADTurn && diff2 <= 0) { // Turn directly to target return targetAngle - direction; } else { // Turn CW return RADTurn; } } else { // CCW if(diff2 < RADTurn && diff2 >= 0) { // Turn directly to target return targetAngle - direction; } else { // Turn CW return -RADTurn; } } } void drawPointsToTarget(float x1, float y1, float x2, float y2, float direction, float maxTurnAngle, int step, int steps) { // Constants float stepDistance = 10; // e.g. 1 in 5, 1 in checkFrequency. float checkFrequency = 2; // Calculate which way to turn float check = maxTurnAngle/checkFrequency; direction += turnToTarget(x1, y1, x2, y2, direction, check); // Adjust angles float checkDirection = (direction-RAD90); // Calculate new position float x3 = x1 + stepDistance/checkFrequency * cos(checkDirection); float y3 = y1 + stepDistance/checkFrequency * sin(checkDirection); // Loop if(step < steps && !(round(x3, -1) == round(x2, -1) && round(y3, -1) == round(y2, -1)) ) { drawPointsToTarget(x3, y3, x2, y2, direction, maxTurnAngle, ++step, steps); } if(step % checkFrequency == 0) { // Draw marker noStroke(); fill(c_shield); ellipse((int)x3+1, (int)y3+1, 4, 4); fill(c_shield); ellipse((int)x3, (int)y3, 4, 4); } } void nothing() { } float round(float number, float decimal) { return (float)(round((number*pow(10, decimal))))/pow(10, decimal); } float normalizeRadian(float rad) { if(rad > TWO_PI) { rad -= TWO_PI; rad = normalizeRadian(rad); } else if(rad < -TWO_PI) { rad += TWO_PI; rad = normalizeRadian(rad); } return rad; } public class spaceShip { // Variables private int id, x, y, sizeRadius; private PImage graphic; private float turnSpeed, maxSpeed, direction, movementRemaining, graphicScale, distance; // Constructor spaceShip(int id, PImage graphic, float graphicScale, float turnSpeed, float maxSpeed, float direction, int x, int y, int sizeRadius) { this.id = id; this.graphic = graphic; this.graphicScale = graphicScale; this.turnSpeed = turnSpeed; this.maxSpeed = maxSpeed; this.direction = direction; this.x = x; this.y = y; this.sizeRadius = sizeRadius; } // Set Position void setPosition(int x, int y) { this.x = x; this.y = y; } // Set Direction void setDirection(float direction) { this.direction = direction; } // Draw movement lines void drawMovementPoints(int tx, int ty) { drawPointsToTarget(x, y, (float)tx, (float)ty, direction, turnSpeed, 0, 50); } // Get graphic PImage getGraphic() { return graphic; } // Draw method void draw() { smooth(); // Push tranformation matrix pushMatrix(); imageMode(CORNERS); // Position Ship translate(x, y); rotate(direction); // Draw boundary circle ellipseMode(CENTER); stroke(c_shield); strokeWeight(4); noFill(); ellipse(0, 0, sizeRadius*2, sizeRadius*2); // Scale and position graphic scale(graphicScale, graphicScale); image(graphic, -graphic.width/2, -graphic.height/2); scale(1/graphicScale, 1/graphicScale); // Pop transformation matrix popMatrix(); noSmooth(); } float getMovementRemaining() { return movementRemaining; } void refreshMovement() { movementRemaining = maxSpeed * 25; } boolean moveTowardsTarget(float tx, float ty) { // Work out which way to turn towards target float turnAmount = turnToTarget(x, y, tx, ty, direction, turnSpeed); // Set new direction direction += turnAmount; // Calculate new position x += maxSpeed * cos(direction-RAD90); y += maxSpeed * sin(direction-RAD90); // Calculate new distance float newDistance = dist(x, y, tx, ty); // Check if actually moving further away if(round(x, -1) == round(tx, -1) && round(y, -1) == round(ty, -1)) { return false; } else if(movementRemaining > maxSpeed) { movementRemaining -= maxSpeed; return true; } else { movementRemaining = 0; return false; } } }