Java基础练手游戏,坦克大战(1)

一些基础知识

Java绘图坐标体系

坐标体系 - 介绍

下图说明了Java坐标系。坐标原点位于左上角,以像素为单位。在 Java坐标系中,第一个是x坐标,表示当前位置水平方向,距离坐标原点x个像素;第二个是y坐标,表示当前位置为垂直方向,距离左边原点y个像素。

Java基础练手游戏,坦克大战(1)_第1张图片

坐标体系 - 像素

1.绘图还必须要搞清一个非常重要的概念 - 像素 一个像素等于多少厘米?

2.计算机在屏幕上显示的内容都是由屏幕上的每一个 像素组成的。例如,计算机显示器的分辨率是800 * 600 ,表示计算机屏幕上的每一行都由800个点组成,共有600行整个计算机有 480 000 个像素。像素是一个密度单位,而厘米是长度单位,两者无法比较

Java绘图技术

介绍 - 快速入门

Java基础练手游戏,坦克大战(1)_第2张图片

绘图原理

Component类提供了两个和绘图相关最重要得到方法;

1.paint(Graphics g)绘制组件的外观

2.repaint()刷新组件的外观

当组件第一次在屏幕显示的时候,程序会自动的调用paint方法来绘制组件。

在以下情况paint()将会被调用:

1.窗口最小化,再最大化

2.窗口的大小发生变化

3.repaint方法被调用

Graphics类

Graphics类你可以理解就是画笔,为我们提供各种绘制图形的方法:

1.画直线 drawLine(int x1, int y1, int x2, int y2)

2.画矩形边框 drawRect(int x, int y, int width, int height)

3.画椭圆边框 drawOval(intx, int y, int width, int height)

4.填充矩形 fillRect(int x, int y, int width, int height)

5.填充椭圆 fillOval(int x, int y, int width, int height)

6.画图片 drawImage(Image img, int x, int y, ...)

7.画字符串 drawString(String str, int x, int y)

8.设置画笔字体 setFont(Font font)

9.设置画笔颜色 setColor(Color c)

Java事件处理机制

java事件处理采取"委派事件模型"。当事件发生时,产生事件的对象,会把此"信息"传递给"事件监听者处理"这里所说的"信息"实际上就是java.awt.event 事件类库里某个类所创建的对象,把它称为"事件的对象

Java基础练手游戏,坦克大战(1)_第3张图片

事件处理机制的深入了解

前面我们提到了几个重要的概念 事件源,事件监听器我们下面来全面介绍它们。

1.事件源:事件源就是一个产生事件的对象,比如按钮,窗口等。

2.事件:事件就是承载事件源状态改变时的对象,比如当键盘事件,鼠标事件,窗口事件等等。会生成一个事件对象,该对象保存着当前事件的很多信息,比如KeyEvent对象有含有被按下键的Code值。Java.awt.event包 和java.swing.event包中定义了各种事件类型

3.事件类型:

Java基础练手游戏,坦克大战(1)_第4张图片

4.事件监听器接口:

①当事件源产生一个事件,可以传送给事件监听者处理

②事件监听者实际上就是一个类,该类实现了某个事件监听器接口,比如我们在前面MyPanle就是一个类,它实现了KeyListener接口,他就可以作为一个事件监听者,对接受到的事情进行处理

③事件监听器接口有多种,不同的事件监听器接口可以监听不同的事件,一个类可以实现多个接口

④这些接口在java.awt.event包 和 javax.swing.event包中定义。

Java基础练手游戏,坦克大战(1)_第5张图片

我们主要使用KeyListener

坦克大战第一部分

    • 通过画一个圆圈,简单演示Java画图机制

第一部分,创建一个画图窗口

package draw_;

import javax.swing.*;
import java.awt.*;


@SuppressWarnings({"all"})
public class DrawCircle extends JFrame {//JFrame对应窗口,可以理解成一个画框

    //定义一个画板
    private  MyPanel mp = null;
    public static void main(String[] args) {
        new DrawCircle();
    }
    //创建一个构造器
    public DrawCircle() {
        //初始化面板
        mp = new MyPanel();
        //把面版放到窗口(画框)
        this.add(mp);
        //设置窗口大小
        this.setSize(400, 400);
        //点击窗口的×就会退出
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setVisible(true);//可以显示
    }
}

然后,先定义一个MyPanel类,继承JPanel类,在面板上画图形。

可使用快捷键 paint 快速重写

class  MyPanel extends JPanel {

    @Override
    public void paint(Graphics g) {//绘图方法
        super.paint(g);//调用父类方法完成初始化

         g.drawOval(10, 10, 100, 100);//画出一个圆形
    }
}

    • 通过控制一个小球的移动简单演示事件处理机制

在构造器中新增this.addKeyListener(mp);来调用键盘事件监听器

package event;

import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;


public class ballMove extends JFrame{

    MyPanel mp = null;
    public static void main(String[] args) {
        ballMove ballMove = new ballMove();
    }
    public ballMove(){
        mp = new MyPanel();
        this.add(mp);
        this.setSize(400,300);

        //窗口JFrame可以监听到mp面板上发生的键盘事件
        this.addKeyListener(mp);

        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setVisible(true);
    }
}

