0
点赞
收藏
分享

微信扫一扫

java项目笔记 - 第16章:坦克大战1.0

小编 2022-04-24 阅读 71

第16章:坦克大战1.0

总体内容

在这里插入图片描述

项目说明

坦克大战的演示就省略了,和小时候玩的坦克大战差不多
在这里插入图片描述
在这里插入图片描述

java绘图坐标体系

坐标体系 - 介绍

在这里插入图片描述

坐标体系 - 像素

在这里插入图片描述

java绘图技术

绘图快速入门案例

案例要求:在面板上画一个小圆

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

//JFrame 相当于一个窗口
// 本例中窗口(Excise继承了JFrame)内有一画板(MyPanel),用画笔(Graphics)来绘图
public class Excise extends JFrame {//JFrame对应一个窗口
    //定义一个面板
    private MyPanel mp = null;

    //主方法
    public static void main(String[] args) {
        new Excise();
    }

    //构造器
    public Excise() {
        //初始化面板
        mp = new MyPanel();
        //把面板放到窗口中
        this.add(mp);
        //设置窗口大小
        this.setSize(400, 300);
        //设置窗口可以显示
        this.setVisible(true);
        //设置 当点击窗口的X时,程序完全退出
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }
}

//定义一个MyPanel类(面板类),继承JPanel
//   画图形,就在面板上画
class MyPanel extends JPanel {
    //说明:
    //1. MyPanel对象 相当于一个画板
    //2. Graphics g 这里g相当于画笔
    //3. Graphics中提供了很多绘图的方法
    @Override
    public void paint(Graphics g) {//paint()是绘图方法
        super.paint(g);//调用父类的方法完成初始化(不可省略)
        //画出一个圆,调用Graphics的drawOval()方法
        g.drawOval(10, 10, 100, 100);
    }
}

输出结果:
在这里插入图片描述

绘图中的paint()

在这里插入图片描述

绘图常用方法

在这里插入图片描述

项目:绘制游戏区域

游戏中有很多坦克,所以我们将坦克先抽象成一个父类,定义一些方法让子类去继承
Tank.java

package com.wpz.tankgame;

/**
 * @author 王胖子
 * @version 1.0
 * 因为该游戏会有很多坦克
 * 所以先抽象成一个父类
 */
public class Tank {
    private int x;//坦克横坐标
    private int y;//坦克纵坐标

    public Tank(int x, int y) {
        this.x = x;
        this.y = 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;
    }
}

编写我的坦克->继承Tank
MyTank.java

package com.wpz.tankgame;

/**
 * @author 王胖子
 * @version 1.0
 * 我的坦克
 */
public class MyTank extends Tank {
    public MyTank(int x, int y) {
        super(x, y);
    }
}

编写面板类->继承Jpanel(在面板上绘制游戏区域)
MyPanel.java

package com.wpz.tankgame;

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

/**
 * @author 王胖子
 * @version 1.0
 * 坦克大战的绘图区域
 */
public class MyPanel extends JPanel {
    MyTank myTank = null;//在绘图区域中先定义一个自己的坦克

    public MyPanel() {
        myTank = new MyTank(100, 100);//初始化自己的坦克
    }

    @Override
    public void paint(Graphics g) {
        super.paint(g);
        g.fillRect(0, 0, 1000, 750);//绘图区域:填充矩形,默认是黑色
    }
}

编写窗口类->继承JFrame
TankGame.java

package com.wpz.tankgame;

import javax.swing.*;

/**
 * @author 王胖子
 * @version 1.0
 * 窗口类
 */
public class TankGame extends JFrame {
    private MyPanel mp = null;//定义面板

    public static void main(String[] args) {
        new TankGame();
    }

    public TankGame() {
        this.mp = new MyPanel();//初始化面板
        this.add(mp);//把面板加到窗口中
        this.setSize(1000, 750);//设置窗口大小
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//设置关闭方式:点击X则退出程序
        this.setVisible(true);//设置是否可见
    }
}

输出效果
在这里插入图片描述

项目:绘制坦克

在这里插入图片描述

package com.wpz.tankgame;

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

/**
 * @author 王胖子
 * @version 1.0
 * 坦克大战的绘图区域
 */
public class MyPanel extends JPanel {
    MyTank myTank = null;//先定义一个自己的坦克

