java坦克大战(1.0)

坦克大战

后面开始学习怎么使用java制造一个坦克大战游戏
但是不是直接开始做,而是随着这个游戏程序的制造,一边学习新知识融入到游戏中。包括多线程,反射,IO流…

Java坐标体系

在几乎所有的坐标中都有一个x轴和y轴,根据x,y的不同数据可以从x轴和y轴出发一条线,而这两条线就会形成一个交叉点。
x轴和y轴的出发点交叉点,叫做原点。如图所示

在这里插入图片描述

像素

计算机在屏幕上显示的内容都是由像素组成的,例如1080*1920,表示每行有1920个像素,每列有1080个像素。所以整个屏幕有2073600个像素,所以像素是密度单位,不是长度单位。

例如:你在1080的显示屏上使用x,y轴画了两条线,再使用2k的显示屏打开时,你会发现缩小了。
这里就是因为屏幕能显示的像素变多了,所以整体看着就觉得缩小了

Java绘图

使用Java画一个圆
在现实中绘画,需要{ 画框,画板,笔},在java中也有对应的类

  1. 定义一个自己的面板类,继承Java的面板类JPanel相当于画板。
    JPanel有个方法paint,可以使用画笔Graphics类对象的方法进行绘制
  2. 定义一个自己的框架类,也就是显示的窗口,继承Java的框架类JFrame
    在框架类的无参构造器中 把画板添加到框架里,且设置框架的尺寸和什么时候关闭程序
    JFrame有add方法可以将画板添加到框架里,setDefaultCloseOperation方法觉得啥时候关闭框架,结束程序
    还可以设置框架的尺寸,
public class test {
    public static void main(String[] args) {
        //11.实例化一个框架(框架的无参构造器,已经创建了面板和画笔了)
        new CircleFrame();
    }
}
//1.先定义一个自己的面板类(画板),继承Java的面板类,画画就是在画板上画
class MyPanel extends JPanel{
    //2.重写JPanel的paint方法(画笔方法),这里编写你要用画笔干啥,Graphics g可以理解为画笔
    @Override
    public void paint(Graphics g) {
        super.paint(g);//调用父类的方法,完成初始化
        System.out.println("paint方法运行");
        //3.画一个圆
        g.drawOval(20,20,100,100);//画圆的方法,x,y定义圆的起始位置,后面定义圆的宽和高
    }
}

//4.定义一个展示面板的框架(窗口,可以理解为画框),继承Java的JFrame框架类
class CircleFrame extends JFrame{
    //5.定义一个面板变量
    MyPanel myPanel = null;
    public CircleFrame(){//无参构造器
        //6.初始化面板,实例化面板
        myPanel = new MyPanel();
        //7.将面板放到框架(窗口)里面
        this.add(myPanel);
        //8.设置框架(窗口)的尺寸
        this.setSize(500,500);
        //9.让窗口显示出来
        this.setVisible(true);
        //10.当点击了窗口的关闭键后退出程序
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }
}

Graphics类的常用方法

  1. 画直线-drawLine(int x,int,y,int x2,int y2)
  2. 画矩形边框-drawRect(int x,int y,int width,int height)
  3. 画椭圆-drawOval(int x,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,int y…)
  7. 画字符串drawString(String str,int x,int y)
  8. 设置画笔的字体setFont(Font font)
  9. 设置画笔的颜色 setColor(Color c )

使用演示:

public class test {
    public static void main(String[] args) {
        new CircleFrame();
    }
}
class MyPanel extends JPanel{
    @Override
    public void paint(Graphics g) {
        super.paint(g);
        System.out.println("paint方法运行");
//        1. 画直线-drawLine(int x,int,y,int x2,int y2)
        g.drawLine(10,10,50,50);
//        2. 画矩形边框-drawRect(int x,int y,int width,int height)
        g.drawRect(20,20,70,70);
//        3. 画椭圆-drawOval(int x,int y,int width,int height)
        g.drawOval(20,20,100,100);
//        4. 填充矩形fillRect((int x,int y,int width,int height)
        //需要先设置一下画笔的颜色
        g.setColor(Color.BLACK);
        g.fillRect(70,70,100,90);
//        5. 填充椭圆fillOval(int x,int y,int width,int height)
        //如果不改其他颜色,就不用再设置一下了,要换其他颜色,再重新调用setColor
        g.fillOval(30,30,60,60);
//        6. 画图片-drawImage(Image img,int,int y...)
        //需要先获取一下图片,需要提前把图片放在根目录,不然编译器找不到
        Image image = Toolkit.getDefaultToolkit().getImage(Panel.class.getResource("/4.jpg"));
        g.drawImage(image,70,70,860,360,this);
//        7. 画字符串drawString(String str,int x,int y)
        //可以先设置一个颜色和设置一下字体
        g.setColor(Color.PINK);
        g.setFont(new Font("微软雅黑",Font.BOLD,30));//字体,加粗,字体大小
        g.drawString("Java",90,110);
//        8. 设置画笔的字体setFont(Font font)
//        9. 设置画笔的颜色 setColor(Color c )
    }
}
class CircleFrame extends JFrame{
    MyPanel myPanel = null;
    public CircleFrame(){
        myPanel = new MyPanel();
        this.add(myPanel);
        this.setSize(500,500);
        this.setVisible(true);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }
}

