Aircraft[] remove(Aircraft[] array, int index) { if (index == 0) { return (Aircraft[])subset(array,1,array.length-1); } else if (index == array.length - 1) { return (Aircraft[])subset(array,0,array.length-1); } else { return (Aircraft[])concat( (Aircraft[])subset(array, 0, index), (Aircraft[])subset(array, index+1, array.length - index - 1) ); } } class Airport { int x; int y; int z; int w; int h; Aircraft flights[] = new Aircraft[6]; Aircraft grounded[] = new Aircraft[0]; float max_capacity = 1.0; float capacity = 0.0; float max_supplies = 4.0; float supplies = 4.0; PImage tower; Airport() { this.tower = loadImage("tower.png"); } void update() { for (int a = 0; a < this.flights.length; a++) { if (this.flights[a].state == Aircraft.DEAD) { this.flights = remove(this.flights,a); break; } } for (int a = 0; a < this.flights.length; a++) { this.flights[a].update(); if (this.flights[a].state == Aircraft.REFUEL && this.flights[a].runway < 0) { this.grounded = (Aircraft[])append(this.grounded,this.flights[a]); } if (this.flights[a].state != Aircraft.REFUEL && this.flights[a].runway >= 0) { this.grounded = remove(this.grounded,this.flights[a].runway); for (int g = 0; g < this.grounded.length; g++) { this.grounded[g].runway = g; } this.flights[a].runway = -1; } } this.capacity = 0.0; for (int g = 0; g < this.grounded.length; g++) { this.grounded[g].runway = g; this.capacity += this.grounded[g].space; } } void draw() { pushMatrix(); translate(this.x - this.tower.width/2,this.y - this.tower.height/2,this.z); beginShape(QUADS); texture(this.tower); vertex(0, this.tower.height, 0,0,1); vertex(0, 0, 0,0,0); vertex(this.tower.width, 0, 0,1,0); vertex(this.tower.width, this.tower.height, 0,1,1); endShape(); popMatrix(); fill(0,0,0); noStroke(); rectMode(CORNER); rect(width-100,0,100,height); noFill(); stroke(0,255,0); rectMode(CENTER); rect(this.x + 40,this.y, 20, 100); fill(0,255,0); noStroke(); rect(this.x + 40,this.y - 100*(this.capacity/this.max_capacity-1.0)/2,10,100*this.capacity/this.max_capacity); fill(0,0,255); noStroke(); rect(this.x + 50,this.y - 100*(this.supplies/this.max_supplies-1.0)/2,10,100*this.supplies/this.max_supplies); for (int a = 0; a < this.flights.length; a++) { if (this.flights[a].runway == -1) { this.flights[a].draw(); } } int runway_y = 0; for (int a = 0; a < this.grounded.length; a++) { this.grounded[a].x = this.w + 50; this.grounded[a].y = runway_y + this.grounded[a].h/2; this.grounded[a].draw(); runway_y += this.grounded[a].h + 30; } } void start_level(int level) { this.flights[0] = new Jumbo(this); //this.flights[0].x = random(this.h); //this.flights[0].y = random(this.h); this.flights[1] = new Heli(this); //this.flights[1].x = random(this.h); //this.flights[1].y = random(this.h); this.flights[2] = new Heli(this); //this.flights[2].x = random(this.h); //this.flights[2].y = random(this.h); this.flights[3] = new Heli(this); //this.flights[3].x = random(this.h); //this.flights[3].y = random(this.h); for (int a = 4; a < this.flights.length; a++) { this.flights[a] = new TwinProp(this); //this.flights[a].x = random(this.h); //this.flights[a].y = random(this.h); } } void mousePressed(int mouseX, int mouseY) { for (int a = 0; a < this.flights.length; a++) { this.flights[a].mousePressed(mouseX,mouseY); } } } class Aircraft { static final int WAITING = 0; static final int REFUEL = 1; static final int DEPART = 2; static final int ARRIVE = 3; static final int CLEARED = 4; static final int SCRAMBLED = 5; static final int ALERT = 6; static final int DEAD = 7; String name = "F000"; float x = 0; float y = 0; float z = 0; int w = 50; int h = 50; int runway = -1; PImage tex; PImage crate; float dist = 1.0; float seed; float heading = 0.0; float bearing = 0.0; float turn_speed = 0.02; float standoff; float fuel = 1.0; float fuel_rate = 1.0/900.0; //30 seconds in the air float refuel_rate = 1.0/600.0; //20 second on the ground int state = 0; // 0 = waiting, 1 = refueling, 2= departing, 3=dead float cargo = 0.0; float max_cargo = 1.0/3.0; float space = 1.0/3.0; float speed = 1.0/150.0; //cross the screen in 5 seconds float dir_x = 0.0; float dir_y = 0.0; float sign_x = 1.0; float sign_y = 1.0; Airport airport; Aircraft(Airport airport) { this.airport = airport; this.state = Aircraft.DEPART; this.seed = random(100000); this.heading = random(PI * 2) - PI; this.bearing = this.heading; this.standoff = -1.0; this.fuel = .76; //this.computeStandoff(); this.x = this.airport.x + cos(this.bearing) * this.airport.w; this.y = this.airport.y + sin(this.bearing) * this.airport.w; //this.heading = atan2(this.airport.y - this.y, this.airport.x - this.x); this.crate = loadImage("crate.png"); } void computeStandoff() { this.standoff = random(0.8) + 0.2; } void update() { this.dist = sqrt(pow(this.x - airport.x,2) + pow(this.y - airport.y,2))/(this.airport.h/2); if (abs(this.heading - this.bearing) >= PI) { if (this.heading > this.bearing) { this.bearing += 2 * PI; } else { this.bearing -= 2 * PI; } } else { this.bearing += constrain(this.heading - this.bearing, this.turn_speed * -1, this.turn_speed); } this.dir_x = cos(this.bearing) * sign_x; this.dir_y = sin(this.bearing) * sign_y; if (this.state == Aircraft.WAITING || this.state == Aircraft.ALERT || this.state == Aircraft.SCRAMBLED) { this.z = 0; this.fuel -= this.fuel_rate; this.x += this.speed * this.airport.w * this.dir_x; this.y += this.speed * this.airport.h * this.dir_y; /* if (this.x > this.airport.w || this.x < 0.0) { this.dir_x *= -1; this.heading = atan2(this.dir_y,this.dir_x); } if (this.y > this.airport.h || this.y < 0.0) { this.dir_y *= -1; this.heading = atan2(this.dir_y,this.dir_x); } */ this.heading = atan2(this.x - this.airport.x, this.airport.y - this.y); if (this.heading < 0) { this.heading *= 1; } if (this.fuel < 0.25) { this.state = Aircraft.ALERT; } if (this.fuel < 0.0) { this.state = Aircraft.DEAD; score -= int(1000 * this.space); } if (this.standoff < this.dist * 0.9) { this.heading = atan2(this.airport.y - this.y, this.airport.x - this.x); } if (this.standoff > this.dist * 1.1) { this.heading = atan2(this.y - this.airport.y, this.x - this.airport.x); } } if (this.state == Aircraft.REFUEL) { this.z = 0; this.fuel += this.refuel_rate; //this.x += this.speed * width * this.dir; //if (this.x > width || this.x < 0.0) //{ // this.dir *= -1; //} if (this.fuel > 1.0) { this.state = Aircraft.DEPART; this.heading = random(PI * 2) - PI; this.airport.supplies -= this.max_cargo - this.cargo; this.cargo = this.max_cargo; this.x = this.airport.x; this.y = this.airport.y; this.z = this.airport.z; } } if (this.state == Aircraft.DEPART) { this.z += constrain(0 - this.z, 0, 5); //this.z = 0; this.fuel -= this.fuel_rate; this.x += this.speed * this.airport.w * this.dir_x; this.y += this.speed * this.airport.h * this.dir_y; //this.fuel -= this.refuel_rate; //this.x += this.speed * width * this.dir; //if (this.x > width || this.x < 0.0) //{ // this.dir *= -1; //} if (this.fuel < 0.75) { this.computeStandoff(); score += int(1000 * this.cargo); this.cargo = 0.0; this.state = Aircraft.ARRIVE; } } if (this.state == Aircraft.ARRIVE) { this.heading = atan2(this.airport.y - this.y, this.airport.x - this.x); this.z = 0; this.fuel -= this.fuel_rate; this.x += this.speed * this.airport.w * this.dir_x; this.y += this.speed * this.airport.h * this.dir_y; //this.fuel -= this.refuel_rate; //this.x += this.speed * width * this.dir; //if (this.x > width || this.x < 0.0) //{ // this.dir *= -1; //} if (this.fuel < 0.5 || this.standoff > this.dist) { this.state = Aircraft.WAITING; } } if (this.state == Aircraft.CLEARED) { this.heading = atan2(this.airport.y - this.y, this.airport.x - this.x); this.z += constrain(this.z + this.airport.z, -5, 0); this.fuel -= this.fuel_rate; this.x += this.speed * this.airport.w * this.dir_x; this.y += this.speed * this.airport.h * this.dir_y; if (this.dist < 0.1) { this.state = Aircraft.REFUEL; } if (this.airport.capacity + this.space > this.airport.max_capacity) { this.computeStandoff(); this.state = Aircraft.WAITING; } } } void mousePressed(int mouseX, int mouseY) { if (mouseX > this.x - this.w/2 && mouseX < this.x + this.w/2 && mouseY > this.y - this.h/2 && mouseY < this.y + this.h/2) { if (this.airport.capacity + this.space <= 1.0 && (this.state == Aircraft.WAITING || this.state == Aircraft.ALERT || this.state == Aircraft.ARRIVE || this.state == Aircraft.DEPART )) { this.state = Aircraft.CLEARED; //this.x = 0; //this.y = 0; //this.y = this.airport.y; } else if (this.state == Aircraft.CLEARED) { this.computeStandoff(); this.state = Aircraft.WAITING; } else if (this.state == Aircraft.REFUEL) { this.state = Aircraft.DEPART; this.x = this.airport.x; this.y = this.airport.y; this.z = this.airport.z; } } } void draw() { if (mouseX > this.x - this.w/2 && mouseX < this.x + this.w/2 && mouseY > this.y - this.h/2 && mouseY < this.y + this.h/2) { stroke(255,255,255); strokeWeight(3); if (mousePressed && !(this.airport.capacity + this.space <= 1.0) && this.state == Aircraft.WAITING) { stroke(255,0,0); } pushMatrix(); stroke(255,255,255); translate(this.x,this.y,this.z); rotate(this.bearing + 7 * PI/8); //strokeWeight(5); noFill(); arc(0,0,this.w * 1.5,this.h * 1.5,0,PI/4); arc(0,0,this.w * 2,this.h * 2,0,PI/4); arc(0,0,this.w * 2.5,this.h * 2.5,0,PI/4); popMatrix(); //line (this.x,this.y,this.airport.x, this.airport.y); } color c; if (this.state == Aircraft.DEPART || this.state == Aircraft.ARRIVE) { c = color(0,255,0,192); } else if (this.state == Aircraft.ALERT) { c = color(255,0,0,192); //,(1.0 - this.dist) * 255); } else if (this.state == Aircraft.CLEARED) { c = color(0,0,255,192); //,(1.0 - this.dist) * 255); stroke(c); line(this.x,this.y,this.z,this.airport.x,this.airport.y,-400); } else if (this.state == Aircraft.REFUEL) { c = color(0,0,255,192); //,(1.0 - this.dist) * 255); } else { c = color(255,255,0,192); //,(1.0 - this.dist) * 255); } pushMatrix(); translate(this.x,this.y,this.z); stroke(255,255,255); noFill(); rectMode(CENTER); rect(0,h/2 + 10,w,10); noStroke(); fill(c); rect(w*(this.fuel-1.0)/-2,h/2 + 10,w* this.fuel,10); if (this.cargo > 0.0) { beginShape(QUADS); texture(this.crate); vertex(w/2-8, h/2-8,0,1); vertex(w/2+8, h/2-8,0,0); vertex(w/2+8, h/2+8,1,0); vertex(w/2-8, h/2+8,1,1); endShape(); } //textFont(displayFont,20); //text(this.state, 0, -45); //text(this.heading, 0, -30); //text(this.bearing, 0, -15); if (this.tex != null) { //tint(c); textureMode(NORMALIZED); rotate(this.bearing); beginShape(QUADS); texture(this.tex); vertex(w/-2, h/-2,0,1); vertex(w/2, h/-2,0,0); vertex(w/2, h/2,1,0); vertex(w/-2, h/2,1,1); endShape(); } else { ellipseMode(CENTER); ellipse(0,0,w,h); } popMatrix(); } } class Jumbo extends Aircraft { Jumbo(Airport airport) { super(airport); this.tex = loadImage("plane.png"); this.airport = airport; this.w = 75; this.h = 75; //this.fuel = 1.0; this.fuel_rate = 1.0/1800.0; //60 seconds in the air this.refuel_rate = 1.0/1800.0; //60 seconds on the ground this.max_cargo = 1.0/1.0; this.space = 1.0/2.0; this.speed = 1.0/300.0; //cross the screen in 10 seconds this.turn_speed = 0.03; } void computeStandoff() { this.standoff = random(0.2) + 0.4; } } class TwinProp extends Aircraft { TwinProp(Airport airport) { super(airport); this.tex = loadImage("twinprop.png"); this.airport = airport; this.w = 50; this.h = 50; //this.fuel = 1.0; this.fuel_rate = 1.0/1800.0; //60 seconds in the air this.refuel_rate = 1.0/900.0; //30 seconds on the ground this.max_cargo = 1.0/3.0; this.space = 1.0/3.0; this.speed = 1.0/240.0; //cross the screen in 8 seconds this.turn_speed = 0.04; } void computeStandoff() { this.standoff = random(0.2) + 0.6; } } class Heli extends Aircraft { Heli(Airport airport) { super(airport); this.tex = loadImage("heli.png"); this.airport = airport; this.w = 25; this.h = 25; //this.fuel = 1.0; this.fuel_rate = 1.0/1800.0; //60 seconds in the air this.refuel_rate = 1.0/150.0; //10 seconds on the ground this.max_cargo = 1.0/12.0; this.space = 1.0/6.0; this.speed = 1.0/600.0; //cross the screen in 20 seconds this.turn_speed = 0.05; } void computeStandoff() { this.standoff = random(0.2) + 0.4; } } Airport airport; PFont displayFont; PImage bg01; int max_time = 60*3*30; // 3 minutes int score = 0; int margin = 5; int ui_font_size = 15; void setup() { size(800,600,P3D); frameRate(30); displayFont = loadFont("displayFont.vlw"); airport = new Airport(); airport.x = width/2 - 50; airport.y = height/2; airport.z = -400; airport.w = width - 100; airport.h = height; airport.start_level(0); bg01 = loadImage("background01.jpg"); } void draw() { background(bg01); airport.update(); airport.draw(); fill(255,255,255); textFont(displayFont,ui_font_size); text("SCORE:",width-textWidth("SCORE:") - margin,height - ui_font_size * 2 - margin * 2 - 50); text(int(score),width-textWidth(str(score)) - margin,height - ui_font_size - margin - 50); text("TIME LEFT:",width-textWidth("TIME LEFT:") - margin,height - ui_font_size * 2 - margin * 2); text(int((max_time-frameCount)/30.0),width-textWidth(str(int((max_time-frameCount)/30.0))) - margin,height - ui_font_size - margin); if (frameCount < 90) { textFont(displayFont); text("WELCOME TO CHOKE POINT", airport.x - textWidth("WELCOME TO CHOKE POINT")/2,airport.y); } if (frameCount > max_time) { textFont(displayFont); text("YOU LOSE!", airport.x - textWidth("YOU LOSE!")/2,airport.y); } else if (airport.supplies <= 0.0) { textFont(displayFont); text("YOU WIN!", airport.x - textWidth("YOU WIN!")/2,airport.y); } } void mousePressed() { airport.mousePressed(mouseX,mouseY); }