赞
踩
今天给大家分享一个简易的植物大战僵尸游戏,用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(); } }
接下来就可运行了:
有兴趣的可以试一试。
下载地址:
植物大战僵尸完整源码
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。