1200字范文,内容丰富有趣,写作的好帮手!
1200字范文 > JAVA实现简单“伪植物大战僵尸“游戏

JAVA实现简单“伪植物大战僵尸“游戏

时间:2020-07-06 21:37:31

相关推荐

JAVA实现简单“伪植物大战僵尸“游戏

用两天时间试着用JAVA模拟植物大战僵尸写的游戏

程序只用了2天时间完成,BUG较多,也没有做过多优化,功能也很简单,最后也没有想去改进

源代码免费提供,CSDN上的需要积分下载,可以去GIT上下载**

GIT地址:/akh5/JAVA/tree/master/Plants

只有当左下角图标亮起时才能安放豌豆射手

主要代码

父类MovingObject,包含所有判断和图片读取相关代码

package Plants;import java.awt.Graphics;import java.awt.image.BufferedImage;import java.util.Random;public abstract class MovingObject {public static final int LIFE = 0;public static final int DEAD = 1;public static final int REMOVE = 2;public static final int EAT = 3 ;public static final int HIT = 4;protected int state = LIFE ;//当前状态(默认为活着)protected int width; //宽protected int height; //高protected int x; //横坐标protected int y; //纵坐标/*僵尸,植物的构造方法*/public MovingObject(int width,int height) {this.width = width;this.height = height;}public MovingObject(int width , int height , int x , int y){this.width = width;this.height = height;this.x = x;this.y = y;}public abstract void step();//获取对象的图片public abstract BufferedImage getImage();//判断对象是否是活着public boolean isLife() {return state == LIFE ; //当前状态为LIFE 表示对象活着}//判断对象是否是死着public boolean isDead() {return state == DEAD ; //当前状态为LIFE 表示对象活着}//判断对象是否删除public boolean isRemove() {return state == REMOVE ; //当前状态为LIFE 表示对象活着}public boolean isEat(){return state == EAT;}public boolean isHit(){return state == HIT ;}public boolean outofBounds() {return this.y>=World.HEIGHT;}public void paintObject(Graphics g) {g.drawImage(this.getImage(), this.x,this.y,null);}// /*判断敌人是否越界*/// public boolean outofBounds() {// //return this.y>=World.HEIGHT;// }/*碰撞检测 this是敌人 other是子弹*/public boolean hit(MovingObject other) {int x1 = this.x-other.width; //int x2 = this.x+this.width; //int y1 = this.y-other.height;int y2 = this.y+this.height;int x = other.x;int y = other.y;//x在x1与x2之间,且y在y1与y2之间,即为撞上了return x>=x1&&x<=x2&&y>=y1&&y<=y2;}public void goDead() {state = DEAD; //将当前状态修改为DEAD}public void goEat(){state = EAT;}public void goHit(){state = HIT;}}

图片Image类,存放图片路径

这里用切换图片的方法让图片动起来,植物和僵尸有十几张按帧截出来图,循环切换图片达到动图效果

package Plants;import java.awt.image.BufferedImage;import javax.imageio.ImageIO;import java.io.IOException;public class Images {public static BufferedImage background; //背景图public static BufferedImage bullets; //子弹图public static BufferedImage[] sun; //太阳图public static BufferedImage[] plants; //植物切换public static BufferedImage[] zombies; //僵尸public static BufferedImage select0; //背景图public static BufferedImage select1;public static BufferedImage[] eat;public static BufferedImage[] die;public static BufferedImage start;public static BufferedImage gameover;public static BufferedImage sunback;static{background = readImage("background.png");bullets = readImage("bullet.png");sun = new BufferedImage[10];for(int i = 0; i< 10;i++){sun[i] = readImage("Sun"+i+".png");}select0 = readImage("select0.png");select1 = readImage("select1.png");sunback = readImage("SunBack.png");eat = new BufferedImage[4];for(int i = 0;i<4;i++){eat[i] = readImage("eat"+i+".png");}start = readImage("start.png");gameover = readImage("gameover.png");die = new BufferedImage[3];for (int i = 0; i<3;i++){die[i] = readImage("die"+i+".png");}plants = new BufferedImage[13];for(int i = 0;i<13;i++){plants[i] = readImage("Peashooter["+(i+1)+"].png");}zombies = new BufferedImage[18];for(int i = 0 ;i<18;i++){zombies[i] = readImage("Zombie["+(i+1)+"].png");}}public static BufferedImage readImage(String fileName){//同包下读取图片try {BufferedImage img = ImageIO.read(MovingObject.class.getResource(fileName));return img;}catch(Exception e){e.printStackTrace();throw new RuntimeException();}}}

子类Plant,豌豆射手图片切换,以及图片宽高,坐标

package Plants;import java.awt.image.BufferedImage;public class Plants extends MovingObject {private int life;private int getx;private int gety;public int moveable = 1;private int timer = 0;public Plants(int x,int y){super(90,90,x,y);life = 3;}@Overridepublic void step() {}int index = 5;@Overridepublic BufferedImage getImage() {// 每十毫秒走一次if(isLife()) {BufferedImage img = Images.plants[index++%13];//System.out.println(index);return img;}if(isDead()) {return null;}return null;/* index = 0;* 10M 返回Images.heros[0] index = 1* 20M 返回Images.heros[1] index = 2* 30M 返回Images.heros[0] index = 3* 40M 返回Images.heros[1] index = 4* */}public void subtaractLife() {if(timer++%2 == 0)life--;if(life<0){goDead();state =REMOVE;}}}

子类Zombies,效果同Plants

package Plants;import java.awt.image.BufferedImage;import java.util.Random;public class Zombies extends MovingObject {private int speed;private int timer = 0;private int life = 3;public Zombies(int getx,int gety) {super(100, 120,getx,gety);speed = 2;}@Overridepublic void step() {if(!isEat()&&timer<50)x-=speed;if (timer>50)x-=speed;}int index = 0;@Overridepublic BufferedImage getImage() {if(isLife()) {return Images.zombies[index++%18];}if(isEat()&&timer++<50){return Images.eat[index++%4];}if(timer>=50){state = LIFE;}if(isLife()) {return Images.zombies[index++%4];}if(isDead()){int i = 0;state = REMOVE;return Images.die[i++];// state = REMOVE;// return img;}return null; //删除状态,直接返回NULL;}}

子类back,背景图

package Plants;import java.awt.Graphics;import java.awt.image.BufferedImage;public class Back extends MovingObject {public Back() {super(World.WIDTH, World.HEIGHT, 0, 0);}@Overridepublic void step() {}@Overridepublic BufferedImage getImage() {return Images.background;}public void paintObject(Graphics g) {g.drawImage(this.getImage(), this.x, this.y, null);}}

子类Sun

package Plants;import java.awt.image.BufferedImage;import java.util.Random;public class Sun extends MovingObject {public Sun(int x,int y) {super(100,100,x,y);Random rand = new Random();x = rand.nextInt(World.WIDTH-this.width);}@Overridepublic void step() {y+=3;}int index = 0;@Overridepublic BufferedImage getImage() {return Images.sun[index++%9];}}

主类World,主要代码,全部功能的实现类,僵尸入场,鼠标监听,这里只设定了鼠标点击操作,判定当前太阳值,能否安防豌豆射手。用数组方式存放所有对象,动态扩容

package Plants;import java.awt.Font;import java.awt.Graphics;import javax.swing.JFrame; //相框import javax.swing.JPanel; //相坂 ,面板import java.util.Arrays;import java.util.Random;import java.util.Timer;import java.util.TimerTask;import java.awt.event.MouseAdapter; // 鼠标监听器import java.awt.event.MouseEvent; //监听事件,鼠标的坐标封装在内public class World extends JPanel{public static final int WIDTH = 1434;public static final int HEIGHT = 780;private Back back = new Back();private Plants[] plants = {};private Bullets[] bullets = {};private MovingObject[] Zombiesun = {};private int Sun = 50;private int score = 0;public static final int START = 0;public static final int RUNNING = 1;// public static final int PAUSE = 2;public static final int GAME_OVER = 3;private int state = START; //当前状态默认为启动状态public MovingObject nextOne() {Random rand = new Random();int type = rand.nextInt(33);if(type <4) {return new Zombies(1434,70);}else if(type <8 ) {return new Zombies(1434,220);}else if(type < 24) {Sun+=50;Random sun = new Random();int locatex = rand.nextInt(400)+1000;return new Sun(locatex,0);}else if(type < 28) {return new Zombies(1434,470);}else if(type < 32) {return new Zombies(1434,590);}else {return new Zombies(1434,340);}}public Plants nextPlant(int x,int y) {return new Plants(x,y);}int enterIndex = 0; //敌人入场计数器public void enterAction() {enterIndex++;if(enterIndex%40 == 0) {//每400(10M*40)毫秒走一次MovingObject obj = nextOne(); //获取敌人对象Zombiesun = Arrays.copyOf(Zombiesun, Zombiesun.length+1);//扩容长度Zombiesun[Zombiesun.length-1] = obj;}}int plantIndex = 0;public void plantAction(int x,int y){Plants obj = nextPlant(x,y); //获取敌人对象plants = Arrays.copyOf(plants, plants.length+1);//扩容长度plants[plants.length-1] = obj;// }}public void stepAction() {for(int i = 0; i < Zombiesun.length;i++) {Zombiesun[i].step();}for(int i = 0;i < bullets.length;i++) {bullets[i].step();}}public void bulletHitAction() {for(int i = 0 ; i<bullets.length;i++) {Bullets b = bullets[i];for(int j = 0; j < Zombiesun.length;j++) {MovingObject f = Zombiesun[j];if(b.isLife()&&f.isLife()&&f.hit(b)) {b.goDead();f.goDead();score+=10;}}}}public void PlantsMeetAction() {for(int i = 0;i<Zombiesun.length;i++) {// 遍历所有敌人MovingObject f = Zombiesun[i]; //获取每一个敌人for(int j = 0;j<plantIndex;j++){if(plants[j].isLife()&&f.isLife()&&f.hit(plants[j])) {//撞上了f.goEat();plants[j].subtaractLife();}}}}public void outOfBoundsAction() {int index = 0;MovingObject[] zombieLives = new MovingObject[Zombiesun.length];for(int i = 0 ;i<Zombiesun.length;i++) {MovingObject f = Zombiesun[i];//实际向保留的是,不越界的,并且状态是活着的//死了的是爆破的效果,不要的是REMOVE状态if(!f.outofBounds()&&!f.isRemove()) {//不越界,判断f.outofbounds()取反的值zombieLives[index] = f;index++;}}//把不越界的敌人装到enemi中,此时的长度是indexZombiesun = Arrays.copyOf(zombieLives, index);index = 0; //下标不越界的敌人的计数器//统计不越界的敌人,Bullets[] bulletLives = new Bullets[bullets.length];for(int i = 0 ;i<bullets.length;i++) {Bullets b = bullets[i];if(!b.outofBounds()&&!b.isRemove()) {//不越界,判断f.outofbounds()取反的值bulletLives[index] = b;index++;}}//把不越界的敌人装到enemi中,此时的长度是indexbullets = Arrays.copyOf(bulletLives, index);}int SX =-50;int SY = -50;public Bullets[] shoot(){Bullets[] bs = new Bullets[1];bs[0] = new Bullets(SX,SY);return bs;}int shootIndex = 0; //子弹入场计数器/*子弹入场*/public void shootAction() {shootIndex++;if(shootIndex%40==0) {Bullets[] bs = shoot();System.out.println(bs.length);//扩容(bs有几个元素,就扩大多少容量)bullets = Arrays.copyOf(bullets, bullets.length+bs.length);/** bs是原数组* 0是从原数组bs第一个元素开始* bullets是目标数组* bullets.length-bs.length从下标几开始复制* bs.length代表是复制几个元素* */System.arraycopy(bs, 0, bullets, bullets.length-bs.length, bs.length);}}public void checkGameOverAction() {//每10毫秒走一次for (int i = 0; i<Zombiesun.length;i++) {if (Zombiesun[i].x < 200) {try {UserDao.save("李四", score);} catch (Exception e) {// TODO 自动生成的 catch 块e.printStackTrace();}state = GAME_OVER;}}}public void action() {MouseAdapter l = new MouseAdapter() {// public void mouseMoved(MouseEvent e) {//int x = e.getX();//int y = e.getY();//plants[p].moveto(x, y);// } //英雄机随着鼠标移动了;@Overridepublic void mouseClicked(MouseEvent e) {super.mouseClicked(e);if (state == START)state = RUNNING;if (state == RUNNING) {int sx;int sy;if (Sun >= 100) {sx = e.getX() - 45;sy = e.getY() - 45;plantAction(sx, sy);SX =sx+65;SY = sy+6;plantIndex++;if(Sun>10) {shoot();}Sun -= 100;}//Sun+=50;}}};this.addMouseListener(l); //处理鼠标的操作事件this.addMouseMotionListener(l); //处理鼠标滑动事件Timer timer = new Timer();int intervel = 50;timer.schedule(new TimerTask() {public void run() {if(state == RUNNING) {enterAction();shootAction();PlantsMeetAction();stepAction();bulletHitAction();outOfBoundsAction();checkGameOverAction();repaint(); //所有事件都在repain之前完成//System.out.println(bullets.length);}}}, intervel, intervel);}/** 重写paint()画 g:画笔 在里面调用刚刚写的 paintObject()*/public void paint(Graphics g){back.paintObject(g); //画天空for(int i = 0;i<plants.length;i++){plants[i].paintObject(g); //画敌人}for(int i=0;i<Zombiesun.length;i++){//遍历所有敌人Zombiesun[i].paintObject(g); //画敌人}for(int i=0;i<bullets.length;i++){//遍历所有子弹bullets[i].paintObject(g); //画子弹}if(Sun<100){g.drawImage(Images.select0,10,600,null);}else{g.drawImage(Images.select1,10,600,null);}if(state == START)g.drawImage(Images.start,0,0,null);if(state == GAME_OVER) {g.drawImage(Images.gameover, 500, 200, null);g.setFont(new Font("黑体",Font.BOLD,35));g.drawString("排行榜", 350, 350);String[] result;try {result = UserDao.getScoreAndUsername();int y = 360;for(int i = 0;i<10;i++) {//只显示十个数据在窗口上if(result[i]!=null) {g.setFont(new Font("",Font.PLAIN,20));g.drawString(result[i], 500, y);y+=30;//依次往下挪30给像素,排开}}} catch (Exception e) {// TODO 自动生成的 catch 块e.printStackTrace();}}g.drawString("SCORE:"+score,10,25);}public static void main(String[] args) {JFrame frame = new JFrame();World world = new World();frame.add(world);frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);frame.setSize(WIDTH,HEIGHT);frame.setLocationRelativeTo(null);frame.setVisible(true);Music m = new Music();m.start();world.action();}}

音乐Music类,单线程播放背景音乐。

package Plants;import java.io.BufferedInputStream;import java.io.FileInputStream;import java.io.FileNotFoundException;import javazoom.jl.decoder.JavaLayerException;import javazoom.jl.player.Player;public class Music extends Thread {public void run() {try {FileInputStream fil1 =new FileInputStream("src/Plants/Music/Crazy Davy.mp3");BufferedInputStream bis1 =new BufferedInputStream(fil1);Player p = new Player(bis1);p.play();} catch (FileNotFoundException e) {e.printStackTrace();} catch (JavaLayerException e) {e.printStackTrace();}}}

数据库相关操作次要功能

package Plants;import java.sql.Connection;import java.sql.DriverManager;import java.sql.ResultSet;import java.sql.SQLException;import java.sql.Statement;public class UserDao {//1定义数据库驱动public static String driver="com.mysql.jdbc.Driver" ;//定义urlpublic static String url="jdbc:mysql://localhost:3306/shoot";//定义mysql用户名,每个人的用户在安装mysql的时候是自己定义的public static String user="root";//定义mysql设置是的密码static String password="";//定义连接对象Connectionpublic static Connection con;//定义传输器对象public static Statement statement;public static void DBConnection() throws Exception {//注册数据库Class.forName(driver);//获取数据库连接con=DriverManager.getConnection(url, user, password);//获取传输器statement=con.createStatement();//}//将分数存入数据库public static void save(String name,int score) throws Exception {try {DBConnection();String sql="insert into score(username,score) values('"+name+"',"+score+")";//利用传输器将sql传入数据库statement.executeUpdate(sql);} catch (Exception e) {// TODO 自动生成的 catch 块e.printStackTrace();}finally {con.close();}}public static String[] getScoreAndUsername() throws Exception {ResultSet rs = null;String result[] = new String[100];try {DBConnection();String sql="select username,score from score order by score desc";rs = statement.executeQuery(sql);for (int i = 0 ;i<result.length;i++) {if(rs.next()) {result[i] = "第"+(i+1)+"名"+rs.getString("username")+":"+rs.getInt("score");}}} catch (Exception e) {// TODO 自动生成的 catch 块e.printStackTrace();}finally {con.close();rs.close();}return result;}public static void main(String[] args) throws Exception {String result[] = getScoreAndUsername();for(int i = 0;i<result.length;i++) {if(result[i]!=null) {System.out.println(result[i]);}}}}

简单实现的程序,其中的功能和算法也相对粗糙

BUG也很多,比如没有设置豌豆射手的安放区域,所以豌豆射手是鼠标点哪放哪的,以及子弹的生成也是通过鼠标点击的同时生成的,而且是单线程的操作,所以只能用一次点击鼠标完成操作。

僵尸设定了生命值,但是还是被子弹一碰就死,这里要修改父类godie()相关代码,但是后续不想更新了所以没有修改。

我在僵尸死的时候设定了一组轮播的图片,但是僵尸还是死后一秒直接消失,这里是数组成员REMOVE操作一旦执行就把当前僵尸的元素删除了,所以可以在子弹触碰和删除前延时操作。

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。