用Java实现一个简易的植物大战僵尸游戏

今天给大家分享一个简易的植物大战僵尸游戏,用Java编写,还是挺好玩的。

一、设计思路
1.植物大战僵尸运用Java基础实现,通过滚轮上选择植物,随机生成各种类型僵尸,以及植物。
2.玩家可以安放各种植物到草坪上,僵尸通过重绘实现走步效果,以及僵尸死亡时效果。
实际运行效果如下:
在这里插入图片描述
二、代码实现
1.首先要考虑的就是将游戏涉及到的各种对象搞清,由于Java面向对象特性,我们可以将各个对象的共同特征抽象出来,比如僵尸,有多种类型的僵尸,就可抽象出一个僵尸对象的超类,植物也是如此。

public abstract class Zombie {
	
	protected int width;
	protected int height;
	protected int x;
	protected int y;
	protected int live;
	protected int xSpeed;
	protected int deadTm;
	private static BufferedImage[] imgs;
	static {
		imgs=new BufferedImage[25];
		for(int i=0;i<imgs.length;i++) {
			imgs[i]= i<=13 ? loadImage("/ZombieDie/Frame"+i+".png") : loadImage("/ZombieHead/Frame"+(i-14)+".png");
		}
	}
	int index=0;
	int index1=0;
	public BufferedImage getDeadImg() {
		if(index==13) {
			return imgs[13];
		}
		return imgs[index++%14];
	}
	public BufferedImage getDeadHeadImg() {
		if(index1==10) {
			return imgs[24];
		}
		return imgs[index1++%11+14];
	}
	public Zombie(int width,int height) {
		this.width=width;
		this.height=height;
		Random rand=new Random();
		this.x=GamePlay.WIDTH-100;
		//this.y=rand.nextInt(GamePlay.HEIGHT-this.height);
		this.y=rand.nextInt(5)*100+46;
		this.deadTm=80;
	}
	public int getDeadTm() {
		return deadTm;
	}
	public void loseDeadTm() {
		deadTm--;
	}
	public int getWidth() {
		return width;
	}

	public int getHeight() {
		return height;
	}

	public int getX() {
		return x;
	}
	public int getY() {
		return y;
	}
	public int getSpeed() {
		return xSpeed;
	}
	public int getLive() {
		return live;
	}
	public void loseLive() {
		live--;
	}
	public void goSlowDown() {
		xSpeed=1;
	}
	public void goOut() {
		xSpeed=2;
	}
	// 移动方式
	public abstract void step();
	
	public boolean zombieHit(Plant p) {
		int x1=this.x-p.getWidth()+50;
		int x2=this.x+this.width-15;
		int y1=this.y-p.getHeight()+30;
		int y2=this.y+this.height-20;
		int x=p.getX();
		int y=p.getY();
		return x>=x1 && x<=x2 && y>=y1 && y<=y2;
	}
	public boolean outOfBounds() {
		return this.x<=0;
	}
	public static final int LIFE=0;
	public static final int ATTACK=1;
	public static final int DEAD=2;
	
	protected int state=LIFE;
	
	public boolean isLife() {
		return state==LIFE;
	}
	public boolean isAttack() {
		return state==ATTACK;
	}
	public boolean isDead() {
		return state==DEAD;
	}
	public void goLife() {
		state=LIFE;
	}
	public void goAttack() {
		state=ATTACK;
	}
	public void goDead() {
		state=DEAD;
	}
	public void goStop() {
		xSpeed=0;
	}
	public abstract void goRun();
	
	public static BufferedImage loadImage(String fileName) {
		try {
			BufferedImage img=ImageIO.read(Zombie.class.getResource(fileName));
			return img;
		}catch(IOException e) {
			e.printStackTrace();
			throw new RuntimeException();
		}
	}
	public abstract BufferedImage getImage();
	
