Kevins Tower Defense Game

<< Suren's Animation | OldProjectsTrailIndex | Site.Josh's Tug of Word >>

here's what I have so far:



/** this class in essence:
 * 
 * draws the tower
 * 
 * gives it a fire speed
 * 
 * needs cost
 *
 */

import java.awt.*;



public class Tower {

	private int speed;
	private int cost; 
	private int dir;
	private int x;
	private int y;

	public Tower(Graphics g, int x0, int y0){
		x=x0;
		y=y0;

		if(y>25&&y<75){dir=1;}
		else{if(y>325&&y<375){dir=2;}}

		drawTower(g,x,y);

		speed = 10;
		cost = 5; 

	}

	public void drawTower(Graphics g, int x, int y){
		g.setColor(Color.CYAN);
		g.drawRect(x,y, 20,20);
	}

	public int getX(){
		return x;
	}

	public int getY(){
		return y;
	}

	public int getDir()
	{
		return dir;
	}

	public int getSpeed()
	{
		return speed; 
	}

	public int getCost()
	{
		return cost;
	}
}



import java.awt.geom.*;
import java.awt.*;

/**
 * this class will give the projectile: 
 * 
 * it's speed
 * it's direction
 * it's size
 * it's shape
 * it's damage
 *
 */
public class Projectile  {

	private int speed;
	private int direction;
	private int damage; 
	private int x;
	private int y; 

	public Projectile(Graphics g, int x0, int y0, int dir){

		x=x0+5;
		y=y0+5;


		direction = dir;
		speed = 2;
		damage= 1; 

		drawProjectile(g);
	}
	public void move(){
	if(direction == 1){y=y+1;}	
	else{y=y-1;}

	}

	public void drawProjectile(Graphics g){g.setColor(Color.RED); g.drawRect(x,y,5,5); }

	public int getX(){
		return x;
	}

	public int getY(){
		return y;
	}
	public int getDamage(){return damage;}

	public int getDirection(){return direction;}

	public int getSpeed(){return speed;}
	public boolean intersects(Monster m){
		Rectangle a = new Rectangle(x,y,5,5);
		Rectangle b = new Rectangle (m.getX(), m.getY(), 30,30);
		return a.intersects(b);

	}

	public void removePro(Graphics g){
		g.setColor(Color.BLACK); 
		g.drawRect(x,y,5,5); 
	}
}




import java.awt.*;
import java.awt.geom.*;

/**
 * pretty much goes about moving and walking
 * 
 * goes and moves itselfness
 * needs a direction, 
 * needs a speed
 * needs an amount of "life"
 * needs value
 * 
 *
 */
public class Monster  {

	private int x;
	private int y;
	private int health;

	public Monster(Graphics g){
		x=0;
		y=200;
		health = 3;
		drawMonster(g);

	}

	public void drawMonster(Graphics g){
		g.setColor(Color.GREEN);
		g.drawRect(x,y,30,30);
	}

	public void move(){
		x+=1;
	}

	public void removeMonster(Graphics g){
		g.setColor(Color.BLACK);
		g.drawRect(x,y,30,30);
	}

	public int getHealth(){
		return health;
	}
	public int getX(){
		return x;
	}

	public int getY(){
		return y;
	}

	public void hit(){
		health--;

	}
}

import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.applet.*;
import java.util.*;

import javax.swing.Timer;

/**
 * creates a world, onto which the tower and such will be placed
 * 
 * Black background, etc. 
 * 
 *
 */