绘制坦克大战的背景区域

思路:
按照前面的学习
定义画板类和画框类,然后直接在画板上新建一个和框架(窗口)大小一样的矩形(需要填充)即可

public class Tank {
    int x ;//坦克的横坐标
    int y ;//坦克的纵坐标
}
public class MyPanel extends Panel {
@Override
    public void paint(Graphics g){
        super.paint(g);
        g.fillRect(0,0,1000,950);
    }
}
public class myWindow extends JFrame {
    MyPanel  m = null;
    public myWindow(){
        m = new MyPanel();
        this.add(m);
        this.setSize(1000,950);
        this.setVisible(true);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }

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

在这里插入图片描述

绘制坦克

可以坦克有两个特性

不同朝向
不同阵营
所以可以将绘制坦克封装到方法里,根据不同参数绘制不同的坦克

public class MyPanel extends Panel {
    Tank tank;
   @Override
    public void paint(Graphics g) {
        super.paint(g);
       System.out.println("调用paint");
       g.fillRect(0,0,500,600);
       drawTank(20,460,g,0,0);
       drawTank(90,350,g,0,1);

    }
    /**
    @param x 坦克的起始横坐标
    @param y 坦克的起始纵坐标
    @param g 画笔
    @param direct 根据方向绘制不同朝向的坦克
    @param type  根据0或者1 绘制不同颜色的坦克
    */
    public void drawTank(int x,int y,Graphics g,int direct,int type){
        switch (type){
            case 0:
                g.setColor(Color.PINK);//自己的坦克就粉色
                break;
            case 1:
                g.setColor(Color.RED);//敌人的坦克就红色
                break;
        }
            switch (direct){
                case 0://0表示绘制方向朝上的坦克
                    g.fill3DRect(x,y,10,50,false);
                    g.fill3DRect(x+10,y+5,25,40,false);
                    g.fill3DRect(x+35,y,10,50,false);
                    g.fillOval(x+10,y+15,25,25);
                    g.drawLine(x+22,y-5,x+22,y+25);
                    break;
                default://其他情况暂不考虑
                    break;
            }
    }
}

在这里插入图片描述

键盘监听

坦克大战肯定是要根据键盘的操作,坦克做出不同的动作
为了实现这个目标,需要了解一个接口

KeyListener接口,可以对键盘做出监听,获取到键盘的操作
KeyListener接口有三个方法

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

//有按键按下时,该方法触发
public void keyPressed(KeyEvent e) {}

//有按键松开时,该方法触发
public void keyReleased(KeyEvent e) { }

我们可以使用 e.getCode,获取到键盘对应的ASCII码
然后再根据ASCII码是对应的动作时 调用repaint方法,触发paint方法重绘画板

但是要在框架类 使用this.addKeyListener();方法把画板传进去

java事件处理机制

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

委派事件模型
什么是委派事件模型?

举例说明:
我通过微信向同学说“借我300块”,同学收到后,就发了红包给我

那么 事件源就是我要借钱,事件/对象,就是一条微信,同学就是事件监听者。他给我发红包就是对事件进行处理

在这里插入图片描述

在上面已经演示了键盘监听类 KeyEvent
java中还有其他的事件监听类

事件类说明
ActionEvent通常在按下按钮,或双击一个列表项或选中某个菜单时发生)
AdjustmentEvent当操作一个滚动条时发生。
ComponentEvent:当一个组件隐藏,移动,改变大小时发送。
ContainerEvent当一个组件从容器中加入或者删除时发生。
FocusEvent当一个组件获得或是失去焦点时发生。
ItemEvent当一个复选框或是列表项被选中时,当一个选择框或选择菜
KeyEvent当从键盘的按键被按下,松开时发生。
MouseEvent当鼠标被拖动,移动,点击,按下…2
TextEvento当文本区和文本域的文本发生改变时发生。
WindowEvent当一个窗口激活,关闭,失效,恢复,最小化.

事件监听器接口

  1. 当事件源产生一个事件,可以传送给事件监听者处理
  2. 事件监听者,实际上就是一个类,这个类实现了某个事件监听器接口
  3. 事件监听者接口可以有多种,不同的事件监听者接口可以监听不同事件,一个类可以实现多个监听接口
  4. 这些接口通常在java.awt.event包和javax.swing.event包中定义,

