启发性的飞机小游戏(一)


写在前面

建议先将结尾源码素材下载,供练习中的对照参考,如果遇到问题,私下补课,也可以联系博主,第一次写有点多的东西,不合理的地方可以评论留言。



游戏项目的介绍

基于Eclipse的开发环境,通过AWT图形用户界面技术(现在用的少)建立java项目,目的实现:键盘操控飞机移动、炮弹任意角度飞行、碰撞爆炸效果和游戏时间计时。


一、初始化窗口

  1. 首先需要的是建立一个窗口,将背景和飞机两张图片显示出来(这里我们需要创建一个图片包和引入图片的工具类)。

代码如下:

 package game;

 import java.awt.Color;
 import java.awt.Frame;
 import java.awt.Graphics;
 import java.awt.Image;

 public class planegame extends Frame {

 Image planeImg =GameUtil.getImage("Image/plane.png");
 Image bg =GameUtil.getImage("Image/bg.jpg");

 @Override
 public void paint(Graphics g) {// 自动被调用. g相当一支画笔

    g.drawImage(bg, 0,0,null);
    g.drawImage(planeImg,250,250,null);
    }


 /**
 * 初始化窗口
 */
 public void launchFrame() {
    this.setTitle("天才爱生活作品");
    this.setVisible(true);
    this.setSize(Constant.GAME_WIDTH,Constant.GAME_HEIGHT);
    this.setLocation(200, 200);

    }

 public static void main(String[] args) {
    planegame f = new planegame();
    f.launchFrame();
 }
 }
  1. 我们还需要在game包下再创建一个类,GameUtil(名字变了相应的代码则需要改变)工具类来实现图片的加载,上面 我们有引用到.

代码如下:

 package game;

 import java.awt.Image;

 import java.awt.image.BufferedImage;

 import java.io.IOException;

 import java.net.URL;

 import javax.imageio.ImageIO;

 public class GameUtil {
 // 工具类最好将构造器私有化
 private GameUtil() {
 } 


 /**
 * 
 * 返回指定路径文件的图片对象
 * @param path
 * @return
 */
 public static Image getImage(String path) {
    BufferedImage bi = null;
    try {
        URL u = GameUtil.class.getClassLoader().getResource(path);
        bi = ImageIO.read(u);
    } catch (IOException e) {
        e.printStackTrace();
    }
    return bi;
   }
 }
  1. 同2创建Constant类,方便后续的调用

     public class Constant {
       public static final int GAME_WIDTH=500;
       public static final int GAME_HEIGHT=500;
     }
    
  2. 效果如下

    图片素材和所有代码见文章末尾打包。


二、线程内部类实现动画

  1. 在(代码中)初始化窗口

    new PaintThread().start(); //启动重画窗口的线程

  2. 创建一个内部类代码如下:

