今天给大家分享一个简易的植物大战僵尸游戏,用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=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 zombies=new Vector();
Vector plants=new Vector<>();
Vector plantsLife=new Vector<>();
Vector bullets=new Vector<>();
List glasses=new ArrayList<>();
List shovels=new ArrayList<>();
public void shovelEnterAction() {
if(shovels.size()==0) {
shovels.add(new Shovel());
}
}
public void checkShovelAction() {
if(plantsLife.size()==0) {
Iterator 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 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 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;i0 && 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()x1 && mXy1 && mY it=shovels.iterator();
Iterator 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 && mXy1 && mYx1 && mXy1 && mY 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 && mXy1 && mYx1 && mXy1 && mY=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();
}
}
接下来就可运行了:
有兴趣的可以试一试。
下载地址:
植物大战僵尸完整源码