让坦克动起来

要让坦克动起来,得先画出不同朝向的坦克
首先前面已经画出了朝上的,那么横坐标和纵坐标其实不用动,将宽和高调整即可

朝上的:
g.fill3DRect(x,y,10,50,false);
g.fill3DRect(x+10,y+5,25,40,false);
g.fill3DRect(x+35,y,10,50,false);
g.fillOval(x+10,y+15,25,25);
g.drawLine(x+22,y-5,x+22,y+25);
朝右的:
g.fill3DRect(x,y+7,50,10,false);
g.fill3DRect(x+5,y+14,40,25,false);
g.fill3DRect(x,y+37,50,10,false);
g.fillOval(x+10,y+15,25,25);
g.drawLine(x+25,y+25,x+58,y+25);
朝下的:
g.fill3DRect(x,y,10,50,false);
g.fill3DRect(x+10,y+5,25,40,false);
g.fill3DRect(x+35,y,10,50,false);
g.fillOval(x+10,y+12,25,25);
g.drawLine(x+22,y+55,x+22,y+25);
朝左的:
g.fill3DRect(x,y+7,50,10,false);
g.fill3DRect(x+5,y+14,40,25,false);
g.fill3DRect(x,y+37,50,10,false);
g.fillOval(x+10,y+15,25,25);
g.drawLine(x+25,y+25,x-8,y+25);

不同的方向都制造了好后,由于前面绘制坦克的是由drawTank方法的direct来决定的
所以我们在Tank类把他变成一个属性,方便后面监听事件的更改

public class MyPanel extends Panel implements KeyListener {
    int speek = 1;
    Tank tank;
    public MyPanel(){
        tank = new Tank(20,460,0);
    }
   @Override
    public void paint(Graphics g) {
        super.paint(g);
       System.out.println("调用paint");
       g.fillRect(0,0,500,600);
       drawTank(tank.x,tank.y,g,tank.direct,0);
    }
    /**
    @param x 坦克的起始横坐标
    @param y 坦克的起始纵坐标
    @param g 画笔
    @param direct 根据方向绘制不同朝向的坦克
    @param type  根据0或者1 绘制不同颜色的坦克
    */
    public void drawTank(int x,int y,Graphics g,int direct,int type){
        switch (type){
            case 0:
                g.setColor(Color.PINK);//自己的坦克就粉色
                break;
            case 1:
                g.setColor(Color.RED);//敌人的坦克就红色
                break;
        }
            switch (direct){//0上,1右,2下,3左
                case 0://0表示绘制方向朝上的坦克
                    g.fill3DRect(x,y,10,50,false);
                    g.fill3DRect(x+10,y+5,25,40,false);
                    g.fill3DRect(x+35,y,10,50,false);
                    g.fillOval(x+10,y+15,25,25);
                    g.drawLine(x+22,y-5,x+22,y+25);
                    break;
                case 1://1表示绘制方向朝右的坦克
                    g.fill3DRect(x,y+7,50,10,false);
                    g.fill3DRect(x+5,y+14,40,25,false);
                    g.fill3DRect(x,y+37,50,10,false);
                    g.fillOval(x+10,y+15,25,25);
                    g.drawLine(x+25,y+25,x+58,y+25);
                    break;
                case 2://2表示绘制方向朝下的坦克
                    g.fill3DRect(x,y,10,50,false);
                    g.fill3DRect(x+10,y+5,25,40,false);
                    g.fill3DRect(x+35,y,10,50,false);
                    g.fillOval(x+10,y+12,25,25);
                    g.drawLine(x+22,y+55,x+22,y+25);
                    break;
                case 3://3表示绘制方向朝左的坦克
                    g.fill3DRect(x,y+7,50,10,false);
                    g.fill3DRect(x+5,y+14,40,25,false);
                    g.fill3DRect(x,y+37,50,10,false);
                    g.fillOval(x+10,y+15,25,25);
                    g.drawLine(x+25,y+25,x-8,y+25);
                    break;
                default://其他情况暂不考虑
                    break;
            }
    }

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

    }

    @Override//有按键按下时,该方法触发
    public void keyPressed(KeyEvent e) {
        if (e.getKeyCode() == 87){//前进
            moveUp();
            tank.direct = 0;
        }else if(e.getKeyCode() == 83){
            moveDown();
            tank.direct = 2;
        }else if(e.getKeyCode() == 65){
            moveLeft();
            tank.direct = 3;
        }
        else if(e.getKeyCode() == 68){
            moveRight();
            tank.direct = 1;
        }else if(e.getKeyCode() == 32){
            System.out.println("氮气加速~");
            speek +=5;
        }else{
            System.out.println(e.getKeyCode());
        }
        repaint();
    }

    @Override//有按键松开时,该方法触发
    public void keyReleased(KeyEvent e) {

    }
    public void moveUp(){
        tank.y-=speek;
    }
    public void moveLeft(){
        tank.x-=speek;
    }
    public void moveRight(){
        tank.x+=speek;
    }
    public void moveDown(){
        tank.y+=speek;
    }
}