public class World extends Applet
implements MouseListener, ActionListener
{


	Graphics gBuffer;
    ArrayList<Tower> chocolate = new ArrayList<Tower>();
	ArrayList<Projectile> project = new ArrayList<Projectile>();
	ArrayList<Monster> monsty = new ArrayList<Monster>();
    Image virtualMem;
    int appletWidth;        
    int appletHeight;
    Timer projectilemovetimer;
    Timer fireTimer;
    Timer monsterTimer;
    Timer monstMove;
    Timer check;

	 public void init()
	    {

	        addMouseListener(this);
	        appletWidth = 600;//getWidth();
	        appletHeight = 400;//getHeight(); 
	        virtualMem = createImage(appletWidth,appletHeight);
	        gBuffer = virtualMem.getGraphics();
	        gBuffer = virtualMem.getGraphics();
	        gBuffer.setColor(Color.BLACK);
	        gBuffer.fillRect(0,0,appletWidth,appletHeight);
	        projectilemovetimer = new Timer(20, this);
	        fireTimer = new Timer(2000, this);
	        monsterTimer = new Timer(3000,this);
	        monstMove = new Timer (20, this);
	        check = new Timer (20,this);


	    }	

	public void paint (Graphics g){
		 gBuffer.setColor(Color.BLACK);
		    gBuffer.fillRect(0,0,appletWidth,appletHeight);
		    for(Tower a : chocolate){ a.drawTower(gBuffer,a.getX(),a.getY());}
		    for(Projectile p : project){ p.drawProjectile(gBuffer);}
		    for(Monster m : monsty){m.drawMonster(gBuffer);}
			g.drawImage(virtualMem,0,0,this);

	}

	  public void mouseEntered(MouseEvent e) {}
	    public void mouseExited(MouseEvent e) {}
	    public void mouseClicked(MouseEvent e) {}
	    public void mouseReleased(MouseEvent e) {}
	    public void mousePressed(MouseEvent e) 
	    {
	      int x = e.getX();
	      int y = e.getY();
	      if((y>25&&y<75)||(y>325&&y<375)){Tower blah = new Tower(gBuffer, x-10,y-10); chocolate.add(blah); }
	      projectilemovetimer.start();
	      fireTimer.start();
	      monsterTimer.start(); 
	      monstMove.start();
	      check.start();
	      repaint();
	    }

	    public void actionPerformed(ActionEvent e)
	    {
	        Object source = e.getSource();
	        if (source == projectilemovetimer) 

	            {

	               for(Projectile p : project){
	            	   p.move();

	               }
	               repaint();
	            }

	        if (source == fireTimer){
	        	 for(Tower a : chocolate){

	            	   Projectile p = new Projectile(gBuffer,a.getX(),a.getY(),a.getDir());
	            	   project.add(p);

	               }
	        }
	        if (source == monsterTimer){
	        	Monster m = new Monster(gBuffer);
	        	monsty.add(m);

	        }


	        if (source == monstMove){

	        	for(Monster m : monsty){

	        		if (m.getHealth()==0)
	        		{m.removeMonster(gBuffer);
	        		monsty.remove(m);
	        		}
	        		else{ m.move();}
		        	}
	        }

	        if (source == check){
	        	for (Projectile p : project){
	        		for(Monster m : monsty){
	        			if(p.intersects(m)){
	        				m.hit();
	        				p.removePro(gBuffer);
                                                project.remove(p);
	        			}
	        		}
	        	}
	        }

	        repaint();
	    }
	    public void update(Graphics g){
	        paint(g);
	    }

}


So, have a pseudo working prototype, ish. monsters run across the screen, towers are placed when you click in the right bands, projectiles fire at the right times and rates and all that. if you hit a monster with a projectile, it dies. Yay. cept sometimes it throws a concurrent modification error. :) because I have too many things looping over everything, it's only really a roll of the dice until it tries to remove the monster that's being looked at to move. will work on that. :) thanks fr. Chris for the help with the timers, I hadn't realized that they needed to be started. the pong game hid that well, seeing as I wasn't really looking for it specifically. also the get x and y were a bit important. always good to be able to get private variables. and the dueling applet thing was interesting, though I hadn't yet hit a problem with it... i'm sure I soon would have, but it's always good to remember the difference between a component and a subclass. a tower is not a world, but it is part of one. :) chapter nine for the win.

Kevin's musings

I've been having list of fun with removing things from a list as I iterate through it. I think i need to have the lists all check things at the same time, then add the changes to another array list. then loop through that, perform the changes, then empty the list. :) that is work for another day.

Fr Chris' Notes

Humm... there should only be ONE applet.. and it looks like Tower is a subclass of World and so who controls what will be a problem.... a couple of ways to fix this. You can make World non-applet and make a GameRunner class that has instances of World and Tower, or Keep World an Applet, and not make Tower a subclass...