然后依旧创建一个MyPanel类

class MyPanel extends JPanel implements KeyListener {

    //为了让小球可以移动,,将它左上角设置为变量
    int x = 10;
    int y = 10;
    @Override
    public void paint(Graphics g) {
        super.paint(g);
        g.fillOval(x, y,20,20);
    }
    //字符输出该方法触发
    @Override
    public void keyTyped(KeyEvent e) {

    }
    //当某个键按下该方法触发
    @Override
    public void keyPressed(KeyEvent e) {
        //根据用户按下单的不同键,来处理小球移动
        if(e.getKeyCode() == KeyEvent.VK_DOWN){
            y++;
        }else if(e.getKeyCode() == KeyEvent.VK_UP){
            y--;
        }else if(e.getKeyCode() == KeyEvent.VK_LEFT){
            x--;
        }else if(e.getKeyCode() == KeyEvent.VK_RIGHT){
            x++;
        }
        this.repaint();
    }
    //当某个键松开,该方法触发
    @Override
    public void keyReleased(KeyEvent e) {

    }
}

    • 首先我们画出一个坦克

    • 创建一个坦克类,将坦克的位置坐标放进去,并创建构造器和seter, geter方法
package TankGame;


public class Tank {
    private int x;//坦克横坐标
    private int y;//坦克纵坐标

    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 Tank(int x, int y) {
        this.x = x;
        this.y = y;
    }
}
    • 创建我的坦克 Bnaso 类,并且继承Tank类
package TankGame;


public class Bnaso extends Tank{

    public Bnaso(int x, int y) {
        super(x, y);
    }
}
3.同样创建画板
package TankGame;

import javax.swing.*;

public class TankGame01 extends JFrame {
    //定义MyPanel
    MyPanel mp = null;
    public static void main(String[] args) {
        TankGame01 tankGame01 = new TankGame01();
    }

    public TankGame01(){
        mp = new MyPanel();
        this.add(mp);
        this.setSize(1000, 800);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setVisible(true);
    }
}
    • 创建MyPanel类
package TankGame;

import javax.swing.*;
import java.awt.*;


public class MyPanel extends JPanel {
    //定义我的坦克
    Bnaso bnaso = null;
    public MyPanel(){
        bnaso = new Bnaso(100,100);//初始化自己tank
    }

    @Override
    public void paint(Graphics g) {
        super.paint(g);
        g.fillRect(0,0,1000,750);

        //画出坦克 - 封装方法
        drawTank(bnaso.getX(),bnaso.getY(), g, 0, 0);
    }

    /**
     *
     * @param x 坦克的左上角x坐标
     * @param y 坦克的左上角y坐标
     * @param g 画笔
     * @param dir 坦克方向(上下左右)
     * @param type 坦克类型
     */
    public void drawTank(int x, int y, Graphics g, int dir, int type){
        switch (type) {
            //根据不同类型坦克,设置不同颜色
            case 0: //我的tank
                g.setColor(Color.cyan);
                break;
            case 1: //敌人的tank
                g.setColor(Color.orange);
                break;
        }

        //根据坦克方向绘制坦克
        switch (dir){
            case 0://方向向上
                g.fill3DRect(x, y, 10, 60, false);//左侧轮子
                g.fill3DRect(x + 30, y, 10, 60, false);//右侧轮子
                g.fill3DRect(x + 10, y + 10, 20, 40, false);//中间矩形
                g.fillOval(x + 10, y + 20, 20, 20);//画出圆盖
                g.drawLine(x + 20, y, x + 20, y + 40);
                break;
            default:
                System.out.println("暂时不处理");
        }
    }
}

    • 对坦克添加移动功能

1.由于坦克在调用键盘监听器后,需要向四个方向转向,所以需要画出四个方向的图
switch (dir){
            case 0://方向向上
                g.fill3DRect(x, y, 10, 60, false);//左侧轮子
                g.fill3DRect(x + 30, y, 10, 60, false);//右侧轮子
                g.fill3DRect(x + 10, y + 10, 20, 40, false);//中间矩形
                g.fillOval(x + 10, y + 20, 20, 20);//画出圆盖
                g.drawLine(x + 20, y + 30, x + 20, y);
                break;
            case 1://方向向上
                g.fill3DRect(x, y, 60, 10, false);//上边轮子
                g.fill3DRect(x, y + 30, 60, 10, false);//下边轮子
                g.fill3DRect(x + 10, y + 10, 40, 20, false);//中间矩形
                g.fillOval(x + 20, y + 10, 20, 20);//画出圆盖
                g.drawLine(x + 30, y + 20, x + 60, y + 20);
                break;
                //向下
            case 2://方向向上
                g.fill3DRect(x, y, 10, 60, false);//左侧轮子
                g.fill3DRect(x + 30, y, 10, 60, false);//右侧轮子
                g.fill3DRect(x + 10, y + 10, 20, 40, false);//中间矩形
                g.fillOval(x + 10, y + 20, 20, 20);//画出圆盖
                g.drawLine(x +20, y + 30, x + 20, y + 60);
                break;
        case 3://方向向左
            g.fill3DRect(x, y, 60, 10, false);//上边轮子
            g.fill3DRect(x, y + 30, 60, 10, false);//下边轮子
            g.fill3DRect(x + 10, y + 10, 40, 20, false);//中间矩形
            g.fillOval(x + 20, y + 10, 20, 20);//画出圆盖
            g.drawLine(x + 30, y + 20, x , y + 20);
            break;

        }