	public void paintObject(Graphics g) {
		g.drawImage(getImage(), x, y, width, height, null);
	}
	public void paintHead(Graphics g) {
		g.drawImage(getDeadHeadImg(), x-10, y-30, null);
		
	}
}

2.植物超类代码实现:

public abstract class Plant {
	
	protected int x;
	protected int y;
	protected int width;
	protected int height;
	protected int ySpeed;
	protected int live;
	
	protected int fixLive;
	
	public Plant(int width,int height) {
		this.width=width;
		this.height=height;
		this.x=0;
		this.y=GamePlay.HEIGHT;
		ySpeed=1;
	}

	public int getX() {
		return x;
	}

	public void setX(int x) {
		this.x = x;
	}

	public int getY() {
		return y;
	}

	public void setY(int y) {
		this.y = y;
	}

	public int getWidth() {
		return width;
	}

	public int getHeight() {
		return height;
	}

	public int getLive() {
		return live;
	}
	public void loseLive() {
		this.live--;
	}
	public void moveTo(int x,int y) {
		this.x=x-this.width/2;
		this.y=y-this.height/2;
	}
	public void step() {
		y-=ySpeed;
		if(y<=0) {
			state=STOP;
		}
	}
	
	public static BufferedImage loadImage(String fileName) {
		try {
			BufferedImage img=ImageIO.read(Plant.class.getResource(fileName));
			return img;
		}catch (IOException e) {
			e.printStackTrace();
			throw new RuntimeException();
		}
	}
	public abstract BufferedImage getImage();
	
	public void paintObject(Graphics g) {
		g.drawImage(getImage(), x, y, width,height,null);
	}
	public static final int WAIT=0;
	public static final int STOP=1;
	public static final int MOVE=2;
	
	public static final int LIFE=3;
	
	public static final int DEAD=4;
	
	protected int state=WAIT;
	
	public void setState(int state) {
		this.state=state;
	}
	public boolean isWait() {
		return state==WAIT;
	}
	public boolean isStop() {
		return state==STOP;
	}
	public boolean isMove() {
		return state==MOVE;
	}
	public boolean isLife() {
		return state==LIFE;
	}
	public boolean isDead() {
		return state==DEAD;
	}
	public void goWait() {
		state=WAIT;
	}
	public void goStop() {
		state=STOP;
	}
	public void goMove() {
		state=MOVE;
	}
	public void goLife() {
		state=LIFE;
	}
	public void goDead() {
		state=DEAD;
	}
}

3.通过子类继承父类实现各个对象的创建,创建完各个对象后,接下来就可让他们动起来,以僵尸为例,僵尸入场并走步,如下:

//随机生成各类僵尸
public Zombie nextOneZombie() { 
		Random rand=new Random();
		int type=rand.nextInt(20);
		if(type<5) {
			return new Zombie0();
		}else if(type<11) {
			return new Zombie1();
		}else if(type<17) {
			return new Zombie2();
		}else {
			return new Zombie3();
		}
	}
	int zombieEnterTime=0;
	public void zombieEnterAction() {
		zombieEnterTime++;
		if(zombieEnterTime%300==0) {
			zombies.add(nextOneZombie());
		}
	}

4.在僵尸移动过程中,就涉及到僵尸与植物的碰撞问题,这其中就要理解两者间如何才算碰撞,实现如下:

	//判断是否碰撞
	public boolean zombieHit(Plant p) {
		int x1=this.x-p.getWidth()+50;
		int x2=this.x+this.width-15;
		int y1=this.y-p.getHeight()+30;
		int y2=this.y+this.height-20;
		int x=p.getX();
		int y=p.getY();
		return x>=x1 && x<=x2 && y>=y1 && y<=y2;
	}

5.绘制界面,通过重绘实现,具体代码如下:

public class GamePlay extends JPanel{

	private static final long serialVersionUID = 1L;
	