    public MyPanel() {
        myTank = new MyTank(100, 100);//初始化自己的坦克
    }

    @Override
    public void paint(Graphics g) {
        super.paint(g);
        g.fillRect(0, 0, 1000, 750);//绘图区域:填充矩形,默认是黑色
        //画出坦克->封装到画坦克的方法中
        drawTank(myTank.getX(), myTank.getY(), g, 0, 0);//画出我的坦克
    }

    /**
     * 该项目有两种类型坦克:①我方②敌方 -> 不同类型的坦克,颜色不同
     * 该项目有四种移动方向:不同移动方向使用画笔绘制的坦克是不同的
     *
     * @param x         坦克左上角x坐标
     * @param y         坦克左上角y坐标
     * @param g         画笔
     * @param direction 坦克的移动方向(上下左右)
     * @param type      坦克的类型(敌方/我方)
     */
    public void drawTank(int x, int y, Graphics g, int direction, int type) {
        //两种类型的坦克①我方②敌方 -> 不同类型的坦克,颜色不同
        switch (type) {
            case 0://我方
                g.setColor(Color.CYAN);
                break;
            case 1://敌方
                g.setColor(Color.YELLOW);
                break;
        }
        //四种移动方向:不同移动方向使用画笔绘制的坦克是不同的
        switch (direction) {
            case 0://向上
                g.fill3DRect(x, y, 10, 60, false);//画坦克左边轱辘(fillRect()画填充的矩形)
                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 + 30);//画坦克的炮筒
                break;
            default:
                System.out.println("暂时没有处理");

        }
    }
}

输出效果:
在这里插入图片描述

java事件处理机制

案例:小球移动

解决:怎样让小球受到键盘的控制,上下左右移动

package com.wpz.event;

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

/**
 * @author 王胖子
 * @version 1.0
 * 让小球收到键盘的控制,上下左右移动 -->来讲解java的事件控制
 */
//窗口类
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(250, 200);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setVisible(true);
        //JFrame窗口对象 可以监听键盘事件:即监听面板上发生的键盘事件
        this.addKeyListener(mp);
    }
}

//面板类
//KeyListener 是监听器,可以监听键盘事件
//面板类实现键盘监听器,所以在面板类中可以写需要监听的键盘事件
class MyPanel extends JPanel implements KeyListener {
    //为了让小球可以移动,把他左上角的坐标(x,y)设置成变量
    int x = 10;
    int y = 10;

    @Override
    public void paint(Graphics g) {
        super.paint(g);
//        g.fillOval(10,10,20,20);
        g.fillOval(x, y, 20, 20);//填充的小球,默认填充黑色
    }

    //当某个键按下,该方法被触发
    @Override
    public void keyPressed(KeyEvent e) {
//        System.out.println((char) e.getKeyCode()+"键 被按下");
        //根据用户按下不同键,来处理小球移动
        //在java中会给每一个键,分配一个值(int)
        if (e.getKeyCode() == KeyEvent.VK_DOWN) {//KeyEvent.VK_DOWN就是向下箭头对应的code
            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++;
        }
        //让面板重绘(当坐标x/y发生变化时,需要主动调用paint()方法进行重绘,这样才能显示小球移动的效果)
        this.repaint();
    }

    //当某个键释放(松开),该方法被触发
    @Override
    public void keyReleased(KeyEvent e) {

    }

    //有字符输出时,该方法被触发
    @Override
    public void keyTyped(KeyEvent e) {

    }
}

静态效果图,按↑↓←→可以控制小球移动
在这里插入图片描述

事件处理机制

基本说明

在这里插入图片描述
在这里插入图片描述

概念说明

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

项目:控制坦克上下左右移动(代码改进过程)

在这里插入图片描述

面板类MyPanel

package com.wpz.tankgame;

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

/**
 * @author 王胖子
 * @version 1.0
 * 坦克大战的绘图区域
 */
public class MyPanel extends JPanel implements KeyListener {
    MyTank myTank = null;//先定义一个自己的坦克

    public MyPanel() {
        myTank = new MyTank(100, 100);//初始化自己的坦克
        myTank.setSpeed(5);//设置坦克移动的速度
    }