2.由于坦克需要转向,而且存在速度,所以在坦克类中需要定义一个方向属性和一个speed属性,并且提供geter和seter方法以及speed在四个方向上迭代的方法。
package TankGame02;

public class Tank {
    private int Speed = 1;
    private int dir;//Tank方向

    public int getDir() {
        return dir;
    }

    public void setDir(int dir) {
        this.dir = dir;
    }
    //移动
    public void MoveUp(){
        y -= Speed;
    }

    public void MoveRight(){
        x += Speed;
    }

    public void MoveDown(){
        y += Speed;
    }

    public void MoveLeft(){
        x -= Speed;
    }
    public Tank(int dir) {
        this.dir = dir;
    }

    public int getSpeed() {
        return Speed;
    }

    public void setSpeed(int speed) {
        Speed = speed;
    }

    private int x;//坦克横坐标
    private int y;//坦克纵坐标

    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 Tank(int x, int y) {
        this.x = x;
        this.y = y;
    }
}
3.由于需要存在敌我两种坦克,所以需要根据不同类型坦克,设置颜色
/**
     *
     * @param x 坦克的左上角x坐标
     * @param y 坦克的左上角y坐标
     * @param g 画笔
     * @param dir 坦克方向(上下左右)
     * @param type 坦克类型
     */

public void drawTank(int x, int y, Graphics g, int dir, int type){
        switch (type) {
            //根据不同类型坦克,设置不同颜色
            case 0: //我的tank
                g.setColor(Color.cyan);
                break;
            case 1: //敌人的tank
                g.setColor(Color.orange);
                break;
        }
4.创建画板和构造器
package TankGame02;

import javax.swing.*;


public class TankGame02 extends JFrame {
    //定义MyPanel
    MyPanel mp = null;
    public static void main(String[] args) {
        TankGame02 tankGame01 = new TankGame02();
    }

    public TankGame02(){
        mp = new MyPanel();
        this.add(mp);
        this.setSize(1000, 750);
        this.addKeyListener(mp);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setVisible(true);
    }
}
5.重写KeyPressed方法
 @Override
    public void keyPressed(KeyEvent e) {
        //处理WDSA键按下的情况
        if(e.getKeyCode() ==  KeyEvent.VK_W){
            //改变坦克方向
            bnaso.setDir(0);
            //修改坦克坐标
            bnaso.MoveUp();
        }else if(e.getKeyCode() == KeyEvent.VK_D){
            bnaso.setDir(1);
            bnaso.MoveRight();
        }else if(e.getKeyCode() == KeyEvent.VK_S){
            bnaso.setDir(2);
            bnaso.MoveDown();
        }else if(e.getKeyCode() == KeyEvent.VK_A){
            bnaso.setDir(3);
            bnaso.MoveLeft();
        }
        this.repaint();
    }
6.为了监听键盘事件,实现KeyListener
public class MyPanel extends JPanel implements KeyListener {
    //定义我的坦克
    Bnaso bnaso = null;
    public MyPanel(){
        bnaso = new Bnaso(100,100);//初始化自己tank
        bnaso.setSpeed(2);
    }
7.画出敌人坦克
1.创建敌人类
public class EnemyTank extends Tank {

    public EnemyTank(int x, int y) {
        super(x, y);
    }
}
2.为了方便,使用数组存放敌人坦克,并且出于线程安全的考虑,使用Vector
public class MyPanel extends JPanel implements KeyListener {
    //定义我的坦克
    Bnaso bnaso = null;
    //定义敌人坦克,放入Vector中
    Vector enemyTanks = new Vector();
    int enemyTankSize = 3;
    public MyPanel(){
        bnaso = new Bnaso(100,100);//初始化自己tank
        bnaso.setSpeed(2);
        //初始化敌人坦克
        for (int i = 0; i < enemyTankSize; i++) {
            EnemyTank enemyTank = new EnemyTank(100 * (i + 1), 0);
            enemyTank.setDir(2);
            enemyTanks.add(enemyTank);

        }
    }
3.画出坦克和敌人坦克
 public void paint(Graphics g) {
        super.paint(g);
        g.fillRect(0,0,1000,750);//填充矩形

        //画出坦克 - 封装方法
        drawTank(bnaso.getX(),bnaso.getY(), g, bnaso.getDir(), 1);
        //画出敌人坦克
        for (int i = 0; i < enemyTanks.size(); i++) {
            //取出一个坦克
            EnemyTank enemyTank = enemyTanks.get(i);
            drawTank(enemyTank.getX(), enemyTank.getY(), g, enemyTank.getDir(), 0);
        }
    }

你可能感兴趣的:(坦克大战,java,游戏,开发语言)