The idea is to have a single playing field (the applet's Graphics g) which will have its timer and init.... so one Applet only, please! There are a number of examples in the starting code where a non-applet Object Class has its own drawing method (like public void draw(Graphics g) ) and the class that is the subclass of Applet will have in its paint() method

t.draw(g); where it passes along the place to draw to the Tower class (and t is the name of an instance of a Tower class)

There was no getX or getY methods and you never started the timer.. below I have a version which you can at least see the stuff, and perhaps you can just fix up the behaviour from this:

World.java

import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.applet.*;
import java.util.*;

import javax.swing.Timer;

/**
 * creates a world, onto which the tower and such will be placed
 * 
 * Black background, etc. 
 * 
 *
 */
public class World extends Applet
implements MouseListener, ActionListener
{


    Graphics gBuffer;
    ArrayList<Tower> chocolate = new ArrayList<Tower>();
	Image virtualMem;
    int appletWidth;        
    int appletHeight;
    Timer timer;
    ArrayList<Projectile> project = new ArrayList<Projectile>();
	 public void init()
	    {

	        addMouseListener(this);
	        appletWidth = 600;//getWidth();
	        appletHeight = 400;//getHeight(); 
	        virtualMem = createImage(appletWidth,appletHeight);
	        gBuffer = virtualMem.getGraphics();


	        timer = new Timer(10, this);

	    }	

	public void paint (Graphics g){
	    gBuffer.setColor(Color.BLACK);
	    gBuffer.fillRect(0,0,appletWidth,appletHeight);
	    for(Tower a : chocolate){ a.drawTower(gBuffer);}
	    for(Projectile p : project){ p.draw(gBuffer);}
		g.drawImage(virtualMem,0,0,this);


	}

	  public void mouseEntered(MouseEvent e) {}
	    public void mouseExited(MouseEvent e) {}
	    public void mouseClicked(MouseEvent e) {}
	    public void mouseReleased(MouseEvent e) {}
	    public void mousePressed(MouseEvent e) 
	    {
	      int x = e.getX();
	      int y = e.getY();
	      if((y>25&&y<75)||(y>325&&y<375)){Tower blah = new Tower( x-10,y-10); chocolate.add(blah); }
	      timer.start();
	      repaint();
	    }

	    public void actionPerformed(ActionEvent e)
	    {
	        Object source = e.getSource();
	        if (source == timer) 

	            {
	               for(Tower a : chocolate){
	            	   Projectile p = new Projectile(a.getX(),a.getY(),a.getDir());
	            	   project.add(p);

	               }
	               for(Projectile p : project){
	            	   p.move();

	               }
	            }


	        repaint();
	    }
	    public void update(Graphics g){
	        paint(g);
	    }

}

Tower.java

/** this class in essence:
 * 
 * draws the tower
 * 
 * gives it a fire speed
 * 
 * needs cost
 *
 */
import java.applet.*;
import java.awt.*;
import java.util.Timer;


public class Tower  {

	private int speed;
	private int cost; 
	private int dir;
	private int x;
	private int y; 
	public Tower(int x0, int y0){
		if(y>25&&y<75){dir=1;}
		else{if(y>325&&y<375){dir=2;}}
		speed = 10;
		cost = 5; 
		x=x0;
		y=y0;

	}

	public void drawTower(Graphics g){
	    g.setColor(Color.CYAN);
		g.drawRect(x,y, 20,20);
	}

	public int getDir()
	{
		return dir;
	}

	public int getSpeed()
	{
		return speed; 
	}

	public int getCost()
	{
		return cost;
	}
	public int getX()
	{
		return x;
	}
	public int getY()
	{
		return y;
	}
}

Projectile

import java.awt.*;

/**
 * this class will give the projectile: 
 * 
 * it's speed
 * it's direction
 * it's size
 * it's shape
 * it's damage
 *
 */
public class Projectile {

	private int speed;
	private int direction;
	private int damage; 
	private int x;
	private int y; 

	public Projectile(int xc, int yc, int dir){

		x=xc;
		y=yc;

		direction = dir;
		speed = 2;
		damage= 1; 
	}
	public void move(){
	if(direction == 1){y=y+1;}	
	else{y=y-1;}

	}
	public void draw(Graphics g){
	    g.setColor(Color.RED);
	    g.drawRect(x,y,5,5);

	   }


	public int getDamage(){return damage;}

	public int getDirection(){return direction;}

	public int getSpeed(){return speed;}
}