import java.awt.Color; import java.awt.GradientPaint; import java.awt.Graphics2D; import java.awt.Rectangle; import java.awt.Transparency; import java.awt.event.KeyEvent; import java.awt.geom.GeneralPath; import java.awt.image.BufferStrategy; import java.awt.image.BufferedImage; import java.util.Random; import javax.swing.JFrame; /* * Abducer 4K Game * Code Copyright 2007 - Alexander Hristov. http://www.ahristov.com/tutorial * * Code is provided AS IS for educational purposes. It cannot be posted publicly (either in * electronic or printed form) or used in any other way without permission. */ public class A extends JFrame { private static final int WIDTH = 800; private static final int HEIGHT = 600; private static final int MIN_Y = 50; private static final int SCR_HEIGHT = HEIGHT+50; private static final int STATE_PLAYING = 1; private static final int STATE_GAME_OVER = 2; private static final int STATE_INIT = 3; private static final int STATE_INIT_LEVEL = 4; private static final int STATE_LIFE_LOST = 5; private boolean key[] = new boolean[65535]; private static final double SCALE = 100; /* Image size is size * 8 */ private static final int IMAGE_BULLET = 1; private static final int IMAGE_PLAYER = 4; private static final int IMAGE_FLOWER = 8; private static final int MAX_FLOWER_TYPES = 5; private static final int IMAGE_GRAVE = 3; private static final int MAX_IMAGES = IMAGE_FLOWER+MAX_FLOWER_TYPES; private static final int MAX_FUEL = 3000; private static final int MAX_HEALTH = 3000; private static final int FUEL_SCALE = MAX_FUEL/200; private static final int HEALTH_SCALE = MAX_HEALTH/200; private static final int ITEM_EXPLOSION = 1; private static final int ITEM_GRAVE = 2; private static final int ITEM_PLAYER = 3; private static final int ITEM_STAR = 4; private static final int ITEM_BULLET = 5; private static final int ITEM_ANIMAL = 6; private static final int MAX_ITEMS = 100; private static final int STATUS_LINE = 70; private static final int SCORE_POSITION = 200; private static final int LIVES_POSITION = SCORE_POSITION + 150; private static final int FUEL_POSITION = LIVES_POSITION + 160; private static final int HEALTH_POSITION = 50; private static final int SURFACE_HEIGHT = HEIGHT-150; private static final int MAX_WORMHOLE_COUNTER=10; private static final int PLAYER_SIZE = 32; /** Animal states */ private static final int STATE_NORMAL = 0; // Normal private static final int STATE_SUCKED = 2; // Sucked by the beam private static final int STATE_WORMHOLE = 3; // Falling into the wormhole /** Behaviours */ private static final int BEHAVIOUR_STILL = 0; // Stay still private static final int BEHAVIOUR_JUMP =1 ; // Jump randomly //private static final int BEHAVIOUR_FLY =2 ; // Fly randomly private static final int BEHAVIOUR_CRAWL =2 ; // Crawl /** Firing behaviours */ private static final int FIRE_NONE = 0; // Fire upwards private static final int FIRE_UP = 1; // Fire upwards private static final int FIRE_PLAYER = 2; // Fire towards the player /** Otherworld */ private static final int MAX_STARS = 30; /** Planet Surface */ private static final int PLANET_MARGIN = 30; private static final int FACE_OFFSET_X = 16; private static final int FACE_OFFSET_Y = 16; private static final int FLOWER_SIZE = 32; private static final int FLOWER_KILL_SPEED = 160; public static void main(String[] x) throws Exception { new A(); } public A() { setSize(WIDTH,SCR_HEIGHT); setResizable(false); /************************************************************* * GLOBAL INITIALIZATION *************************************************************/ int[] itemType = new int[MAX_ITEMS]; int[] itemX = new int[MAX_ITEMS]; int[] itemY = new int[MAX_ITEMS]; int[] itemVX = new int[MAX_ITEMS]; int[] itemVY = new int[MAX_ITEMS]; int[] itemImage = new int[MAX_ITEMS]; int[] itemStartY = new int[MAX_ITEMS]; int[] itemState = new int[MAX_ITEMS]; int[] itemBehaviour = new int[MAX_ITEMS]; int[] itemFireTimer = new int[MAX_ITEMS]; int[] itemFireFrequency = new int[MAX_ITEMS]; int[] itemFireStance = new int[MAX_ITEMS]; int[] itemTimer = new int[MAX_ITEMS]; int[] planetHeight = new int[WIDTH]; Random rnd = new Random(); BufferedImage[] images = new BufferedImage[MAX_IMAGES]; int steps; int state = STATE_INIT; int score = 0; int lives = 5; int level = 0; int animals = 0; int weight; int planetMass = 0; int sunRadius; int wormholeX = 0; int wormholeY = 0; int wormholeRX; int wormholeRY; int sunX; int sunY; int x,y,i,slot; Graphics2D g; GeneralPath planet = new GeneralPath(); GeneralPath suckBeam = new GeneralPath(); GeneralPath wormhole = new GeneralPath(); GeneralPath path = new GeneralPath(); Rectangle player = null; BufferedImage scenery = null; BufferedImage earth = null; for (i = 1; i < MAX_IMAGES; i++) // BOTH WINDOWS AND LINUX images[i] = new BufferedImage(i*8,i*8,BufferedImage.TYPE_INT_ARGB); // Bullet image g = images[IMAGE_BULLET].createGraphics(); g.setColor(new Color(0x008000)); g.fillOval(0,0,8,8); g.setColor(new Color(0x00EC00)); g.fillOval(2,2,4,4); // Player image g = images[IMAGE_PLAYER].createGraphics(); // Capsule g.setPaint( new GradientPaint(9,6,new Color(0xffffff),24,20,new Color(0x0),true)); g.fillOval(4,4,24,24); g.setColor(new Color(0x0)); g.drawOval(4,4,24,24); g.setColor(new Color(0xf19b8e)); g.fillRect(13,17,6,5); g.setColor(new Color(0x0)); g.drawRect(13,17,6,5); // Soccer g.setPaint( new GradientPaint(0,23,new Color(0xff),0,30,new Color(0x0),true)); g.fillOval(0,21,32,10); // Head g.setColor(new Color(0xf19b8e)); g.fillOval(7,10,18,8); g.setColor(new Color(0x0)); g.drawOval(7,10,18,8); // Eyes g.setColor(new Color(0xff)); g.fillOval(10,13,2,2); g.setColor(new Color(0x0)); g.drawOval(10,13,2,2); g.setColor(new Color(0xff)); g.fillOval(19,13,2,2); g.setColor(new Color(0x0)); g.drawOval(19,13,2,2); // Mouth g.drawLine(14,15,17,15); // Antenas g.drawLine(24,6,30,1); g.drawLine(7,6,1,1); // END of image img g = images[IMAGE_GRAVE].createGraphics(); g.setColor(new Color(0x808000)); path.reset(); path.moveTo(3,11); path.lineTo(0,20); path.lineTo(12,20); path.lineTo(9,11); path.closePath(); g.fill(path); g.setColor(new Color(0x0)); g.draw(path); g.fillRect(5,0,3,15); g.fillRect(1,3,11,3); g.fillRect(0,20,13,3); //int[] itemHeight = new int[MAX_ITEMS]; int itemHeight=0; int fuel = MAX_FUEL; int health = MAX_HEALTH; enableEvents(8); show(); createBufferStrategy(2); BufferStrategy strategy = getBufferStrategy(); setDefaultCloseOperation(EXIT_ON_CLOSE); while (true) { long frameStart=System.currentTimeMillis(); while (System.currentTimeMillis()-frameStart < 20) Thread.yield(); if (state == STATE_INIT || state == STATE_INIT_LEVEL) { // LEVEL INITIALIZATION if (state == STATE_INIT) { // GAME INITIALIZATION score = 0; lives = 5; level = 0; health = MAX_HEALTH; } // Scenery generation // WINDOWS: scenery = new BufferedImage(WIDTH,SCR_HEIGHT,BufferedImage.TYPE_INT_RGB); // LINUX : //scenery = getGraphicsConfiguration().createCompatibleImage(WIDTH,SCR_HEIGHT,Transparency.OPAQUE); g = scenery.createGraphics(); Color sunColor=null; Color skyStart; Color skyEnd; Color soilStart; Color soilEnd; sunX = rnd.nextInt(WIDTH); sunY = rnd.nextInt(HEIGHT); sunRadius = (level%30)*10; planetMass = (level%26)*10; if (sunRadius < 75) { sunColor = Color.getHSBColor(237/360f,sunRadius/75f,1f-sunRadius*0.008f); } else { sunColor = Color.getHSBColor((81-sunRadius*0.27f)/360f,1f,1f); } if (sunRadius < 75) { skyStart = new Color(0); skyEnd = new Color(50,50,50); soilStart = new Color(20+2*sunRadius,20+2*sunRadius,20+2*sunRadius); soilEnd = new Color(sunRadius,sunRadius,sunRadius); } else if (sunRadius < 150) { skyStart = new Color(255,255-sunRadius+75,255-sunRadius+75); skyEnd = new Color(2*(sunRadius-75),255-2*sunRadius+75,255-2*sunRadius+75); soilStart = new Color(sunRadius/3,sunRadius,0); soilEnd = new Color(0,50,0); } else { skyStart = new Color(100+sunRadius/6,0,0); skyEnd = new Color(200+sunRadius/6,0,0); soilStart = new Color(255-sunRadius+50,0,0); soilEnd = new Color(0,0,0); } g.setPaint(new GradientPaint(0,0,skyStart,0,SURFACE_HEIGHT,skyEnd)); g.fillRect(0,0,WIDTH,SCR_HEIGHT); // Sun g.setColor(sunColor); g.fillOval(sunX-sunRadius,sunY-sunRadius,2*sunRadius,2*sunRadius); wormholeRX = 150-planetMass/2; wormholeRY = 75-planetMass/4; wormholeX = rnd.nextInt(WIDTH-2*wormholeRX)+wormholeRX; wormholeY =100+planetMass; wormhole.reset(); wormhole.moveTo(wormholeX-wormholeRX,wormholeY); wormhole.quadTo(wormholeX,wormholeY-wormholeRY,wormholeX+wormholeRX,wormholeY); wormhole.quadTo(wormholeX,wormholeY+wormholeRY,wormholeX-wormholeRX,wormholeY); wormhole.closePath(); // wormhole g.setColor(new Color(0)); g.fill(wormhole); g.setColor(new Color(0x303030)); g.draw(wormhole); //steps = 27-planetMass/10; // The bigger the sun radius, the bigger the rugosity // 0 - 300 //int b = 5+sunRadius/5+planetMass/5; //int a = 5+sunRadius/10+planetMass/10; // Planet surface initialization planet.reset(); planet.moveTo(0,SURFACE_HEIGHT); planet.lineTo(PLANET_MARGIN, SURFACE_HEIGHT); int prevY = SURFACE_HEIGHT; x = PLANET_MARGIN; int deltaX = (WIDTH-2*PLANET_MARGIN)/25; for (i = 1; i < 25; i++) { int y1 =rnd.nextInt(50)-rnd.nextInt(50); if (prevY+y1 > HEIGHT) y1 = -y1; if (prevY+y1 < wormholeY+wormholeRY) y1 = -y1; int y2 =rnd.nextInt(50)-rnd.nextInt(50); if (prevY+y1+y2 < wormholeY+wormholeRY) y2=-y2; if (prevY+y1+y2 > HEIGHT) y2= -y2; planet.quadTo(x+deltaX/2,prevY+y1,x+deltaX,prevY+y1+y2); prevY += y1+y2; x+=deltaX; } //planet.lineTo(WIDTH-PLANET_MARGIN,SURFACE_HEIGHT); planet.lineTo(WIDTH+PLANET_MARGIN,SURFACE_HEIGHT); planet.lineTo(WIDTH+PLANET_MARGIN,SCR_HEIGHT); planet.lineTo(0,SCR_HEIGHT); //planet.closePath(); // LINUX: //earth = getGraphicsConfiguration().createCompatibleImage(WIDTH,SCR_HEIGHT,Transparency.BITMASK); // WINDOWS: earth = new BufferedImage(WIDTH,SCR_HEIGHT,BufferedImage.TYPE_INT_ARGB); g = earth.createGraphics(); g.setPaint(new GradientPaint(0,SURFACE_HEIGHT,soilStart,0,HEIGHT,soilEnd)); g.fill(planet); for (i = 0; i < WIDTH; i++) for (planetHeight[i]=HEIGHT-1; planetHeight[i] > 0 && earth.getRGB(i,planetHeight[i]) !=0; planetHeight[i]-- ) { } itemType = new int[MAX_ITEMS]; itemImage = new int[MAX_ITEMS]; itemX = new int[MAX_ITEMS]; itemY = new int[MAX_ITEMS]; itemStartY = new int[MAX_ITEMS]; itemVX = new int[MAX_ITEMS]; itemVY = new int[MAX_ITEMS]; itemTimer = new int[MAX_ITEMS]; itemState = new int[MAX_ITEMS]; itemBehaviour = new int[MAX_ITEMS]; itemFireTimer = new int[MAX_ITEMS]; itemFireFrequency = new int[MAX_ITEMS]; itemFireStance = new int[MAX_ITEMS]; fuel = MAX_FUEL; // Place the player itemX[0] = WIDTH/2; itemY[0] = 25; itemType[0] = ITEM_PLAYER; itemImage[0] = IMAGE_PLAYER; // Initial item population - level initialization animals = level % 10+1; // Up to 10 flowers //animals = 0; for (i = 1; i <= animals+MAX_STARS; i++) { if (i > animals) { itemX[i] = rnd.nextInt(WIDTH); itemY[i] = wormholeY-wormholeRY/2+rnd.nextInt(wormholeRY); itemVX[i] = rnd.nextInt(30)+20; itemType[i] = ITEM_STAR; itemFireFrequency[i]= rnd.nextInt(4)+2; // Radius //itemFireTimer[i]= rnd.nextInt(100)+155; // Color } else { itemBehaviour[i] = rnd.nextInt(BEHAVIOUR_CRAWL+1); itemImage[i] = IMAGE_FLOWER+rnd.nextInt(MAX_FLOWER_TYPES); itemX[i] = rnd.nextInt(WIDTH-2*PLANET_MARGIN-2*FLOWER_SIZE)+PLANET_MARGIN; itemY[i]= planetHeight[itemX[i]+2*FLOWER_SIZE]-2*FLOWER_SIZE; if (itemBehaviour[i] == BEHAVIOUR_CRAWL) { itemVX[i] = rnd.nextInt(100)-50; } itemType[i] = ITEM_ANIMAL; itemStartY[i] = itemY[i]; itemFireFrequency[i] = 300-(level%20)*5; itemFireTimer[i] = rnd.nextInt(itemFireFrequency[i]); //itemFireStance[i] = level % (FIRE_UP+1); itemFireStance[i] = FIRE_PLAYER; } } // Flower initialization // // Flower - START ************************************ // for (int flower = 0; flower < 5; flower++) { images[IMAGE_FLOWER+flower] = // BOTH WINDOWS AND LINUX new BufferedImage(2*FLOWER_SIZE,2*FLOWER_SIZE,BufferedImage.TYPE_INT_ARGB); g = images[IMAGE_FLOWER+flower].createGraphics(); path.reset(); steps = rnd.nextInt(10)+3; int upsize = FLOWER_SIZE/5; int aperture = rnd.nextInt(5)+5; int cp = rnd.nextInt(5)+3; path.moveTo(FLOWER_SIZE/2-aperture,upsize+FLOWER_SIZE); int[] fx = new int[2*cp+3]; int[] fy = new int[2*cp+3]; fx[2*cp+2] = FLOWER_SIZE/2-aperture; fy[2*cp+2] = upsize+FLOWER_SIZE; for (i = cp; i >= 0; i--) { fx[2*i] = rnd.nextInt(FLOWER_SIZE/2); fy[2*i] = upsize+FLOWER_SIZE/cp*i; fx[2*i+1] = rnd.nextInt(FLOWER_SIZE/2); fy[2*i+1] = upsize+fy[2*i]+rnd.nextInt(FLOWER_SIZE/cp*(i+1)-FLOWER_SIZE/cp*i); path.quadTo(fx[2*i+1],fy[2*i+1],fx[2*i],fy[2*i]); } path.quadTo(FLOWER_SIZE/2,upsize+rnd.nextInt(upsize)-2*upsize,FLOWER_SIZE-fx[0],upsize); for (i = 0; i <= cp; i++) { path.quadTo(FLOWER_SIZE-fx[2*i+1],fy[2*i+1],FLOWER_SIZE-fx[2*i+2],fy[2*i+2]); } path.closePath(); double angle = 2*Math.PI/steps; g.translate(FLOWER_SIZE/2,0); int rr = rnd.nextInt(100)+155; int gg = rnd.nextInt(100)+155; int bb = rnd.nextInt(100)+155; for (i = 0; i <= steps; i++) { g.setPaint(new GradientPaint(0,0,new Color(rr,gg,bb),FLOWER_SIZE,FLOWER_SIZE,new Color(0))); g.fill(path); g.setColor(new Color(0)); g.draw(path); g.rotate(-angle,FLOWER_SIZE/2,FLOWER_SIZE); } int kernelSize = 10; g = images[IMAGE_FLOWER+flower].createGraphics(); g.setColor(new Color(0)); g.fillOval(FLOWER_SIZE-kernelSize,FLOWER_SIZE-kernelSize,2*kernelSize,2*kernelSize); g.setColor(Color.yellow); g.fillOval(FLOWER_SIZE-kernelSize+1,FLOWER_SIZE-kernelSize+1,2*kernelSize-2,2*kernelSize-2); // // Flower - END ************************************ // } state = STATE_PLAYING; } /***************************************************************** * EVOLUTION *****************************************************************/ if (key[KeyEvent.VK_ENTER]) { if (state == STATE_LIFE_LOST ) { health = MAX_HEALTH; state = STATE_INIT_LEVEL; } if (state == STATE_GAME_OVER) { state =STATE_INIT ; } } if (state == STATE_PLAYING) { // Player evolution (as long as we are playing) suckBeam.reset(); if (key[KeyEvent.VK_UP] && fuel > 0 ) { itemVY[0] -= 10;fuel--; } if (key[KeyEvent.VK_DOWN] && fuel > 0) { itemVY[0] += 10;fuel--; } if (key[KeyEvent.VK_LEFT] && fuel > 0 && itemVX[0] > -500) { itemVX[0] -= 10;fuel--; } if (key[KeyEvent.VK_RIGHT] && fuel > 0 && itemVX[0] < 500) { itemVX[0] += 10;fuel--; } if (key[KeyEvent.VK_SPACE] && fuel > 0) { int xc = itemX[0]+PLAYER_SIZE/2; int yc = itemY[0]+PLAYER_SIZE/2; suckBeam.moveTo(xc,yc); suckBeam.lineTo(xc-50,yc+150); suckBeam.lineTo(xc+50,yc+150); suckBeam.closePath(); fuel--; } // Item evolution weight = 0; for (i = 0; i < MAX_ITEMS; i++) { if (itemType[i] <= ITEM_GRAVE) continue; if (itemType[i] == ITEM_STAR) { itemX[i] = (int)(itemVX[i]/10+itemX[i])%WIDTH; continue; } itemTimer[i]++; itemFireTimer[i]++; if (itemState[i] == STATE_WORMHOLE) { if (itemTimer[i] >= MAX_WORMHOLE_COUNTER) { // Finally sucked into the wormhole : award score and // decrease number of animals remaining if (i == 0) { // IF we are sucked into the wormhole it is because // we have completed the level. Thus - init a new one state = STATE_INIT_LEVEL; level++; score+=50*level; } if (itemType[i] == ITEM_ANIMAL) { animals--; score+=50*(level+1); fuel += planetMass*2; if (fuel > MAX_FUEL) fuel = MAX_FUEL; } itemType[i] = 0; } } else { // First compute our height //itemHeight[i]= planetHeight[itemX[i]+itemImage[i]*4]-itemY[i]-itemImage[i]*4; int size; if (itemType[i] == ITEM_ANIMAL) { size = 30; itemHeight = planetHeight[itemX[i]+30]-itemY[i]-3*FLOWER_SIZE+2; } else { size = 4*itemImage[i]; itemHeight = planetHeight[itemX[i]+itemImage[i]*4]-itemY[i]-itemImage[i]*4; } // ------------------------------------------------------ // PLANET COLLISION CHECK : START //------------------------------------------------------ if (itemHeight <= 0 && itemState[i] != STATE_SUCKED) { // We have if (i == 0) { // If it's the player - spawn an explosion health = health-(int)(3*itemVY[0]*itemVY[0]/500+6); if (health <= 0) slot =0; else for (slot = 1; slot < MAX_ITEMS -1 && itemType[slot] != 0; slot++); itemType[slot] = ITEM_EXPLOSION; itemState[slot] = STATE_NORMAL; itemVX[slot] = 0; itemVY[slot] = 0; itemTimer[slot] = 0; itemX[slot] = itemX[0]; itemY[slot] = itemY[0]; } else if (itemType[i] == ITEM_BULLET) { // If it's a bullet - remove it itemType[i] = 0; } else { // It's a flower. If falling too fast, kill it if (itemVY[i] > FLOWER_KILL_SPEED) { animals--; itemType[i] = ITEM_GRAVE; // Killed itemImage[i] = IMAGE_GRAVE; itemY[i]+=64; } } itemY[i] = itemY[i]+itemHeight; // Make height = 0; itemVY[i] = -itemVY[i]/4; if (itemVY[i] >= -10) itemVY[i] = 0; } // ------------------------------------------------------ // PLANET COLLISION CHECK : END //------------------------------------------------------ // ------------------------------------------------------ // GRAVITY ACTION : START //------------------------------------------------------- //double t = delta/SCALE; //double dy = ; itemVY[i] = (int)(itemVY[i]+1e7*planetMass/((itemY[i]-10000)*(itemY[i]-10000))*4/10.0); // ------------------------------------------------------ // GRAVITY ACTION : END //------------------------------------------------------ boolean onSurface = itemHeight < 10 && itemVY[i]*itemVY[i]<2500; if (itemType[i] == ITEM_ANIMAL) { if (itemState[i] == STATE_NORMAL) { // ------------------------------------------------------ // MOVEMENT : START //------------------------------------------------------ // Behaviour changes that take place over time if(itemTimer[i] % 100 == 0) { if (itemBehaviour[i] == BEHAVIOUR_JUMP && onSurface) { itemVY[i] = -40-rnd.nextInt(100); itemVX[i] = rnd.nextInt(100)-40; onSurface = false; } } if (itemBehaviour[i] != BEHAVIOUR_CRAWL && onSurface ) { // Try to stop if (itemVX[i]*itemVX[i] > 0) itemVX[i]/=2; itemY[i]= planetHeight[itemX[i]+2*FLOWER_SIZE]-2*FLOWER_SIZE; } // ------------------------------------------------------ // MOVEMENT : END //------------------------------------------------------ // ------------------------------------------------------ // FIRING : START //------------------------------------------------------ if (itemFireStance[i] != FIRE_NONE && itemFireTimer[i] >= itemFireFrequency[i]) { itemFireTimer[i] = 0; // Find slot for (slot = 1; slot < MAX_ITEMS -1 && itemType[slot] != 0; slot++); if (slot == MAX_ITEMS-1) { } if (itemFireStance[i] == FIRE_UP) { itemVX[slot] = 0; itemVY[slot] = -rnd.nextInt(30)*10; } if (itemFireStance[i] == FIRE_PLAYER) { double a = Math.atan2(itemY[0]-itemY[i],itemX[0]-itemX[i]); itemVX[slot] = (int)(400*Math.cos(a)); itemVY[slot] = (int)(400*Math.sin(a)); } itemX[slot] = itemX[i]+30; itemY[slot] = itemY[i]-1; itemFireStance[slot] = FIRE_NONE; itemType[slot] = ITEM_BULLET; itemImage[slot] = IMAGE_BULLET; itemState[slot] = STATE_NORMAL; } // ------------------------------------------------------ // FIRING : END //------------------------------------------------------ } // ------------------------------------------------------ // TRACTOR BEAM : START //------------------------------------------------------ if (suckBeam.contains(itemX[i]+30,itemY[i]+FLOWER_SIZE) && weight < 5) { itemVX[i] = (itemX[0]-itemX[i])*3; itemVY[i] = -20 + planetMass/25; weight += 2; itemState[i] = STATE_SUCKED; } else { itemState[i] = STATE_NORMAL; } } // ------------------------------------------------------ // TRACTOR BEAM END //------------------------------------------------------ // ------------------------------------------------------ // POSITION UPDATE : START //------------------------------------------------------ itemX[i] = (int)(itemX[i]+4*itemVX[i]/100.0); itemY[i] = (int)(itemY[i]+4*itemVY[i]/100.0); if (itemX[i] > WIDTH-itemImage[i]*8) itemX[i] = 5; if (itemX[i] < 5) itemX[i] = WIDTH-itemImage[i]*8-2; if (itemY[i] <= MIN_Y) { if (itemType[i] == ITEM_BULLET) itemType[i] = 0; else { itemY[i] = MIN_Y; if (itemVY[i] < 40) itemVY[i] = 40; } } // ------------------------------------------------------ // POSITION UPDATE : END //------------------------------------------------------ // ------------------------------------------------------ // WORMHOLE START //------------------------------------------------------ if (wormhole.contains(itemX[i]+size,itemY[i]+size) && (i >0 || (i == 0 && animals == 0))) { itemState[i] = STATE_WORMHOLE; itemTimer[i] = 0; } // ------------------------------------------------------ // WORMHOLE END //------------------------------------------------------ if (i == 0) player = new Rectangle(itemX[0],itemY[0],PLAYER_SIZE,PLAYER_SIZE); // ------------------------------------------------------ // COLLISION WITH PLAYER //------------------------------------------------------ if (itemType[i] == ITEM_BULLET){ if (player.contains(itemX[i], itemY[i])) { itemType[i] = ITEM_EXPLOSION; itemTimer[i] = 0; health = health - 20*(level%15); } if (itemX[i] <0 || itemY[i] < 0 || itemX[i] > WIDTH) { itemType[i] = 0; } } } if (health <= 0) { lives--; if (lives <=0 ) state = STATE_GAME_OVER; else state = STATE_LIFE_LOST; } } } /****************************************************************** * SCREEN UPDATE ******************************************************************/ g = (Graphics2D)strategy.getDrawGraphics(); // Draw scenery g.drawImage(scenery,0,0,null); // Draw suction beam, if space key is on if (key[KeyEvent.VK_SPACE] && itemState[0] != STATE_WORMHOLE) { // WINDOWS : g.setColor(new Color(255,255,0,80)); // LINUX : //g.setColor(new Color(255,255,)); //g.setColor(new Color(0xFFFFC0)); g.fill(suckBeam); } g.drawImage(earth,0,0,null); // Draw items for (i = 0; i < MAX_ITEMS; i++) { if (itemType[i] != 0) { if (itemType[i] == ITEM_STAR) { g.setClip(wormhole); g.setColor(new Color(0xFFFFFF)); g.fillOval( itemX[i]-itemFireFrequency[i], itemY[i]-itemFireFrequency[i], 2*itemFireFrequency[i],2*itemFireFrequency[i]); g = (Graphics2D)strategy.getDrawGraphics(); } else if (itemType[i] == ITEM_EXPLOSION) { int r1 = itemTimer[i]; if (r1 > 15) r1 = 15; g.setColor(new Color(255,255-r1*10,0)); g.fillOval(itemX[i]-r1+16,itemY[i]-r1+16,2*r1,2*r1); if (itemTimer[i] > 15) { g.setColor(new Color(r1*10,0,0)); r1 = itemTimer[i]-15; g.fillOval(itemX[i]-r1+16,itemY[i]-r1+16,2*r1,2*r1); } itemTimer[i]++; if (itemTimer[i] > 30) // If it's our ship the one who's exploding, it is because // we lost a life. Keep it this way. if (i != 0) itemType[i] = 0; else itemTimer[i] = 0; } else { //int originalSizeX =itemImage[i]*8; //int originalSizeY =itemImage[i]*8; int scaledSizeX=itemImage[i]*8; int scaledSizeY=itemImage[i]*8; x = itemX[i]; y = itemY[i]; if (itemState[i] ==STATE_WORMHOLE) { //if (i == 0) System.out.println(MAX_WORMHOLE_COUNTER-itemTimer[i]); scaledSizeX = itemImage[i]*8*(MAX_WORMHOLE_COUNTER-itemTimer[i])/MAX_WORMHOLE_COUNTER; scaledSizeY = itemImage[i]*8*(MAX_WORMHOLE_COUNTER-itemTimer[i])/MAX_WORMHOLE_COUNTER; x = (wormholeX-x)*itemTimer[i]/MAX_WORMHOLE_COUNTER+x; y = (wormholeY-y)*itemTimer[i]/MAX_WORMHOLE_COUNTER+y; /*if (i == 0) System.out.println(x+" "+y+" "+(x+scaledSizeX-1)+" "+(y+scaledSizeY-1)+" <- "+ "0 0 "+(originalSizeX-1)+" "+(originalSizeY-1)+ " "+(scaledSizeX)+" "+scaledSizeY);*/ } if (itemType[i] == ITEM_ANIMAL) { // Stem g.setColor(new Color(0x005500)); g.fillRect(itemX[i]+30,itemY[i]+30,2,2*FLOWER_SIZE); } g.drawImage(images[itemImage[i]], x,y,x+scaledSizeX-1,y+scaledSizeY-1, 0,0,itemImage[i]*8-1,itemImage[i]*8-1,null); // Draw a face according to what the critter is doing if (itemType[i] == ITEM_ANIMAL && itemState[i] != STATE_WORMHOLE) { // Draw eyes and mouth g.translate(itemX[i]+FACE_OFFSET_X,itemY[i]+FACE_OFFSET_Y); if (itemVY[i]*itemVY[i] > 10000) { // Panicked g.setColor(new Color(0x0)); g.fillOval(13,18,5,3); g.fillOval(11,11,5,5); g.fillOval(16,11,5,5); g.setColor(new Color(0xFFFFFF)); g.fillOval(12,12,3,3); g.fillOval(17,12,3,3); } else { g.setColor(new Color(0x0)); if (itemState[i] == STATE_SUCKED) { // Disgusted g.drawArc(13, 17, 6, 4, 180, -180); } else { // Smiling g.drawArc(13, 17, 6, 4, 0, -180); } g.setColor(new Color(0x0)); g.fillOval(12,12,4,4); g.fillOval(17,12,4,4); g.setColor(new Color(0xFFFFFF)); g.fillOval(13,13,1,1); g.fillOval(18,13,1,1); } } g = (Graphics2D)strategy.getDrawGraphics(); } } } // Draw Score g.setColor(new Color(0x00FF00)); g.drawString(String.valueOf(score),SCORE_POSITION+75,STATUS_LINE+16); if (state == STATE_GAME_OVER) { g.drawString("GAME OVER",250,250); } // Draw lives for (i = 0; i < lives; i++) { g.drawImage(images[IMAGE_PLAYER], LIVES_POSITION+20*i,STATUS_LINE, LIVES_POSITION+20*i+16,STATUS_LINE+16,0,0,PLAYER_SIZE,PLAYER_SIZE,null); } // Game over text (if necessary) g.setColor(new Color(0x0)); // Health g.fillRect(HEALTH_POSITION,STATUS_LINE,MAX_HEALTH/HEALTH_SCALE+2,18); g.fillRect(FUEL_POSITION,STATUS_LINE,MAX_FUEL/FUEL_SCALE+2,18); g.setColor(new Color(0x00FF00)); g.fillRect(HEALTH_POSITION+1, STATUS_LINE+1, health/HEALTH_SCALE,16); // fuel g.setColor(new Color(0xFF0000)); g.fillRect(FUEL_POSITION+1, STATUS_LINE+1, fuel/FUEL_SCALE, 16); //g.dispose(); strategy.show(); } } protected void processKeyEvent(KeyEvent e) { key[e.getKeyCode()] =e.getID() == KeyEvent.KEY_PRESSED; } } /** Size log -------- 2301 - Basic game mechanics, some graphics 2458 - Full game mechanics, disappearance effect into wormhole, fuel 2485 - Multiple item loop 2539 - Two behaviours (static, jumping) 2673 - Blood splash effect due to high falls. 2726 - 3 behaviours (static, jumping, flying) 2927 - Surface position determination, codified planet data 3122 - Final player image, blood image 3253 - Explosions, Health, losing lives and game over -- Optimized size : 3166 3297 - Level completion & animal count 3347 - Basic Flower graphic 3427 - Cool star effect in wormhole 3475 - Updated imageSizes array to allow for non-square sprites 3426 - Removed Color.xxx constant references 3583 - Cool faces :-) 3654 - Height calculation. Tongue pulling when player dies :-) 3699 - Stems drawn joined to earth where appropriate 3807 - Codifed level data, one level 3989 - 6 different planets 3996 - Random level generation 4005 - Proper animal distribution 4166 - Merged stars with main item array 4134 - Removed level complete message and pause. Now action goes directly to the next level 4156 - Moved terrain generation parameters as level data 4073 - Removed crawling behaviour, removed stem drawing. 4002 - Removed planet height calculation (unneeded without the above) 3999 - Simplified collision detection with screen edges 4084 - Firing towards player 3946 - Blood removed, sniff :-( 4053 - Replaced blood with grave effect, which is equally cool :-) 4013 - Replaced double[] arrays with int[] arrays 3979 - Converted *everything* to procedural : procedural flowers, procedural level generation, etc. 4040 - Big code simplification. Crawling behaviour is back! :-) Bigger flowers - 3856 4028 BUGS: - Realistic collisions - Make sure that the wormhole doesn't go into the surface */