画出敌人坦克

因为敌人坦克后面肯定是有自己的特性的所以新建一个EnemyTanks类
敌人坦克肯定不止一个,所以需要集合
且后面会运用到多线程,所以使用Vector集合来存储敌人坦克,提高安全性
然后遍历集合绘制敌人坦克

public class MyPanel extends Panel implements KeyListener {
    int speek = 1;
    Tank tank;
    Vector<EnemyTanks> enemyTanks = new Vector<>();
    public MyPanel(){
        tank = new Tank(20,460,0);
        for (int i = 0; i < 3; i++) {
            EnemyTanks enemyTank = new EnemyTanks(100*(i+1),0,2);
            enemyTanks.add(enemyTank);
        }
    }
   @Override
    public void paint(Graphics g) {
        super.paint(g);
       System.out.println("调用paint");
       g.fillRect(0,0,500,600);
       //画我方坦克
       drawTank(tank.x,tank.y,g,tank.direct,0);
       for (int i = 0; i < enemyTanks.size(); i++) {
           EnemyTanks e = enemyTanks.get(i);
           //画敌方坦克
           drawTank(e.x,e.y,g,e.direct,1);
       }
    }
    /**
    @param x 坦克的起始横坐标
    @param y 坦克的起始纵坐标
    @param g 画笔
    @param direct 根据方向绘制不同朝向的坦克
    @param type  根据0或者1 绘制不同颜色的坦克
    */
    public void drawTank(int x,int y,Graphics g,int direct,int type){
        switch (type){
            case 0:
                g.setColor(Color.PINK);//自己的坦克就粉色
                break;
            case 1:
                g.setColor(Color.RED);//敌人的坦克就红色
                break;
        }
            switch (direct){//0上,1右,2下,3左
                case 0://0表示绘制方向朝上的坦克
                    g.fill3DRect(x,y,10,50,false);
                    g.fill3DRect(x+10,y+5,25,40,false);
                    g.fill3DRect(x+35,y,10,50,false);
                    g.fillOval(x+10,y+15,25,25);
                    g.drawLine(x+22,y-5,x+22,y+25);
                    break;
                case 1://1表示绘制方向朝右的坦克
                    g.fill3DRect(x,y+7,50,10,false);
                    g.fill3DRect(x+5,y+14,40,25,false);
                    g.fill3DRect(x,y+37,50,10,false);
                    g.fillOval(x+10,y+15,25,25);
                    g.drawLine(x+25,y+25,x+58,y+25);
                    break;
                case 2://2表示绘制方向朝下的坦克
                    g.fill3DRect(x,y,10,50,false);
                    g.fill3DRect(x+10,y+5,25,40,false);
                    g.fill3DRect(x+35,y,10,50,false);
                    g.fillOval(x+10,y+12,25,25);
                    g.drawLine(x+22,y+55,x+22,y+25);
                    break;
                case 3://3表示绘制方向朝左的坦克
                    g.fill3DRect(x,y+7,50,10,false);
                    g.fill3DRect(x+5,y+14,40,25,false);
                    g.fill3DRect(x,y+37,50,10,false);
                    g.fillOval(x+10,y+15,25,25);
                    g.drawLine(x+25,y+25,x-8,y+25);
                    break;
                default://其他情况暂不考虑
                    break;
            }
    }

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

    }

    @Override//有按键按下时,该方法触发
    public void keyPressed(KeyEvent e) {
        if (e.getKeyCode() == 87){//前进
            moveUp();
            tank.direct = 0;
        }else if(e.getKeyCode() == 83){
            moveDown();
            tank.direct = 2;
        }else if(e.getKeyCode() == 65){
            moveLeft();
            tank.direct = 3;
        }
        else if(e.getKeyCode() == 68){
            moveRight();
            tank.direct = 1;
        }else if(e.getKeyCode() == 32){
            System.out.println("氮气加速~");
            speek +=5;
        }else{
            System.out.println(e.getKeyCode());
        }
        repaint();
    }

    @Override//有按键松开时,该方法触发
    public void keyReleased(KeyEvent e) {

    }
    public void moveUp(){
        tank.y-=speek;
    }
    public void moveLeft(){
        tank.x-=speek;
    }
    public void moveRight(){
        tank.x+=speek;
    }
    public void moveDown(){
        tank.y+=speek;
    }
}

在这里插入图片描述

1.0完成

至此坦克大战1.0完成,后面学习了多线程再制造2.0版本,让敌人坦克也动起来。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值