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

总体内容

  • 1.0版本包括:绘制游戏区域,绘制坦克(敌人和我方),实现用键盘按键来操控坦克上下左右移动(且移动过程中,坦克炮筒朝向发生变化)
  • 本文中的案例包括:
    ①用java在面板上画一个圆圈
    ②小球受键盘按键控制进行移动,
  • 本文中项目完成包括:
    ①绘制游戏区域
    ②绘制我方坦克
    ③控制坦克上下左右移动
    ④绘制敌人坦克(注意炮筒方向)

在这里插入图片描述

项目说明

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

java绘图坐标体系

坐标体系 - 介绍

在这里插入图片描述

坐标体系 - 像素

在这里插入图片描述

java绘图技术

绘图快速入门案例

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

步骤:

  1. 写一个面板类MyPanel(继承Panel),重写paint()(绘图)方法,在方法内调用Graphics(画笔)的方法drawOval()来画园
    在这里插入图片描述
  2. 写一个窗口类Excise(继承JFrame),在窗口类中定义一个面板对象,在构造器中初始化该对象,并把面板放到窗口中,设置窗口大小和是否可见
  3. 在主方法中创建窗口类对象。创建对象时会调用构造器,对窗口和面板进行设置,并调用paint()方法绘制圆
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()

在这里插入图片描述

绘图常用方法

在这里插入图片描述

  1. 画直线:drawLine方法 - 第1,2个参数为起点,第3,4个参数为终点(如果起点和重点的x值不同,则为斜线)
  2. 画矩形:drawRect方法 - 第1,2个参数为起点,第3,4个参数为长和宽
  3. 画填充矩形:fillRect方法
    ①先设置画笔的颜色g.setColor(Color.blue);
    ②再画填充颜色后的矩形g.fillRect(10,10,100,100);
  4. 画图片
    先把图片copy到out下的项目文件夹下面
    在这里插入图片描述
    在这里插入图片描述
    画图片的代码(2步):
    在这里插入图片描述
    输出结果:
    在这里插入图片描述
  5. 画字符串(也就是写字)–>三步
    给画笔设置颜色和字体,然后再写字
    在这里插入图片描述

项目:绘制游戏区域

游戏中有很多坦克,所以我们将坦克先抽象成一个父类,定义一些方法让子类去继承
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事件处理机制

案例:小球移动

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

  • 让面板实现KeyListener接口。KeyListener是监听器,可以监听键盘事件,当面板实现了该接口后,就要实现该接口的三个方法(按下,松开,输出),所以实现了该接口,就可以在该类中编写需要监听的事件
    class MyPanel extends JPanel implements KeyListener
  • 需要监听的事件为:当键盘按下↑↓←→时,小球的坐标发生相应变化。此时就需要把小球左上角的横纵坐标写成变量,方便加减
    public void keyPressed(KeyEvent e){//判断按下的键}
  • 当小球坐标发生变化时,一定要进行重绘this.repaint();
  • 在窗口类中添加面板的键盘监听器。不写这个的话,窗口是不知道需要监听面板上发生的键盘事件的(//JFrame窗口对象 可以监听键盘事件:即监听面板上发生的键盘事件)
    相当于在编码中:面板类中写需要监听的事件窗口类中为面板添加监听器
    this.addKeyListener(mp);
  • 事件监听通俗来说就是:一个类实现事件监听接口成为监听器类,然后再实现接口中处理事件的方法,当事件发生时,监听器监听到该事件,就会把该事件(KeyEvent对象)作为参数传给事件处理方法
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) {

    }
}

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

事件处理机制

基本说明

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

概念说明

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

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

在这里插入图片描述

步骤及改进代码的过程

  1. 画出不同方向的坦克。前面已经画过上,现在把右下左的坦克类型也画出来。在drawTank的第二个switch中添加代码。
  2. 写出事件处理机制的基本代码。
    ①面板类实现KeyListener接口,并实现接口的三个事件处理方法,本项目中只处理键盘按键的事件(keyPressed)
    ②判断事件(按键的类型)->WDSA。先把事件处理空下,一会再想,先写完基本流程。
    ③重绘。在判断结束后(事件处理结束后),用repaint()放啊主动调用paint()进行重绘。
    ④窗口类的构造器中,为面板类添加键盘监听器。
  3. 写事件处理的逻辑(总体分为2步)
    ①改变x/y坐标
    ②改变坦克的方向

关于上面事件处理的①,②,写一下我的想法以及改进过程

  1. 我先不考虑坦克的方向,先写了坐标的变化
    ① 最开始写的:因为坦克左上角的x和y坐标 在父类中给出了set()和get()方法,所以我直接使用了这两种方法来对坦克的x和y坐标进行修改myTank.setY(myTank.getY()-2);
    ② 改进1:上面的代码调用了两次方法,效率↓且复用性、维护性差,所以就想着把坐标的改变封装到方法中,因为这是所有坦克移动时都需要的调用的方法,所以干脆把这些方法写到父类中,体会面向对象的好处(封装)
    public void moveUp(){//向上移动 y-=2; }
    ③改进2:将移动的常量换为变量,方便控制移动的速度。 先死后活的思想,开始时坐标是加减固定值,由此想到可以扩展成变化的值,所以引入变量speed(速度)–>提供get和set方法,可以在初始化坦克对象时赋值
    public void moveUp(){ y-=speed; }
    myTank.setSpeed(5);//修改移动速度
  2. 考虑如何改变坦克的方向
    ① 最开始想到的解决方法:将direction设置成面板类的全局变量。
    首先我的需求是要在keyPressed()事件处理方法中修改坦克的方向,坦克的方向是由direction表示的,此时direction是传入drawTank()中的一个参数,我在一个方法中是访问不到另一个方法中的参数的,所以我自然想到了把direction设置成面板类中的全局变量,这样我就可以在该类中的任何方法中使用到该变量了–>可行但不好
    ②改进:direction是所有坦克都具有的属性,它表示坦克的方向,所以我把direction属性写到了tank父类中,并为它提供get和set方法
    myTank.moveUp();//改变坦克的坐标(将改变坐标封装到父类的moveUp()方法中) myTank.setDirection(0);//改变坦克的方向(将direction作为所有坦克的属性放到父类中)

面板类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);//为面板添加键盘监听器
    }
}

本章作业

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

修改的部分:

  1. 新建敌人坦克类
  2. 面板类中:定义敌人坦克集合及坦克数量,在构造器中初始化敌人坦克(同时修改坦克方向),在paint中绘制敌人坦克

敌人坦克类

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
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值