    @Override
    public void paint(Graphics g) {
        super.paint(g);
        g.fillRect(0, 0, 1000, 750);//绘图区域:填充矩形,默认是黑色
        //画出坦克->封装到画坦克的方法中
        //对direction做了修改,把它放到了tank父类中(使用get()方法访问)
        drawTank(myTank.getX(), myTank.getY(), g, myTank.getDirection(), 0);//画出我的坦克

    }

    /**
     * 该项目有两种类型坦克:①我方②敌方 -> 不同类型的坦克,颜色不同
     * 该项目有四种移动方向:不同移动方向使用画笔绘制的坦克是不同的
     *
     * @param x         坦克左上角x坐标
     * @param y         坦克左上角y坐标
     * @param g         画笔
     * @param direction 坦克的移动方向(上下左右)
     * @param type      坦克的类型(敌方/我方)
     */
    public void drawTank(int x, int y, Graphics g, int direction, int type) {
        //两种类型的坦克①我方②敌方 -> 不同类型的坦克,颜色不同
        switch (type) {
            case 0://我方
                g.setColor(Color.CYAN);
                break;
            case 1://敌方
                g.setColor(Color.YELLOW);
                break;
        }
        //四种移动方向:不同移动方向使用画笔绘制的坦克是不同的
        //direction:0:向上,1:向右,2:向下,3:向左
        switch (direction) {
            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 + 30);//画坦克的炮筒
                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;
        }
    }

    //事件处理方法(对按键进行监听)
    @Override
    public void keyPressed(KeyEvent e) {
        //判断事件(当按下WDSA键时进行处理)
        if (e.getKeyCode() == KeyEvent.VK_W) {//上
            myTank.moveUp();//改变坦克的坐标(将改变坐标封装到父类的moveUp()方法中)
            myTank.setDirection(0);//改变坦克的方向(将direction作为所有坦克的属性放到父类中)
        } else if (e.getKeyCode() == KeyEvent.VK_D) {//右
            myTank.moveRight();
            myTank.setDirection(1);
        } else if (e.getKeyCode() == KeyEvent.VK_S) {//下
            myTank.moveDown();
            myTank.setDirection(2);
        } else if (e.getKeyCode() == KeyEvent.VK_A) {//左
            myTank.moveLeft();
            myTank.setDirection(3);
        }
        //重绘
        this.repaint();
    }

    @Override
    public void keyReleased(KeyEvent e) {

    }

    @Override
    public void keyTyped(KeyEvent e) {

    }
}

实体类Tank

package com.wpz.tankgame;

/**
 * @author 王胖子
 * @version 1.0
 * 因为该游戏会有很多坦克
 * 所以先抽象成一个父类
 */
public class Tank {
    private int x;//坦克横坐标
    private int y;//坦克纵坐标
    //将坦克的方向写到父类中 这样任意坦克在不同方法中 都可以设置移动方向
    private int direction;//坦克的方向(0:上,1:右,2:下,3:左)
    private int speed = 2;//移动速度

    public Tank(int x, int y) {
        this.x = x;
        this.y = y;
    }

    public int getDirection() {
        return direction;
    }

    public void setDirection(int direction) {
        this.direction = direction;
    }

    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 getSpeed() {
        return speed;
    }

    public void setSpeed(int speed) {
        this.speed = speed;
    }

    //将坦克移动时的坐标改变封装到 父类的方法中
    //直接改变坐标的x/y值(取代myTank.setY(myTank.getY()-2);)
    //先死后活:开始时坐标是加减固定值-->可以扩展成变化的--引入变量-->speed(可以在初始化坦克对象时赋值)
    public void moveUp() {
        y -= speed;
    }

    public void moveRight() {
        x += speed;
    }

    public void moveDown() {
        y += speed;
    }

    public void moveLeft() {
        x -= speed;
    }
}

窗口类

package com.wpz.tankgame;

import javax.swing.*;

/**
 * @author 王胖子
 * @version 1.0
 * 窗口类
 */
public class TankGame extends JFrame {
    private MyPanel mp = null;//定义面板

    public static void main(String[] args) {
        new TankGame();
    }

    public TankGame() {
        this.mp = new MyPanel();
        this.add(mp);
        this.setSize(1000, 750);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setVisible(true);
        this.addKeyListener(mp);//为面板添加键盘监听器
    }
}