//帮助我们反复的重画窗口

    class PaintThread extends Thread{
        @Override
        public void run() {
            while(true) {
            System.out.println("重画了一次");//测试使用最后删掉
                repaint();

                try {
                    Thread.sleep(40); //1s=1000ms
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
  1. 会出现窗口的闪烁问题加入双缓冲解决

    private Image offScreenImage = null;
    
    public void update(Graphics g) {
     if(offScreenImage == null)
         offScreenImage = this.createImage(Constant.GAME_WIDTH,Constant.GAME_HEIGHT);//这是游戏窗口的宽度和高度
    
     Graphics gOff = offScreenImage.getGraphics();
     paint(gOff);
     g.drawImage(offScreenImage, 0, 0, null);
     }
    
    1. 可以将画飞机的位置定义成变量,令坐标++就会产生飞机移动的动画

三、为游戏建一个父类

  1. 类似初始化窗口 2 步骤(下面类相同方法)

    代码如下:

 import java.awt.Graphics;
 import java.awt.Image;    
 import java.awt.Rectangle;
 public class GameObject {
 Image img;
 double x,y;
 int speed;
 int width,height;

 public void drawSelf(Graphics g){
     g.drawImage(img, (int)x, (int)y, null);
 }

 public GameObject(Image img, double x, double y, int speed, int width, int height) {
    super();
    this.img = img;
    this.x = x;
    this.y = y;
    this.speed = speed;
    this.width = width;
    this.height = height;
 }

 public GameObject(Image img, double x, double y) {
    super();
    this.img = img;
    this.x = x;
     this.y = y;
 }

 public GameObject() {

 }
 /**
  * 返回物体所在的矩形,便于后续的碰撞检测
  * @return
  */
 public Rectangle getRect() {
    return new Rectangle((int)x,(int)y,width,height);
    }   
 }

四、飞机类

  • 在其中封装飞机的一些方法:画自己、飞机位置方法、键盘监听、游戏存活时间.

    1. 重写一个drawself,画飞机的移动,飞机位置的方法,同时在planegame里调用
      Plane plane= new Plane(planeImg,250,250);

代码如下:

 package game;

 import java.awt.Graphics;

 import java.awt.Image;

 public class Plane  extends GameObject {

 public  void  drawSelf(Graphics  g){
    g.drawImage(img, (int)x,(int) y, null);
    x++;
  }

    public  Plane(Image  img, double x, double y){
    this.img = img;
    this.x = x;
    this.y = y;
 }

 }
  1. 在主窗口里写入键盘控制代码

    • 如下

      /键盘控制/

      class KeyMonitor extends KeyAdapter{
      
      @Override
      public void keyPressed(KeyEvent e) {
         plane.addDirection(e);
      }
      
      @Override
      public void keyReleased(KeyEvent e) {
         plane.minusDirection(e);
      }
      
      }
      
      • 在初始化窗口增加监听

        addKeyListener(new KeyMonitor()); //给窗口增加键盘的监听

      • 在飞机类封装方法,定义变量(上、下、左、右)、增加方向的方法、x++改为根据方向判断,注释掉的存活时间部分会用到。

代码如下:

 import java.awt.Graphics;

 import java.awt.Image;

 import java.awt.event.KeyEvent;

 public class Plane extends   GameObject {

 int speed=3;

 boolean left,up,right,down;

 /*boolean live=true;*/

 public void drawSelf(Graphics g){
    /*if(live) { */
        g.drawImage(img, (int)x, (int)y, null);

     if(left) {
        x-=speed;
     }
     if(right) {
         x+=speed;
     }
     if(up) {
         y-=speed;
     }
     if(down) {
        y+=speed;
     }

    /*}else {

    }*/

 }

 public Plane(Image img,double x,double y) {
    this.img=img;
    this.x=x;
    this.y=y;
    this.speed=3;
    this.width=40;
    this.height=40;

 }


 //按下某个键增加相应的方向
   public void addDirection(KeyEvent e) { 
       switch(e.getKeyCode()) {
       case KeyEvent.VK_LEFT:
           left=true;
           break;
       case KeyEvent.VK_UP:
           up=true;
           break;
       case KeyEvent.VK_RIGHT:
           right=true;
           break;
       case KeyEvent.VK_DOWN:
           down=true;
           break;
       }

   }   
 //抬起某个键释放相应的方向
       public void minusDirection(KeyEvent e) { 
           switch(e.getKeyCode()) {
           case KeyEvent.VK_LEFT:
               left=false;
               break;
           case KeyEvent.VK_UP:
               up=false;
               break;
           case KeyEvent.VK_RIGHT:
               right=false;
               break;
           case KeyEvent.VK_DOWN:
               down=false;
               break;
           }

 } }

五、炮弹类

  1. 构造炮弹的方法
  2. 画炮弹(包括碰撞反弹)
  3. 主窗口内操作
  • 和plane类一样主窗口new对象直接50个(可改)Shell[] shells=new Shell[50];
  • 初始化窗口初始化
    for(int i=0;i<shells.length;i++) {
    shells[i]= new Shell();
     }
  • 画方法里 画出所有的炮弹(位置画飞机的下面)
  for(int i=0;i<shells.length;i++) {
   shells[i].draw(g);
  }
  1. 类代码:

    package game;
    
     import java.awt.Color;
    
     import java.awt.Graphics;
    
      public class Shell extends GameObject {
    
    double degree;

     public Shell() {
    x=200;
    y=200;
    width=10;
    height=10;
    speed=2;
    degree=Math.random()*Math.PI*2;
    }

    public void draw(Graphics g) {
    Color c =g.getColor();
    g.setColor(Color.YELLOW);

    g.fillOval((int)x, (int)y, width, height);//填充

    //炮弹沿着任意角度去飞
    x+=speed*Math.cos(degree);
    y+=speed*Math.sin(degree);

    if(x<0||x>Constant.GAME_WIDTH-width) {
        degree =Math.PI-degree;
    }
    if(y<30||y>Constant.GAME_HEIGHT-height) {
        degree =-degree;
    }
    g.setColor(c);

   }
     }
  1. 效果:


六、碰撞检测和爆炸类

  • 碰撞检测
  1. 主窗口画炮弹的循环里加入
boolean touch=shells[i].getRect().intersects(plane.getRect());
                   if(touch) {
                    plane.live=false;}
  1. 将飞机类的注释去掉,如果发生碰撞飞机消失死掉
  • 爆炸类
  1. 包含爆炸的位置和爆炸的图片加载

代码如下:

package game;

import java.awt.Graphics;

import java.awt.Image;

public class Explode {
double x, y;

static Image[] imgs = new Image[16];
static {
    for (int i = 0; i < 16; i++) {
        imgs[i] = GameUtil.getImage("image/explode/e" + (i + 1) + ".gif");
        imgs[i].getWidth(null);
    }
}

int count;

public void draw(Graphics g) {
    if (count <= 15) {
        g.drawImage(imgs[count], (int) x, (int) y, null);
        count++;
    }
}

public Explode(double x, double y) {
    this.x = x;
    this.y = y;
}
  }
  1. 在主窗口声明 Explode bao;在画炮弹方法如果飞机死亡中加入

     if(bao==null) {
     bao= new Explode(plane.x,plane.y);    
      }
    
    1. 效果

七、增加游戏计时

  1. 主窗口定义时间变量

    Date startTime=new Date();
    Date endTime;
    int period;//游戏持续的时间
    
    1. 在爆炸的if语句里加入

      endTime=new Date();
      period=(int)((endTime.getTime()-startTime.getTime())/1000);

    2. 在画炮弹里加入

      //计时功能,给出提示

      if(!plane.live) {
       g.setColor(Color.red);
       Font f=new Font("宋体",Font.BOLD,50);
       g.setFont(f);
       g.drawString("时间:"+period+"秒",(int)plane.x, (int)plane.y);
        }
      
    3. 在主窗口画方法开始 加Color c=g.getColor();结束 加g.setColor(c);
      变回原来的颜色


   转载规则


《启发性的飞机小游戏(一)》 zfylearn 采用 知识共享署名 4.0 国际许可协议 进行许可。
 上一篇
java容器、泛型及一些知识点的回顾 java容器、泛型及一些知识点的回顾
记录一些自己在学习中认识不够清晰的知识点,方便自己回顾 一、 集合的知识结构图 什么时候使用集合? 当我们需要将一些相同结构的个体整合在一起时,就可以考虑使用集合了 。举例:购物车 为什么要使用集合? 集合和数组相似点
2019-08-09 zfylearn
下一篇 
yilia主题配置中遇到的一些问题 yilia主题配置中遇到的一些问题
一、头像设置中的问题问题 解决方法 二、推送到远端时的问题 问题如下 解决方法打开方式 打开位置 三、点击所有文章的缺失问题解决方法 1、node版本大于6.2 2、博客根目录下(和上面打开位置相同)执行命
2019-07-08 zfylearn
  目录