JAVA零基础学习之路(三十)

飞机大战

简介和项目

通过游戏项目学习整个Java基础知识体系。比如:多线程用来实现动画效果、容器实现对于多发炮弹的存取和处理、常用类等等的应用。

大纲知识点要求
游戏项目基本功能开发 AWT基本知识 了解
  ImagelO 加载图片 掌握
  多线程和内部类 了解
  双缓冲技术 了解
飞机类设计 键盘控制 了解
  八个方向自由控制 了解
  类的设计(复习面向对象) 理解
炮弹类设计 炮弹任意角度飞行 了解
  容器或数组存储炮弹 了解
  矩形碰撞检测 了解
爆炸类设计 利用数组实现系列图片轮播 了解
  主窗囗中实现爆炸对象展示 了解
  时间控制 了解
  字符串显示 了解

游戏项目基本功能开发

AWT技术画出游戏主窗口

  • 基本功能实现

AWT和Swing是Java中常见的GUI(图形用户界面)技术。仅限于画出最基本的窗口和图形加载,所以,大家无需在此花大量时间学习这两门技术。

本项目中,我们使用的是 AWT技术,它是Java中最老的GUI技术,非常简单。

建立Java项目,并建立类MyGameFrame。

import java.awt.*;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
public class MyGameFrame extends Frame {
    //初始化窗口
    public void launchFrame(){
        this.setTitle("飞机大战");
        this.setvisible(true);//窗口默认不可见。需要让他可见
        this.setSize(width: 500, height: 500);
        this.setLocation(x:300, y:300);
        //增加关闭窗口的动作
        this.addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                System.exit(status:0);
             }
        });
    }
    public static void main(String[] args) {
        MyGameFrame frame = new MyGameFrame();
        frame.LaunchFrame();
    }
}

图形和文本绘制

paint方法

1.如果要在窗口中画图或者显示什么内容,重写paint(Graphics g)方法。

2. paint()画出窗口及其内部内容。它会被系统自动调用。我们不需要去调用这个方法。

【例】paint方法介绍

@Override
public void paint(Graphics g) {
    //paint方法作用是:画出整个窗口及内部内容。被系统自动调用。
}

ImagelO实现图片加载技术

public class MyGameFrame extends Frame {
    Image bg = GameUtil.getImage(path:"images/bg.jpg");
    Image plane = GameUtil.getImage(path:"images/plane.png");
    //初始化窗口
    public void launchFrame(){...}
    @Override
    public void paint(Graphics g) {
        g.drawImage(bg, x:0, y:0, width:500, height:500, observer: null);
        g.drawImage(plane, x: 200, y:200, width: 30, height:30, observer: null);
    }
    public static void main(String[] args] {
        MyGameFrame frame = new MyGameFrame();
        frame.launchFrame();
    }
}

双缓冲技术解决闪烁问题

在实际开发中,绘制图形是非常复杂的,绘图可能需要几秒甚至更长时间,也经常发生闪烁现象,为了解决这个问题,我们通常使用“双缓冲技术”。

“双缓冲技术”的绘图过程如下:

1、在内存中创建与画布一致的缓冲区

2、在缓冲区画图

3、将缓冲区位图拷贝到当前画布上

4、释放内存缓冲区

双缓冲即在内存中创建一个与屏幕绘图区域一致的对象,先将图形绘制到内存中的这个对象上,再一次性将这个对象上的图形拷贝到屏幕上,这样能大大加快绘图的速度。

我们只需将如下“双缓冲”实现代码,放入MyGrameFrame 类中,即可:

【例】添加双缓冲技术

private Image offScreenImage = null;
public void update(Graphics g) {
    if(offScreenlmage == null)
        offScreenlmage=this.createlmage(500,500);//这是游戏窗口的宽度和高度
    Graphics gOff = offScreenlmage.getGraphics();
    paint(gOff);
    g.drawlmage(offScreenlmage, 0, 0, null);
}

GameObject类设计

import java.awt.*;
//游戏物体的根类
public class GameObject {
    Image img;//对应的图片
    int x,y;//坐标
    int speed;//物体移动速度
    int width,height;//物体的宽度和高度
    //画自己
    public void drawMySelf(Graphics g){
        g.drawImage(img,x,y,width,height, observer: null);
    }
    //返回该物体对应的矩形
    public Rectangle getRec(){
        return new Rectangle(x,y,width,height);
    }
    public GameObject(){}
    public GameObject(Image img, int x, int y, int speed, int width, int height){
        this.img = img;
        this.x = x;
        this.y = y;
        this.speed = speed;
        this.width = width;
        this.height = height;
    }
    public Game0bject(Image img, int x, int y, int speed) {
        this(img,x,y);
        this.speed = speed; 
    }
    public Game0bject(Image img, int x, int y) {
        this(img);
        this.x = x;
        this.y =y;
    }
    public GameObject(Image img) {
        this.img =img;
        if(this.img!=null){
            this.width = img.getWidth(observer:null);
            this.height = img.getHeight(observer:null);
        }
    }
}

设计飞机类

有了GameObject类,设计飞机类特别简单。