	public static final int WIDTH=1400;
	public static final int HEIGHT=600;
	public static final int START=0;
	public static final int RUNNING=1;
	public static final int GAME_OVER=2;
	
	public static int state=RUNNING;
	
	Background start=new Background(800, 533, 300, 50);
	Background running=new Background(WIDTH, HEIGHT, 0, 0);
	Background gameOver=new Background(WIDTH, HEIGHT, 0, 0);
	
	Vector<Zombie> zombies=new Vector<Zombie>();
	
	Vector<Plant> plants=new Vector<>();
	Vector<Plant> plantsLife=new Vector<>();
	Vector<Bullet> bullets=new Vector<>();
	List<Glass> glasses=new ArrayList<>();
	
	List<Shovel> shovels=new ArrayList<>();
	
	public void shovelEnterAction() {
		if(shovels.size()==0) {
			shovels.add(new Shovel());
		}
	}
	public void checkShovelAction() {
		if(plantsLife.size()==0) {
			Iterator<Shovel> its=shovels.iterator();
			while(its.hasNext()) {
				Shovel s=its.next();
				if(s.isMove() && shovelCheck) {
					its.remove();
				}
			}
		}
	}
	int glassX=260;
	int glassY=80;
	public void glassEnterAction() {
		for(int i=0;i<9;i++) {
			int x=glassX+i*Glass.width;
			for(int j=0;j<5;j++) {
				int y=glassY+j*Glass.height;
				glasses.add(new Glass(x, y));
			}
		}
	}
	public void glassCheckAction() {
		for(Glass g : glasses) {
			g.goEmpty();
			int x1=g.getX();
			int y1=g.getY();
			for(Plant p : plantsLife) {
				if(p.isLife() || (p instanceof Blover && ((Blover)p).isClick())) {
					int x=p.getX();
					int y=p.getY();
					if(x1==x && y1==y) {
						g.goHold();
						break;
					}
				}
			}
		}
	}
	public Zombie nextOneZombie() {
		Random rand=new Random();
		int type=rand.nextInt(20);
		if(type<5) {
			return new Zombie0();
		}else if(type<11) {
			return new Zombie1();
		}else if(type<17) {
			return new Zombie2();
		}else {
			return new Zombie3();
		}
	}
	int zombieEnterTime=0;
	public void zombieEnterAction() {
		zombieEnterTime++;
		if(zombieEnterTime%300==0) {
			zombies.add(nextOneZombie());
		}
	}
	int zombieStepTime=0;
	public void zombieStepAction() {
		if(zombieStepTime++%6==0) {
			for(Zombie z : zombies) {
				if(z.isLife()) {
					z.step();
				}
			}
		}
	}
	int spikerockHitTime=0;
	public void zombieMoveToSpikerockAction() {
		if(spikerockHitTime++%20==0) {
			for(Plant p : plantsLife) {
				if(p instanceof Spikerock) {
					if(p.isLife()) {
						int x1=p.getX();
						int y1=p.getY();
						int x2=p.getX()+p.getWidth();
						int y2=p.getY()+p.getHeight();
						for(Zombie z : zombies) {
							if(z.isLife() || z.isAttack()) {
								int x=z.getX();
								int y=z.getY();
								if(x>x1 && y>y1 && x<x2 && y<y2) {
									z.loseLive();
								}
							}
						}
					}
				}
			}
		}
	}
	int zombieHitTime=0;
	public void zombieHitAction() {
		if(zombieHitTime++%100==0) {
			for(Zombie z : zombies) {
				if(!z.isDead()) {
					z.goLife();
				}
				for(Plant p : plantsLife) {
					if(z.isLife() && (p.isLife() || (p instanceof Blover && ((Blover)p).isClick())) && z.zombieHit(p) && !(p instanceof Spikerock)) {
						z.goAttack();
						p.loseLive();
					}
				}
			}
		}
	}
	int timeStop=1; //停止2秒
	public void checkZombieAction() {
		Iterator<Zombie> it=zombies.iterator();
		while(it.hasNext()) {
			Zombie z=it.next();
			if(z.getLive()<=0) {
				if(z instanceof Award && !z.isDead()) {
					Award a=(Award)z;
					int type=a.getAwardType();
					switch (type) {
					case Award.CLEAR:
						for(Zombie zo : zombies) {
							zo.goDead();
						}
						break;
					case Award.STOP:
						for(Zombie zo : zombies) {
							zo.goStop();
							timeStop=1;
						}
						break;
					}
				}
				z.goDead();
				//it.remove();
				z.loseDeadTm();
				
			}else {
				if(z.isDead()) {
					z.loseDeadTm();
				}
			}
			if(z.outOfBounds()) {
				gameLife--;
				it.remove();
			}
		}
	}
	public void checkDeadZombieRemoveAction() {
		Iterator<Zombie> it=zombies.iterator();
		while(it.hasNext()) {
			Zombie z=it.next();
			if(z.isDead() && z.getDeadTm()<=0) {
				it.remove();
			}
		}
	}
	public void zombieGoLife() {
		if(timeStop++%250==0) {
			for(Zombie zo : zombies) {
				zo.goRun();						
			}
		}
	}
	int gameLife=1;
	public void checkGameAction() {
		if(gameLife<=0) {
			state=GAME_OVER;
			plants.clear();
			zombies.clear();
			bullets.clear();
			plantsLife.clear();
			shovels.clear();
		}
	}
	public Plant nextOnePlant() {
		Random rand=new Random();
		int type=rand.nextInt(35);
		if(type<5) {
			return new Repeater();
		}else if(type<10) {
			return new ThreePeater();
		}else if(type<15) {
			return new SnowPea();
		}else if(type<20) {
			return new Blover();
		}else if(type<25) {
			return new Spikerock();
		}else if(type<30){
			return new WallNut();
		}else {
			return new Torchwood();
		}
	}
	int plantEnterTm=0;
	public void plantEnterAction() {
		plantEnterTm++;
		if(plantEnterTm%150==0) {
			plants.add(nextOnePlant());
		}
	}
	public void plantStepAction() {
		for(Plant p : plants) {
			if(p.isWait()) {
				p.step();
			}
		}
	}
	public void plantBangAction() {
		for(int i=1;i<plants.size();i++) {
			if(plants.get(0).getY()>0 && plants.get(0).isStop()) {
				plants.get(0).goWait();
			}
			if((plants.get(i).isStop() || plants.get(i).isWait()) && (plants.get(i-1).isStop() || plants.get(i-1).isWait())
				&& plants.get(i).getY()<=plants.get(i-1).getY()+plants.get(i-1).getHeight()) {
				plants.get(i).goStop();
			}
			if(plants.get(i).isStop()  && plants.get(i).getY()>plants.get(i-1).getY()+plants.get(i-1).getHeight()) {
				plants.get(i).goWait();
			}
		}
	}
	int bloverTm=1;
	public void checkBloverAction() {
		if(bloverTm++%200==0) {
			for(Plant p : plantsLife) {
				if(p instanceof Blover && p.isLife()) {
					((Blover)p).goClick();
				}
			}
		}
	}
	int bulletTm=0;
	public void bulletShootAction() {
		if(bulletTm++%80==0) {
			for(Plant p : plantsLife) {
				if(p instanceof Shoot && p.isLife()) {
					Shoot s=(Shoot) p;
					bullets.addAll(Arrays.asList(s.shoot()));
				}
			}
		}
	}
	public void bulletStepAction() {
		for(Bullet b : bullets) {
			b.step();
		}
	}
	public void bulletZombieHitAction() {
		for(Zombie z : zombies) {
			if(z.isAttack() || z.isLife()) {
				for(Bullet b : bullets) {
					if((b.isLife() || b.isFire()) && b.hit(z) && z.getX()<GamePlay.WIDTH) {
						if(b instanceof SnowBullet && b.isLife()) {
							z.goSlowDown();
						}
						if(b.isLife()) {
							z.loseLive();
						}
						z.loseLive();
						b.goDead();
					}
				}
			}
		}
	}
	public void bulletFireHitAction() {
		for(Plant p : plantsLife) {
			if(p instanceof Torchwood && p.isLife()) {
				Torchwood t=(Torchwood)p;
				for(Bullet b : bullets) {
					if(b.isLife() && b.hitFire(t)) {
						b.goFire();
					}
				}
			}
		}
	}
	boolean plantCheck=false;
	boolean shovelCheck=false;
	