本章作业

在这里插入图片描述
分析:
在这里插入图片描述

敌人坦克类

package com.wpz.tankgame;

/**
 * @author 王胖子
 * @version 1.0
 * 敌人的坦克
 */
public class EnemyTank extends Tank {
    public EnemyTank(int x, int y) {
        super(x, y);
    }
}

面板类

package com.wpz.tankgame;

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

/**
 * @author 王胖子
 * @version 1.0
 * 坦克大战的绘图区域
 */
public class MyPanel extends JPanel implements KeyListener {
    MyTank myTank = null;//定义一个自己的坦克
    Vector<EnemyTank> enemyTanks = new Vector<>();//定义敌人的坦克,放到Vector中
    int enemyTankSize = 3;//敌人坦克的数量

    public MyPanel() {
        myTank = new MyTank(100, 100);//初始化自己的坦克
        myTank.setSpeed(5);//设置坦克移动的速度
        //初始化敌人的坦克(注意:使用循环来添加。因为敌人坦克数量多,不要一个一个add)
        for (int i = 0; i < enemyTankSize; i++) {
            //创建一个敌人的坦克
            EnemyTank enemyTank = new EnemyTank(100 * (i + 1), 0);
            //设置方向
            enemyTank.setDirection(2);
            //加入敌人坦克集合
            enemyTanks.add(enemyTank);
        }
    }

    @Override
    public void paint(Graphics g) {
        super.paint(g);
        g.fillRect(0, 0, 1000, 750);//绘图区域:填充矩形,默认是黑色
        //画出自己的坦克->封装到画坦克的方法中
        //对direction做了修改,把它放到了tank父类中(使用get()方法访问)
        drawTank(myTank.getX(), myTank.getY(), g, myTank.getDirection(), 0);//画出我的坦克
        //画敌人的坦克->遍历集合
        for (int i = 0; i < enemyTanks.size(); i++) {
            //取出坦克
            EnemyTank enemyTank = enemyTanks.get(i);
            drawTank(enemyTank.getX(), enemyTank.getY(), g, enemyTank.getDirection(), 1);
        }
    }

    /**
     * 该项目有两种类型坦克:①我方②敌方 -> 不同类型的坦克,颜色不同
     * 该项目有四种移动方向:不同移动方向使用画笔绘制的坦克是不同的
     *
     * @param x         坦克左上角x坐标
     * @param y         坦克左上角y坐标
     * @param g         画笔
     * @param direction 坦克的移动方向(上下左右)
     * @param type      坦克的类型(敌方/我方)
     */
    public void drawTank(int x, int y, Graphics g, int direction, int type) {
        //两种类型的坦克①我方②敌方 -> 不同类型的坦克,颜色不同
        switch (type) {
            case 0://我方
                g.setColor(Color.CYAN);
                break;
            case 1://敌方
                g.setColor(Color.YELLOW);
                break;
        }
        //四种移动方向:不同移动方向使用画笔绘制的坦克是不同的
        //direction:0:向上,1:向右,2:向下,3:向左
        switch (direction) {
            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 + 30);//画坦克的炮筒
                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;
        }
    }

    //事件处理方法(对按键进行监听)
    @Override
    public void keyPressed(KeyEvent e) {
        //判断事件(当按下WDSA键时进行处理)
        if (e.getKeyCode() == KeyEvent.VK_W) {//上
            myTank.moveUp();//改变坦克的坐标(将改变坐标封装到父类的moveUp()方法中)
            myTank.setDirection(0);//改变坦克的方向(将direction作为所有坦克的属性放到父类中)
        } else if (e.getKeyCode() == KeyEvent.VK_D) {//右
            myTank.moveRight();
            myTank.setDirection(1);
        } else if (e.getKeyCode() == KeyEvent.VK_S) {//下
            myTank.moveDown();
            myTank.setDirection(2);
        } else if (e.getKeyCode() == KeyEvent.VK_A) {//左
            myTank.moveLeft();
            myTank.setDirection(3);
        }
        //重绘
        this.repaint();
    }

    @Override
    public void keyReleased(KeyEvent e) {

    }

    @Override
    public void keyTyped(KeyEvent e) {

    }
}

输出效果
在这里插入图片描述

举报

相关推荐

0 条评论