飞机是我们游戏中的主物体,需要由玩家直接控制,手段有:键盘、鼠标、触摸屏等等。无论是什么硬件,本质上都是玩家通过硬件改变游戏物体的坐标,从而实现多种多样的效果。

键盘控制原理

键盘和程序交互时,每次按下键、松开键都会触发相应的键盘事件,事件的信息都封装到了KeyEvent 对象中。

为了识别按下的键是哪个键,系统对键盘所有按键做了编号,每个按键都对应相应的数字。比如:回车键对应数字10,空格键对应数字32等。这些编号,我们都可以通过KeyEvent对象来查询,KeyEvent.VKENTER实际就是存储了数字10。

增加操控功能

我们为飞机类增加了4个方向,用来控制飞机的移动。同时,为了后续需求,也增加了live变量,它表示飞机是“活的”还是“死的”,“活的”我们就画出飞机,“死的”就不画飞机了。

【例】Plane类:增加操控功能

package com.bjsxt.plane;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.KeyEvent;
public class Plane extends GameObject {
    boolean left, up, right, down;
    boolean live = true;
    //按下上下左右键,则改变方向值。 
    //比如:按下上键,则e.getKeyCode()的值就是VK_UP,那么置:up=true;
    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;
        default:
            break;
        }
    }
    @Override
    public void drawMySelf(Graphics g) {
        super.drawMySelf(g);
        //根据方向,计算飞机新的坐标
        if(left){
            x -= speed;
        }
        if(right){
            ×+=speed;
        }
        if(up){
             y -= speed;
        }
        if(down){
             y += speed;
        }
    }
}

炮弹类设计

通过炮弹类的设计,我们可以更深入面向对象编程以及数组的知识。同时,可能还需要读者稍微回忆一下初中数学曾学过的三角函数,这样更能理解炮弹飞行路径的计算原理。当然,如果忘记这些知识了也没关系,毕竟在实际开发中很少涉及数学原理性的内容。

炮弹类我们用实心的黄色椭圆实现,不再加载新的图片。当然,大家可以自行找一些炮弹图片亦可。

我们的逻辑是在窗口固定位置(200,200)处生成炮弹,炮弹方向是随机的,并且遇到边界会反弹。

【例】Shell类

package com.bjsxt.plane;
import java.awt.Color;
import java.awt.Graphics;
public class Shell extends GameObject {
    double degree;
    public Shell(){
        degree = Math.random()*Math.P*2;
        ×=200;
        y=200;
        width = 10;
        height = 10;
        speed = 3;
        //炮弹沿着任意角度飞行
        × += speed*Math.cos(degree);
         y += speed*Math.sin(degree);
         //如下代码,用来实现碰到边界,炮弹反弹回来(原理和打台球游戏一样)
        if(y>Constant.GAME HEIGHT-height|ly<30){
            degree = -degree;
        }
        if(x<O||x>Constant.GAME_ WIDTH-width){
            degree = Math.P/-degree;
        }
        //返回给外部,变回以前的颜色
        g.setColor(c);
    }
}

炮弹任意角度飞行路径

炮弹沿着任意角度飞行,核心代码就两行:

× += speed*Math.cos(degree);

y += speed*Math.sin(degree);

这里实际用到了初中学的三角函数,通过cos/sin将任意角度分解到×轴、Y轴,从而可以精确的直到x、y坐标的变化情况。

碰撞检测技术

游戏中,碰撞是遇到最频繁的技术。当然,很多游戏引擎内部已经做了碰撞检测处理,我们只需调用即可。

矩形检测原理

游戏中,多个元素是否碰到一起,实际上,通常是用“矩形检测”原理实现的。我们在前面提到,游戏中所有的物体都可以抽象成“矩形”,我们只需判断两个矩形是否相交即可。对于一些复杂的多边形、不规则物体,实际上是将他分解成多个矩形,继续进行矩形检测。

Java的APl中,为我们提供了Rectangle类来表示矩形相关信息,并且提供了intersects()方法,直接判断矩形是否相交。

我们的游戏逻辑是:“飞机碰到炮弹,则死亡”。也就是说,我们需要检测:“飞机和所有的炮弹是否碰撞”。如果有50个炮弹对象,则进行50次比对检测即可。我们修改MyGameFrame类的paint()方法

【例】MyGameFrame类:增加碰撞检测

public void paint(Graphics g){
    g.drawlmage(bglmg, 0, 0null);
    plane.drawMySelf(g);//画出飞机本身
    //画出容器中所有的炮弹
    for(int i=0;i<shellList.size();i+ +){
        Shell b ==shellList.get(i);
        b.draw(g);//飞机和所有炮弹对象进行矩形检测
        boolean peng = b.getRect().intersects(plane.getRect()
        if(peng){
            plane.live = false;//飞机死掉,画面不显示
        }
    }
}

分享一个全面学习JAVA的视频教程

以上就是小编为大家整理的关于JAVA的知识。

后续持续更新,还望诸君多多学习,早日上岸!

需要学习具体教程的可以关注私信我哦!

posted @ 2022-09-09 17:43  STARRY丶SKY  阅读(57)  评论(0)    收藏  举报