	public void action() {
		glassEnterAction();
		
		MouseAdapter l=new MouseAdapter() {
			public void mouseClicked(MouseEvent e) {
				int mX=e.getX();
				int mY=e.getY();
				if(state==RUNNING) {
					f:for(Plant p : plantsLife) {
						if(p.isMove() && plantCheck) {
							for(Glass g : glasses) {
								int x1=g.getX();
								int x2=g.getX()+g.getWidth();
								int y1=g.getY();
								int y2=g.getY()+g.getHeight();
								if(mX>x1 && mX<x2 && mY>y1 && mY<y2 && g.isEmpty()) {
									p.setX(x1);
									p.setY(y1);
									g.goHold();
									p.goLife();
									plantCheck=false;
									if(p instanceof Blover) {
										bloverTm=0;
									}
									break f;
								}
							}
						}
					}
					Iterator<Shovel> it=shovels.iterator();
					Iterator<Plant> itp=plantsLife.iterator();
					while(it.hasNext()) {
						Shovel s=it.next();
						if(s.isMove() && shovelCheck) {
							while(itp.hasNext()) {
								Plant p=itp.next();
								int x1=p.getX();
								int x2=p.getX()+p.getWidth();
								int y1=p.getY();
								int y2=p.getY()+p.getHeight();
								if((p.isLife() || (p instanceof Blover && ((Blover)p).isClick())) && mX>x1 && mX<x2 && mY>y1 && mY<y2) {
									itp.remove();
									it.remove();
									shovelCheck=false;
									break;
								}
							}
						}
					}
					for(Plant p : plants) {
						if((p.isStop() || p.isWait()) && !plantCheck && !shovelCheck) {
							int x1=p.getX();
							int x2=p.getX()+p.getWidth();
							int y1=p.getY();
							int y2=p.getY()+p.getHeight();
							if(mX>x1 && mX<x2 && mY>y1 && mY<y2) {
								p.goMove();
								plantCheck=true;
								break;
							}
						}
					}
					Iterator<Shovel> its=shovels.iterator();
					if(plantsLife.size()>0) {
						while(its.hasNext()) {
							Shovel s = its.next();
							int x1 = s.getX();
							int x2 = s.getX()+s.getWidth();
							int y1 = s.getY();
							int y2 = s.getY()+s.getHeight();
							if(s.isWait() && mX>x1 && mX<x2 && mY>y1 && mY<y2 && !plantCheck) {
								s.goMove();
								shovelCheck=true;
							}
						}
					}
					for(Plant p : plantsLife) {
						if(p instanceof Blover) {
							int x1=p.getX();
							int x2=p.getX()+p.getWidth();
							int y1=p.getY();
							int y2=p.getY()+p.getHeight();
							if(((Blover)p).isClick() && mX>x1 && mX<x2 && mY>y1 && mY<y2 && !plantCheck && !shovelCheck) {
								p.goDead();
								for(Zombie z : zombies) {
									if(z.isAttack()) {
										z.goLife();
									}
									z:for(int i=0;i<10;i++) {
										z.goOut();
										if(z.getX()>=GamePlay.WIDTH-z.getWidth()) {
											z.goRun();
											break z;
										}
									}
								}
							}
						}
					}
				}
				if(state==START) {
					int x1 = 720;
					int x2 = 990;
					int y1 = 210;
					int y2 = 320;
					if(mX>=x1&&mX<=x2&&mY>=y1&&mY<=y2) {
						state = RUNNING;
					}
				}
				if(state==GAME_OVER) {
					int x1 = 480;
					int x2 = 950;
					int y1 = 100;
					int y2 = 540;
					if(mX>=x1&&mX<=x2&&mY>=y1&&mY<=y2) {
						state = START;
						gameLife = 1;
					}
				}
			}
			public void mouseMoved(MouseEvent e) {
				if(state==RUNNING) {
					for(Plant p : plantsLife) {
						if(p.isMove()) {
							int x=e.getX();
							int y=e.getY();
							p.moveTo(x, y);
							break;
						}
					}
					for(Shovel s : shovels) {
						if(s.isMove()) {
							int x=e.getX();
							int y=e.getY();
							s.moveTo(x, y);
							break;
						}
					}
				}
			}
		};
		this.addMouseListener(l);
		this.addMouseMotionListener(l);
		Timer timer=new Timer();
		int interval=10;
		timer.schedule(new TimerTask() {
			
			@Override
			public void run() {
				if(state==RUNNING) {
					shovelEnterAction();
					checkShovelAction();
					zombieEnterAction();
					zombieStepAction();
					zombieMoveToSpikerockAction();
					zombieHitAction();
					plantEnterAction();
					plantStepAction();
					plantBangAction();
					zombieGoLife();
					bulletShootAction();
					bulletStepAction();
					bulletZombieHitAction();
					checkBloverAction();
					checkPlantAction();
					checkPlantLifeAction();
					checkZombieAction();
					bulletCheckAction();
					glassCheckAction();
					checkGameAction();		
					checkDeadZombieRemoveAction();
					bulletFireHitAction();
				}				
			}
		}, interval, interval);
	}
	public void refreshAction() {
		Timer timer=new Timer();
		int interval=80;
		timer.schedule(new TimerTask() {
			
			@Override
			public void run() {
				repaint();		
			}
		}, 0,interval);
	}
	public void paint(Graphics g) {
		if(state==START) {
			start.paintObject(g);
		}else if(state==RUNNING) {
			running.paintObject(g);
		}else if(state==GAME_OVER) {
			gameOver.paintObject(g);
		}		
		synchronized (plants) {
			for(Plant p:plants) {
				p.paintObject(g);
			}
		}
		synchronized (plantsLife) {
			for(Plant p:plantsLife) {	
				p.paintObject(g);
			}
		}
		synchronized (zombies) {
			for(Zombie z:zombies) {
				z.paintObject(g);
				if(z.isDead()) {
					z.paintHead(g);
				}
			}
		}
		synchronized (bullets) {
			for(Bullet b:bullets) {
				if(b.isFire()) {
					b.paintObjectFire(g);
				}else if(b.isDead()){
					b.paintObjectDead(g);
				}else {
					b.paintObject(g);
				}
				
			}	
		}
		synchronized (shovels) {
			for(Shovel s:shovels) {
				s.paintObject(g);
			}
		}	
	}
	public static void main(String[] args) {
		JFrame frame=new JFrame();
		GamePlay play=new GamePlay();
		frame.add(play);
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.setSize(WIDTH, HEIGHT+40);
		frame.setResizable(false);
		frame.setVisible(true);
		frame.setLocationRelativeTo(null); 
		frame.setTitle("植物大战僵尸");
		play.action();
		play.refreshAction();
		Runnable r = new ZombieAubio("cuowei.mp3");
		Thread t = new Thread(r);
		t.start();
	}
}

接下来就可运行了:
在这里插入图片描述

有兴趣的可以试一试。

下载地址:
植物大战僵尸完整源码

  • 18
    点赞
  • 193
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

夜空下的星

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值