//Owen Canavan //D13125137 //Menu menu; //menu object String state = ""; //state tracker RoidManager rm; Player player; ExplosionManager em; int level = 1; int scr_diag; //screen diagonal for range finding void setup(){ size(800,600); scr_diag = (int)ceil(sqrt(width*width + height*height)/2); changeState("game"); } void draw(){ background(0); if(state == "game" || state == "gameOver"){ rm.update(); player.update(); em.update(); rm.draw(); player.draw(); em.draw(); } } void levelUp(){ //increase level and reset large rocks level++; rm.init(); } void startGame(){ //start new game level = 1; player = new Player(width/2,height/2); rm = new RoidManager(); rm.init(); em = new ExplosionManager(); } void keyPressed(){ //input manager, delegate to player if(state == "game") player.keyPressed(); if(state == "gameOver"){ if(key == ' ') changeState("game"); } } void keyReleased(){ //input manager, delegate to player if(state == "game") player.keyReleased(); } void changeState(String s){ //simple state manager; change state, call enter state function if(state != s){ state = s; if(state == "game") startGame(); } } //------------------------- //asteroid.pde //------------------------- class RoidManager { //asteroid manager, 4 large, 8 medium, 16 small Roid[] large, medium, small; int active; RoidManager() { large = new Roid[4]; for (int i = 0; i < large.length; i++) large[i] = new Roid(1); medium = new Roid[8]; for (int i = 0; i < medium.length; i++) medium[i] = new Roid(2); small = new Roid[16]; for (int i = 0; i < small.length; i++) small[i] = new Roid(3); } void init() { //start level with 4 large asteroids. base translation speed on game level float speed = 0.5 + (level-1)*0.25; //pick random starting locations within own areas, but avoid the player if they are not in the middle large[0].spawn(player.pos.x < width/2-100 ? random(width/2,width):random(0, width/3), player.pos.y < height/2-100 ? random(height/2,height): random(0, height/3), random(-1, 1), random(-1, 1),speed, random(-1, 1)); large[1].spawn(player.pos.x < width/2-100 ? random(width/2,width):random(0, width/3), player.pos.y > height/2+100 ? random(0,height/2): random(2*height/3,height), random(-1,1),random(-1,1),speed, random(-1,1)); large[2].spawn(player.pos.x > width/2+100 ? random(0,width/2):random(2*width/3,width), player.pos.y < height/2-100 ? random(height/2,height): random(0, height/3), random(-1,1),random(-1,1),speed, random(-1,1)); large[3].spawn(player.pos.x > width/2+100 ? random(0,width/2):random(2*width/3,width), player.pos.y > height/2+100 ? random(0,height/2): random(2*height/3,height), random(-1,1),random(-1,1),speed, random(-1,1)); //track active asteroids active = 4; } void checkBullet(Bullet b) { //check bullet agains every active asteroid //check against the large asteroids for (int i = 0; i < large.length; i++) { Roid roid = large[i]; if (roid != null && roid.alive) { int s = roid.containsPoint(b.x, b.y); //check point collision for each triangle segment of the asteroid if (s > -1) { //a hit if (roid.hp[s] < 4-roid.size) { //a hit that actually does damage (this face hasn't suffered maximum damage roid.hits++; roid.hp[s]++; if (roid.hits == roid.MAX_HITS) { //maximum asteroid damage, split into 2 mediums roid.alive = false; PVector hit2cen = new PVector(roid.pos.x - b.x, roid.pos.y - b.y); //to determine movemnt directions. both moving away from eachother, and the player (90deg) hit2cen.rotate(PI/2); spawn(2, roid.pos.x, roid.pos.y, hit2cen.x, hit2cen.y); spawn(2, roid.pos.x, roid.pos.y, -hit2cen.x, -hit2cen.y); em.spawn(roid.pos.x,roid.pos.y,8,20,20,40,50); //big explosion active++; //we lost one but gained two. one net gain } } //bullet hit, kill and mini explosion. return b.alive = false; em.spawn(b.x,b.y,4,10,20,40,20); return; } } } //havn't hit anything yet. check the mediums for (int i = 0; i < medium.length; i++) { Roid roid = medium[i]; if (roid != null && roid.alive) { int s = roid.containsPoint(b.x, b.y); if (s > -1) { if (roid.hp[s] < 4-roid.size) { roid.hits++; roid.hp[s]++; if (roid.hits == roid.MAX_HITS) { roid.alive = false; PVector hit2cen = new PVector(roid.pos.x - b.x, roid.pos.y - b.y); hit2cen.rotate(PI/2); spawn(3, roid.pos.x, roid.pos.y, hit2cen.x, hit2cen.y); spawn(3, roid.pos.x, roid.pos.y, -hit2cen.x, -hit2cen.y); em.spawn(roid.pos.x,roid.pos.y,8,20,20,40,50); active++; } } em.spawn(b.x,b.y,4,10,20,40,20); b.alive = false; return; } } } //still haven't hit anything. check the smalls for (int i = 0; i < small.length; i++) { Roid roid = small[i]; if (roid != null && roid.alive) { int s = roid.containsPoint(b.x, b.y); if (s > -1) { if (roid.hp[s] < 4-roid.size) { roid.hits++; roid.hp[s]++; if (roid.hits == roid.MAX_HITS) { roid.alive = false; active--; em.spawn(roid.pos.x,roid.pos.y,8,20,20,40,50); if(active == 0){ levelUp(); } } } em.spawn(b.x,b.y,4,10,20,40,20); b.alive = false; return; } } } } //create a new asteroid void spawn(int size, float x, float y, float vx, float vy) { Roid[] a = size == 1 ? large : ( size == 2 ? medium : small); for (int i=0;i<a.length;i++) { if (!a[i].alive) { //speed based on size and level. increasing speed with each level float speed = 0.5; if(size == 1) speed = 0.5 + (level-1)*0.25; else if(size == 2) speed = 0.75 + (level-1)*0.25; else if(size == 3) speed = 1 + (level-1)*0.25; a[i].spawn(x, y, vx, vy, speed, random(-1, 1)); return; } } } //update loop void update() { //update large, medium, small in order for (int i = 0; i < large.length; i++) { Roid roid = large[i]; if (roid != null && roid.alive) roid.update(); } for (int i = 0; i < medium.length; i++) { Roid roid = medium[i]; if (roid != null && roid.alive) roid.update(); } for (int i = 0; i < small.length; i++) { Roid roid = small[i]; if (roid != null && roid.alive) roid.update(); } //asteroid vs asteroid collisions //asteroid bounce of other asteroid of greater than or equal size. don't react if hit by a small rock //large vs large for (int i = 0; i < large.length -1; i++) { Roid r1 = large[i]; if (r1 != null && r1.alive) { for (int j = i + 1; j < large.length; j++) { //ensure we double check, only loop from current position forward Roid r2 = large[j]; if (r2 != null && r2.alive) { //check each rock is active bounce(r1, r2, true); //bounce both large } } } } //medium vs large for (int i = 0; i < medium.length; i++) { Roid r1 = medium[i]; if (r1 != null && r1.alive) { for (int j = 0; j < large.length; j++) { Roid r2 = large[j]; if (r2 != null && r2.alive) { bounce(r1, r2, false); //bounce just the medium } } } } //med vs med for (int i = 0; i < medium.length -1; i++) { Roid r1 = medium[i]; if (r1 != null && r1.alive) { for (int j = i + 1; j < medium.length; j++) { Roid r2 = medium[j]; if (r2 != null && r2.alive) { bounce(r1, r2, true); //bounce both medium } } } } //small vs large & medium for (int i = 0; i < small.length; i++) { Roid r1 = small[i]; if (r1 != null && r1.alive) { for (int j = 0; j < large.length + medium.length; j++) { //combining both large and medium in a single loop Roid r2 = j >= large.length ? medium[j-large.length] : large[j]; if (r2 != null && r2.alive) { bounce(r1, r2, false); //bounce just the smalls } } } } //small vs small for (int i = 0; i < small.length -1; i++) { Roid r1 = small[i]; if (r1 != null && r1.alive) { for (int j = i + 1; j < small.length; j++) { Roid r2 = small[j]; if (r2 != null && r2.alive) { bounce(r1, r2, true); //bounce both small } } } } } void bounce(Roid r1, Roid r2, boolean both) { //if collision circle intersecting, seperate then bounce abount axis between two float d = dist(r1.pos.x, r1.pos.y, r2.pos.x, r2.pos.y); float RAD = (r1.radius + r2.radius)*0.75; if (d < RAD) { //if intersecting float _d = RAD - d; //seperate PVector vc = new PVector(r1.pos.x - r2.pos.x, r1.pos.y - r2.pos.y); //vector between roid centres vc.normalize(); r1.pos.x += vc.x * _d/2; r1.pos.y += vc.y * _d/2; r2.pos.x -= vc.x * _d/2; r2.pos.y -= vc.y * _d/2; //bounce PVector v1 = new PVector(r1.vx, r1.vy); //rock 1 velocity PVector v2 = new PVector(r2.vx, r2.vy); //rock 2 velocity PVector vcn = new PVector(vc.y, - vc.x); //right hand normal //bounce r1 float dp11 = v1.dot(vcn); float dp12 = v1.dot(vc); PVector proj11 = vcn.mult(vcn, dp11);//project vel on the centres vector PVector proj12 = vc.mult(vc, dp12); //project vel onto normal proj12.x *= -1; proj12.y *= -1; PVector v1N = new PVector(proj11.x + proj12.x, proj11.y + proj12.y); //new bounced velocity v1N.normalize(); r1.vx = v1N.x; r1.vy = v1N.y; if (both) { //do we bounce the second? //bounce r2 float dp21 = v2.dot(vcn); float dp22 = v2.dot(vc); PVector proj21 = vcn.mult(vcn, dp21); PVector proj22 = vc.mult(vc, dp22); proj22.x *= -1; proj22.y *= -1; PVector v2N = new PVector(proj21.x + proj22.x, proj21.y + proj22.y); v2N.normalize(); r2.vx = v2N.x; r2.vy = v2N.y; } } } void draw() { //draw each rock, large, medium, small for (int i = 0; i < large.length; i++) { Roid roid = large[i]; if (roid != null && roid.alive) roid.draw(); } for (int i = 0; i < medium.length; i++) { Roid roid = medium[i]; if (roid != null && roid.alive) roid.draw(); } for (int i = 0; i < small.length; i++) { Roid roid = small[i]; if (roid != null && roid.alive) roid.draw(); } } } class Roid { //a single asteroid int size, radius; float rot, vx, vy, speed, rot_speed; boolean alive; Point pos; Point[] points; int[] hp; int hits, MAX_HITS; Roid(int _size) { //instantiate inactive size = _size; alive = false; } void spawn(float _x, float _y, float _vx, float _vy, float _speed, float r_speed) { //wake up alive = true; pos = new Point(_x, _y); float vs = sqrt(_vx*_vx + _vy*_vy); vx = _vx/vs; vy = _vy/vs; speed = _speed; rot_speed = r_speed; int min_r=1, max_r=1; radius = size == 1 ? 100 : size == 2 ? 50 : 25; min_r = (int)(radius * 0.75); max_r = (int)(radius * 1.25); int n = (int)random(8, 12); points = new Point[n]; hp = new int[n]; //hitpoints for each facade hits = 0; MAX_HITS = (4-size)*floor(n/3); //bigger rocks need more hits to destroy float _a = (2*PI)/n; float pa = 0; for (int i = 0; i < n; i++) { //randomised number of verticies (angles and lengths) to give lumpy surface int px = 0; int py = 0; int r = (int)random(min_r, max_r); pa += _a; float a = random( pa - _a/2, pa + _a/2); px = (int)(cos(a) * r); py = (int)(sin(a) * r); points[i] = new Point(px, py); } } //we are rotating each point here instead of just doing a global translate/rotate, as we need to determine the proximity of each face to the player for colouring void rotatePoint(Point p, float r) { float a = atan2(p.y, p.x); float d = dist(0, 0, p.x, p.y); a += r; //bounds if (a > 2*PI) a -= 2*PI; if (a < 0) a += 2*PI; p.x = cos(a)*d; p.y = sin(a)*d; } void update() { if (!alive) return; rot += 0.01 * rot_speed; //global rotate. don't think it's needed anymore //bounds if (rot > 2*PI) rot -= 2*PI; if (rot < 0) rot += 2*PI; //rotate each point for (int i=0;i<points.length;i++) { rotatePoint(points[i], 0.01*rot_speed); } //move pos.x += vx * speed; pos.y += vy * speed; //edge warp. wait til almost fully off screen if (vx > 0 && pos.x > width + 100) pos.x += -width-(2*100); if (vx < 0 && pos.x < -100) pos.x += width+(2*100); if (vy > 0 && pos.y > height + 100) pos.y += -height-(2*100); if (vy < 0 && pos.y < -100) pos.y += height+(2*100); //collision check again player if (player.alive && !player.dying) { float playerDist = dist(pos.x, pos.y, player.pos.x, player.pos.y); if (playerDist < radius) player.hit(); } } void draw() { if (!alive) return; fill(255); //ellipse(pos.x,pos.y,radius*2,radius*2); translate(pos.x, pos.y); //rotate(rot); stroke(0); fill(1); beginShape(); for (int i=0; i < points.length; i++) { //fientest of fill color Point cur_point = points[i]; vertex(cur_point.x, cur_point.y); } endShape(CLOSE); noFill(); //face shading for (int i=0; i < points.length; i++) { Point p1 = points[i]; Point p2 = (i == points.length-1 ? points[0] : points[i+1]); //get next point, or the first if we hit the end color c = 0; if (hp[i] > 0) { //show red if this face has already been hit int p = (4-size) - hp[i]; strokeWeight(4-p); c = color(200-(p*32), 0, 0); } else { //otherwise on show as grey if either vertex close to the player float d = min(dist(pos.x+p1.x, pos.y+p1.y, player.pos.x, player.pos.y), dist(pos.x+p2.x, pos.y+p2.y, player.pos.x, player.pos.y)); //get nearest if ( d < 2*scr_diag/3) { PVector av = new PVector(p2.x-p1.x, p2.y - p1.y); PVector arv = new PVector(av.y, -av.x); if (arv.dot(new PVector(player.pos.x - pos.x, player.pos.y - pos.y)) > 0) //is this facing towards the player? c = (int)map(d, 0, 2*scr_diag/3, 200, 0); } //c = 255; } stroke(c); strokeWeight(2); line(p1.x, p1.y, p2.x, p2.y); } //rotate(-rot); translate(-pos.x, -pos.y); } //check if point is within roid shape. checking triangle from centre to each face int containsPoint(float x, float y) { x -= pos.x; y -= pos.y; Point last_point = points[0]; Point centre = new Point(0, 0); for (int i = 1; i < points.length; i++) { Point cur_point = points[i]; if (pointInTriangle(centre, last_point, cur_point, x, y)) return i-1; last_point = cur_point; } if (pointInTriangle(centre, last_point, points[0], x, y)) return points.length-1; return -1; } //braycentric coordinate point in triangle check boolean pointInTriangle(Point p1, Point p2, Point p3, float x, float y) { float d = ((p2.y - p3.y)*(p1.x - p3.x) + (p3.x - p2.x)*(p1.y - p3.y)); float a = ((p2.y - p3.y)*(x - p3.x) + (p3.x - p2.x)*(y - p3.y)) / d; float b = ((p3.y - p1.y)*(x - p3.x) + (p1.x - p3.x)*(y - p3.y)) / d; float c = 1 - a - b; return 0 <= a && a <= 1 && 0 <= b && b <= 1 && 0 <= c && c <= 1; //if a,b, & c all 0-1, point inside } } //------------------------- //Bullet.pde //------------------------- class Bullet{ float x, y, vx, vy, speed; int lifetime, life; boolean alive; //A simple bullet Bullet(){ alive = false; } void spawn(float _x, float _y, float _vx, float _vy, int _life, float _s){ x = _x; y = _y; vx = _vx; vy = _vy; lifetime = _life; life = 0; speed = _s; alive = true; } void update(){ if(!alive) return; //move x += vx * speed; y += vy * speed; //asteroid manager collision check (check against every active Roid) rm.checkBullet(this); //lifetime if(++life > lifetime) alive = false; } void draw(){ if(!alive) return; stroke(255); fill(255); ellipse(x,y,5,5); } } //------------------------------ //Geom.pde //------------------------------ //simple class for x,y coordinates class Point { float x, y; Point(float _x, float _y) { x = _x; y = _y; } Point(Point p) { x = p.x; y = p.y; } void offset(float dx, float dy) { x += dx; y += dy; } void offset(Point p) { x += p.x; y += p.y; } String toString() { return "(x="+x+",y="+y+")"; } } //an updateablt/moveable polygon. only used as triangles class MobilePoly { Point pos; float vx, vy, speed, rot, rot_speed; Point[] points; MobilePoly(float x, float y, float _vx, float _vy, float _speed, float _rot, float _rotSpeed, Point[] _p) { vx = _vx; vy = _vy; speed = _speed; Point offset = findCentre(_p); //find centre point of triangle for rotation points = _p; for(int i=0; i < points.length; i++){ //reposition each point, ship ship local coordinates to poly local coords. points[i].offset(-offset.x, -offset.y); } pos = new Point(x, y); pos.offset(offset.x,offset.y); rot = _rot; rot_speed = _rotSpeed; } void update() { //move pos.x += vx * speed; pos.y += vy * speed; //rotate rot += 0.03 * rot_speed; //bounds if (rot > 2*PI) rot -= 2*PI; if (rot < 0) rot += 2*PI; //edge warp if (vx > 0 && pos.x > width) pos.x += -width; if (vx < 0 && pos.x < 0) pos.x += width; if (vy > 0 && pos.y > height) pos.y += -height; if (vy < 0 && pos.y < 0) pos.y += height; } void draw() { //draw triangle translate(pos.x, pos.y); rotate(rot); fill(255); stroke(255); beginShape(); vertex(points[0].x, points[0].y); vertex(points[1].x, points[1].y); vertex(points[2].x, points[2].y); endShape(CLOSE); rotate(-rot); translate(-pos.x, -pos.y); } //simple centre point calc, average sum of each point Point findCentre(Point[] p) { float x = 0, y = 0; for (int i = 0; i < p.length; i++) { if (p[i] != null) { x += p[i].x; y += p[i].y; } } return new Point(x/3, y/3); } } //--------------------------- //Particle.pde //--------------------------- class ExplosionManager { Explosion[] exps; //explosion pool ExplosionManager() { exps = new Explosion[10]; //prepare explosions; for (int i = 0; i<exps.length;i++) { exps[i] = new Explosion(); } } //start a new explosion void spawn(float x, float y, int c, int spread, int min_life, int max_life, int size) { for (int i = 0; i<exps.length;i++) { //search pool, find inactive if (!exps[i].alive) { exps[i].spawn(x, y, c, spread, min_life, max_life, size); break; } } } void update() { //update loop for (int i = 0; i<exps.length;i++) { exps[i].update(); } } void draw() { //draw loop for (int i = 0; i<exps.length;i++) { exps[i].draw(); } } } class Explosion { //a collection of particles boolean alive; Particle[] parts; int dead_count; Explosion() { alive = false; } void spawn(float x, float y, int c, int spread, int min_life, int max_life, int size) { //create new particles parts = new Particle[c]; for (int i=0; i < c; i++) { parts[i] = new Particle(this, x + random(-spread, spread), y + random(-spread, spread), (int)random(min_life, max_life), size, (int)random(0, min_life/4)); } dead_count = 0; alive = true; } void update() { //update loop if (!alive) return; for (int i=0;i<parts.length;i++) { if (parts[i] != null) parts[i].update(); } } void draw() { //draw loop if (!alive) return; for (int i=0;i<parts.length;i++) { if (parts[i] != null) parts[i].draw(); } } void dead(Particle p) { //listen for dead particles, die if all dead if (++dead_count == parts.length) alive = false; } } //lifetime base particle class Particle { Explosion ex; float x, y; int lifetime, life, size, delay; boolean alive; //instantiate and initiate Particle(Explosion e, float _x, float _y, int _life, int _s, int _delay) { ex = e; x = _x; y = _y; size = _s; lifetime = _life; alive = true; } void update() { //update loop if (!alive) return; if (delay > 0) delay--; else if (++life > lifetime) { //if life over, report death to parent explosion; alive = false; ex.dead(this); } } void draw() { if (!alive) return; if (delay <= 0) { noStroke(); float p = life/(lifetime*1.0f); //determine percentage of life used. casting as float (was going int otherwise?) int c = (int)map(p, 0, 1, 255, 0); //clamp red colour value; fill(c, 0, 0); ellipse(x, y, size*p, size*p); //draw, size base on life } } } //---------------------------- //Player.pde //---------------------------- class Player { Point pos; float rot, vx, vy, speed=0, accel; int w, h; boolean keyForward, keyLeft, keyRight, firing, alive, dying; Bullet[] bullets; int bullet_interval = 10, bullet_cooldown; int dying_time, dying_duration=60, tail_flick; MobilePoly[] fragments; int lives; Player(float x, float y) { alive = true; dying = false; lives = 3; pos = new Point(x, y); w = 20; h = 40; accel = 0; //prepare 15 bullets bullets = new Bullet[15]; for (int i = 0; i < bullets.length; i++) bullets[i] = new Bullet(); } void reset(){ //reset player for new life, same game alive = true; dying = false; //position in centre pos.x = width/2; pos.y = height/2; //kill velocity vx = 0; vy = 0; } void update() { //update loop if (!alive) return; if (dying) { //ship has been hit, scatter the seperate fragments of the ship for (int i = 0; i < fragments.length; i++) if (fragments[i] != null) fragments[i].update(); if (dying_time++ > dying_duration) { //Time to die die(); } } else { if (keyForward) { //if up key is held down, alter velocity along direction of rotation vx += sin(rot) * 0.1; vy += -cos(rot) * 0.1; speed += 0.1; speed = speed > 5 ? 5 : speed; } //if left/right keys held down, rotate ship rot += 0.06 * (keyLeft?-1:(keyRight?1:0)); //rotation bounds check if (rot > 2*PI) rot -= 2*PI; if (rot < 0) rot += 2*PI; //move pos.x += vx; pos.y += vy; //friction vx *= 0.98; vy *= 0.98; //edge warp if (vx > 0 && pos.x > width + h) pos.x += -width-(2*h); if (vx < 0 && pos.x < -h) pos.x += width+(2*h); if (vy > 0 && pos.y > height + h) pos.y += -height-(2*h); if (vy < 0 && pos.y < -h) pos.y += height+(2*h); //if space held down, shoot if (firing) { shoot(); } //update all bullets for (int i = 0; i < bullets.length; i++) bullets[i].update(); } } void die() { //fragment animation over, actually die alive = false; lives--; em.spawn(pos.x,pos.y,16,20,20,40,150); //final big explosion. this isn't always where the fragments end up if(lives < 0) //all lives lost, end the game changeState("gameOver"); } void hit() { //hit by an asteroid dying = true; dying_time = 0; //create ship fragments fragments = new MobilePoly[4]; //create a MobilePoly triangle object to represent 4 different parts of the ship Point[] p0 = { new Point(0, -h/2), new Point(w/4, 0), new Point(0, h/4) }; fragments[0] = new MobilePoly(pos.x, pos.y, vx, vy, speed, rot, random(-1, 1), p0); Point[] p1 = { new Point(w/4, 0), new Point(w/2, h/2), new Point(0, h/4) }; fragments[1] = new MobilePoly(pos.x, pos.y, vx, vy, speed, rot, random(-1, 1), p1); Point[] p2 = { new Point(0, -h/2), new Point(0, h/4), new Point(-w/4, 0) }; fragments[2] = new MobilePoly(pos.x, pos.y, vx, vy, speed, rot, random(-1, 1), p2); Point[] p3 = { new Point(0, 0+h/4), new Point(-w/2, +h/2), new Point(-w/4, 0) }; fragments[3] = new MobilePoly(pos.x, pos.y, vx, vy, speed, rot, random(-1, 1), p3); //mini explosion em.spawn(pos.x,pos.y,4,15,5,10,10); } void shoot() { if (!alive || dying) return; if (--bullet_cooldown > 0) //wait for cooldown before firing again return; PVector heading = PVector.fromAngle(rot-PI/2); //shoot base on rotation for (int i = 0; i < bullets.length; i++) { if (!bullets[i].alive) { //find a dead bullet and start it bullets[i].spawn(pos.x, pos.y, heading.x, heading.y, 100, 10); break; } } bullet_cooldown = bullet_interval; //start new cooldown wait } void draw() { if (!alive) return; for (int i = 0; i < bullets.length; i ++) //draw all the bullets bullets[i].draw(); if (dying) { for (int i = 0; i < fragments.length; i++) //draw all the fragments if (fragments[i] != null) fragments[i].draw(); } else { //normal play, draw the ship translate(pos.x, pos.y); rotate(rot); //ship fill(255); strokeWeight(1); stroke(255); beginShape(); vertex(0, -h/2); vertex(w/2, h/2); vertex(0, h/4); vertex(-w/2, h/2); endShape(CLOSE); if(keyForward){ //draw flickering exhaust tail tail_flick++; if(tail_flick%4 == 0){ stroke(255); strokeWeight(2); float sp = speed/5; line(-3*w/8, 0.7*h, 0, 0.7*h+(h*sp)); line( 3*w/8, 0.7*h, 0, 0.7*h+(h*sp)); if(sp > 0.3){ line(-3*w/8, 0.7*h, 0, 0.7*h+(h*sp*0.3)); line( 3*w/8, 0.7*h, 0, 0.7*h+(h*sp*0.3)); } if(sp > 0.6){ line(-3*w/8, 0.7*h, 0, 0.7*h+(h*sp*0.6)); line( 3*w/8, 0.7*h, 0, 0.7*h+(h*sp*0.6)); } } } rotate(-rot); translate(-pos.x, -pos.y); } } void keyPressed() { //input management if (key == 'w' || key == CODED && keyCode == UP) keyForward = true; if (key == 'a' || key == CODED && keyCode == LEFT) keyLeft = true; if (key == 'd' || key == CODED && keyCode == RIGHT) keyRight = true; if (key == ' ') { if(alive){ shoot(); firing = true; } else { reset(); } } } void keyReleased() { //input management if (key == 'w' || key == CODED && keyCode == UP) { //forward keyForward = false; accel = 0; tail_flick = 0; speed = 0; } if (key == 'a' || key == CODED && keyCode == LEFT) //rotate counter-clockwise keyLeft = false; if (key == 'd' || key == CODED && keyCode == RIGHT) //rotate clockwise keyRight = false; if (key == ' ') //shoot firing = false; } }
www.oscan.net
oscan.net (2024) All Rights Reserved.
[Login]