zoukankan      html  css  js  c++  java
  • Java坦克大战(一)

    接下来的几篇博客,想记录一下通过学习坦克大战项目来循序渐进的学习Java基础。主要是为了巩固基础知识,当然学习编程重要的还是多敲,问题通常是在敲代码的过程中发现的,积累也是在敲代码中寻求的经验。这个坦克大战项目是利用Java图形界面来做的,比较简陋。但是,在不断的往里面加功能的时候,可以学到很多知识,最重要的还是体会Java的面向对象编程思想。下面介绍几个用的上的Demo,最后是坦克大战的1.0版本。

    Demo1:回顾事件处理机制

    /*
     * 功能:事件处理机制(ActionListener的应用)
     */
    package com.fanghua1;
    import java.awt.*;
    import javax.swing.*;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.awt.event.*;
    
    public class Demo1_1 extends JFrame implements ActionListener {
        // 定义一个panel
        MyP mp = null;
        JButton jb1 = null;
        JButton jb2 = null;
    
        public static void main(String[] args) {
            // TODO Auto-generated method stub
            Demo1_1 be = new Demo1_1();
        }
    
        public Demo1_1() {
            mp = new MyP();
            jb1 = new JButton("黑色");
            jb2 = new JButton("红色");
    
            this.add(jb1, BorderLayout.NORTH);
            mp.setBackground(Color.black);
            this.add(mp);// 中间是默认的,不用加参数
            this.add(jb2, BorderLayout.SOUTH);
            
    
            // 注册监听(this 代表Demo9_4)(每创建一个对象就有一个this)
            //jb1、jb2都是事件源对象
            jb1.addActionListener(this);
            // 指定Action命令
            jb1.setActionCommand("aa");
            jb2.addActionListener(this);
            jb2.setActionCommand("bb");
    
            jb1.addActionListener(new Cat());
            jb2.addActionListener(new Cat());
            
            this.setSize(200, 150);
            this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            this.setVisible(true);
        }
    
        @Override
        // 对事件处理的方法,actionPerformed函数 
        //ActionEvent e 是事件对象
        public void actionPerformed(ActionEvent e) {
            // TODO Auto-generated method stub
            // System.out.println("OK");//用来测试监听有没有实现,看控制台
            // 判断那个按钮被点击
            if (e.getActionCommand().equals("aa")) {
                System.out.println("你点击的是黑色");
                mp.setBackground(Color.black);
            } else if (e.getActionCommand().equals("bb")) {
                System.out.println("你点击的是红色");
                mp.setBackground(Color.red);
            } else {
                System.out.println("不知道");
            }
        }
    
        class MyP extends JPanel {
    
            public void Paint(Graphics g) {
                super.paint(g);
                g.fillRect(0, 0, 30, 30);
    
            }
        }
    }
    //一个事件源并不是只有一个事件监听者,他可以有多个事件监听者
    class Cat implements ActionListener{
    
        @Override
        public void actionPerformed(ActionEvent e) {
            if(e.getActionCommand().equals("aa")){
                System.out.println("我监听到了黑色");
            }else if(e.getActionCommand().equals("bb")){
                System.out.println("我监听到了红色");
            }else{
                System.out.println("Nothing");
            }
            
        }
        
    }

    Demo2:加深对事件处理机制的理解

    /*
     * 加深对事件处理机制的理解
     * 通过上下左右键,来控制小球的位置
     */
    package com.fanghua1;
    import java.awt.*;
    import javax.swing.*;
    import java.awt.event.*;
    
    public class Demo1_2 extends JFrame {
    
        // 定义
        PaintO jp = null;
    
        // 构造函数中初始化
        public Demo1_2() {
            jp = new PaintO();
    
            this.add(jp);
    
            this.addKeyListener(jp);
    
            this.setSize(400, 300);
            this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            this.setVisible(true);
        }
    
        public static void main(String[] args) {
            // TODO Auto-generated method stub
            new Demo1_2();
        }
    
    }
    
    // 定义自己的面板
    class PaintO extends JPanel implements java.awt.event.KeyListener {
        int x = 10;
        int y = 10;
    
        public void paint(Graphics g) {
            super.paint(g);
            g.fillOval(x, y, 40, 40);
        }
    
        @Override
        // 键的一个值被输出
        public void keyTyped(KeyEvent e) {
            // TODO Auto-generated method stub
    
        }
    
        @Override
        // 键被按下
        public void keyPressed(KeyEvent e) {
            // TODO Auto-generated method stub
            // System.out.print("按下"+(char)e.getKeyCode());
    
            if (e.getKeyCode() == KeyEvent.VK_DOWN) {
                // x=x;这样就不用写了
                y++; // y+=5;提速
    
                // 调用repaint()函数,来重绘界面
                this.repaint();
    
            } else if (e.getKeyCode() == KeyEvent.VK_UP) {
                y--;
                this.repaint();
            } else if (e.getKeyCode() == KeyEvent.VK_LEFT) {
                x--;
                this.repaint();
            } else if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
                x++;
                this.repaint();
            }
    
        }
    
        @Override
        // 键被释放
        public void keyReleased(KeyEvent e) {
            // TODO Auto-generated method stub
    
        }
    
    }
    //功能:事件处理机制 演示1.2
    package com.fanghua1;
    import java.awt.*;
    import javax.swing.*;
    
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.awt.event.KeyEvent;
    import java.awt.event.KeyListener;
    import java.awt.event.MouseEvent;
    import java.awt.event.MouseListener;
    import java.awt.event.WindowEvent;
    import java.awt.event.WindowListener;
    
    public class Demo1_3 extends JFrame {
    
        Mypanl1_3 mp1 = null;
    
        public static void main(String[] args) {
            // TODO Auto-generated method stub
            new Demo1_3();
        }
    
        public Demo1_3() {
    
            // 这里经常忘记
            mp1 = new Mypanl1_3();
    
            this.add(mp1);
    
            // 注册监听
            this.addKeyListener(mp1);
            this.addMouseListener(mp1);
            this.addWindowListener(mp1);
            this.addMouseMotionListener(mp1);
            // this.addActionListener(mp1);
    
            // 按钮用这个,this.addActionListener(mp1);
    
            this.setSize(300, 400);
            this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            this.setVisible(true);
    
        }
    }
    
    // 这个经常用,java.awt.event.MouseMotionListener 鼠标移动和拖拽
    class Mypanl1_3 extends JPanel implements java.awt.event.MouseMotionListener,
            KeyListener, MouseListener, WindowListener {
    
        public void paint(Graphics g) {
            super.paint(g);
        }
    
        @Override
        public void windowOpened(WindowEvent e) {
            // TODO Auto-generated method stub
            System.out.print("开启窗口被调用" + e.getClass());
        }
    
        @Override
        public void windowClosing(WindowEvent e) {
            // TODO Auto-generated method stub
    
        }
    
        @Override
        public void windowClosed(WindowEvent e) {
            // TODO Auto-generated method stub
            System.out.println("窗口关闭了");
    
        }
    
        @Override
        public void windowIconified(WindowEvent e) {
            // TODO Auto-generated method stub
    
        }
    
        @Override
        public void windowDeiconified(WindowEvent e) {
            // TODO Auto-generated method stub
    
        }
    
        @Override
        // 窗口激活
        public void windowActivated(WindowEvent e) {
            // TODO Auto-generated method stub
            System.out.println("窗口激活");
        }
    
        @Override
        // 窗口不激活
        public void windowDeactivated(WindowEvent e) {
            // TODO Auto-generated method stub
            System.out.println("窗口不激活");
    
        }
    
        @Override
        // 1.鼠标点击
        public void mouseClicked(MouseEvent e) {
            // TODO Auto-generated method stub
            System.out
                    .println("当前鼠标点击的横坐标是" + e.getX() + "当前鼠标点击de纵坐标是" + e.getY());
        }
    
        @Override
        // 2.鼠标按压,没松开
        public void mousePressed(MouseEvent e) {
            // TODO Auto-generated method stub
            System.out.println("鼠标按压,没松开");
    
        }
    
        @Override
        // 3.鼠标松开
        public void mouseReleased(MouseEvent e) {
            // TODO Auto-generated method stub
            System.out.println("鼠标松开");
    
        }
    
        @Override
        // 4.鼠标移动到MyPanel
        public void mouseEntered(MouseEvent e) {
            // TODO Auto-generated method stub
            System.out.println("鼠标移动到面板");
    
        }
    
        @Override
        // 5.鼠标离开
        public void mouseExited(MouseEvent e) {
            // TODO Auto-generated method stub
            System.out.println("鼠标离开");
    
        }
    
        @Override
        // 1.键输入 (与 keyPressed的不同是,外围一圈的键都不会有反应)
        public void keyTyped(KeyEvent e) {
            // TODO Auto-generated method stub
    
        }
    
        @Override
        // 2.键按下(我测试过了:
        // 字母和少数键没反应,其他键盘最外一圈F1-F12,Delete等控制台之类都有反应)
        public void keyPressed(KeyEvent e) {
            // TODO Auto-generated method stub
            // 注意:这里切换到美式键盘下演示。我在搜狗输入法下演示了,结果总出不来
            System.out.println(e.getKeyChar() + "键按下");
        }
    
        @Override
        // 键松开
        public void keyReleased(KeyEvent e) {
            // TODO Auto-generated method stub
    
        }
    
        @Override
        // 重要:鼠标拖拽
        public void mouseDragged(MouseEvent e) {
            // TODO Auto-generated method stub
            System.out.println("鼠标拖拽了");
    
        }
    
        @Override
        // 重要:鼠标移动
        public void mouseMoved(MouseEvent e) {
            // TODO Auto-generated method stub
            // System.out.println("鼠标移动了");
            System.out.println("当前移动移动横坐标是" + e.getX() + "当前移动纵坐标是" + e.getY());
        }
    }

    Demo3:进程与线程

    /* 功能:进程与线程练习
     * Java中一个类要当作线程来使用,方法有两种:
     * 1.继承Thread类,并重写run函数
     * 2.实现Runnable接口,并重写run函数
     * 在这里就可以看出继承(类)和实现(类)的区别了
     */
    package com.fanghua1;
    
    public class Demo1_4 extends Thread {
        public static void main(String[] args) {
            // TODO Auto-generated method stub
            Demo1_4 de = new Demo1_4();
            // 启动run函数
            de.start();
        } 
    
        int times = 0;
    
        @Override
        public void run() {
            // TODO Auto-generated method stub
            // 在控制台,每隔一秒输出一句“HeLLo Word”
            while (true) {
                // 每隔一秒=休眠一秒
                try {
                    Thread.sleep(1000);// 1000表示1000毫秒
                    // sleep 会让该线程进入到Blocked(阻塞)状态,并释放资源
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                times++;
                System.out.println("HeLLo Word" + times);
                if (times == 10) {
                    // 退出程序
                    break;
                }
            }
        }
    }
    /* 功能:加深理解多线程
     * 编写程序,该程序可以接收一个整数n
     * 创建一个线程计算从1+......+n 并输出结果
     * 创建另一个线程每隔一秒在控制台输出“我是另一个线程,我输出第n个HeLLo”
     * 两个工作要同时进行
     * 注意:如果说没有任何要求的情况下来开发线程,最好用接口来实现,给别人继承的空间
     *之后会具体说继承和实现的区别
     */
    
    package com.fanghua1;
    
    public class Demo1_6 {
    
        public static void main(String[] args) {
            // TODO Auto-generated method stub
            new Thread(new Bird(10)).start();
            new Thread(new Pig(10)).start();
    
        }
    }
    
    // 计算需求
    class Bird implements Runnable {
    
        int n = 0;
        int res = 0;
        int times = 0;
        public Bird(int n) {
            this.n = n;
        }
    
        @Override
        public void run() {
            // TODO Auto-generated method stub
            // 每隔1秒算一次
            while (true) {
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                res += (++times);
                System.out.print("当前结果是" + res);
                if (times == n) {
                    System.out.print("最后结果是" + res);
                    break;
                }
            }
        }
    
    }
    
    // 输出需求
    class Pig implements Runnable {
        int n = 0;
        int times = 0;
    
        public Pig(int n) {
            this.n = n;
        }
    
        public void run() {
            // TODO Auto-generated method stub
            while (true) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                System.out.println("我是另一个线程,我输出第" + times + "个HeLLo");
                times++;
                if (times == n) {
                    break;
                }
            }
        }
    }

    坦克大战(1.0版本)

    /*
    * 功能:画出坦克 * 学习:图形界面 */ package com.fanghua1; import java.awt.*; import javax.swing.*; public class MyTankGame1_1 extends JFrame { Mypanel mp=null; public static void main(String[] args) { // TODO Auto-generated method stub new MyTankGame1_1(); } // 构造函数 public MyTankGame1_1() { mp=new Mypanel(); this.add(mp); this.setSize(600,500); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); this.setVisible(true); } } // 我的面板,不要在JFram上面画坦克,会很乱 class Mypanel extends JPanel{ //定义一个我的坦克 Hero hero=null; //在构造函数里给坦克意义初始位置 public Mypanel(){ hero=new Hero(10,10); } //重写paint函数 public void paint(Graphics g){ //一定要调用 super.paint(g); //设置背景颜色 g.fillRect(0, 0, 600, 500); //调用绘画坦克 this.drawTank(hero.getX(), hero.getY(), g, 0, 1); } //画出坦克的函数 public void drawTank(int x,int y,Graphics g,int direct,int type){ //坦克类型 switch(type){ case 0: g.setColor(Color.green); break; case 1: g.setColor(Color.yellow); break; } //判断方向 switch(direct){ //向上 case 0: //画出坦克函数(已封装) //画出左边的矩形 g.fill3DRect(x,y, 5, 30,false); g.fill3DRect(x+15, y, 5,30,false); //画出中间矩形 g.fill3DRect(x+5, y+5, 10, 20,false); //画出圆形 g.fillOval(x+5, y+10, 10, 10); //画出线 g.drawLine(x+10,y+15, x+10, y); break; } } } // 坦克类(自己和敌人的坦克的父类) class Tank { // x表示坦克的横坐标,y代表坦克的纵坐标 int x = 0; 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; } int y = 0; // 构造函数 public Tank(int x, int y) { this.x = x; this.y = y; } } // 我的坦克 class Hero extends Tank { // 因为坦克里面没有定义无参构造函数 // 会报错:Implicit super constructor Tank() is undefined for default // constructor. Must define an explicit constructor // 解决1.在Tank类里面定义无参构造函数。 // 2用父类的构造函数,来初始化子类的成员变量。如下: public Hero(int x, int y) { super(x, y); } } /* * public void paint(Graphics g){ *一定要调用 *super.paint(g); *g.fillRect(0, 0, 600, 500);q *画出坦克函数(未封装) *画出左边的矩形 *g.fill3DRect(hero.getX(),hero.getY(), 5, 30,false); *g.fill3DRect(hero.getX()+15, hero.getY(), 5,30,false); *画出中间矩形 *g.fill3DRect(hero.getX()+5, hero.getY()+5, 10, 20,false); *画出圆形 *g.fillOval(hero.getX()+5, hero.getY()+10, 10, 10); *画出线 *g.drawLine(hero.getX()+10,hero.getY()+15, hero.getX()+10, hero.getY()); *} */

    坦克大战(1.0.1版本)

    /*
     * 功能:坦克可移动
     * 学习:事件处理机制
    */
    package com.fanghua1;
    import java.awt.*;
    import java.awt.event.KeyEvent;
    
    import javax.swing.*;
    
    public class MyTankGame1_2 extends JFrame {
    
        Mypanel1_2 mp = null;
    
        public static void main(String[] args) {
            // TODO Auto-generated method stub
            new MyTankGame1_2();
        }
    
        // 构造函数
        public MyTankGame1_2() {
            mp = new Mypanel1_2();
            this.add(mp);
            // 注册监听
            this.addKeyListener(mp);
    
            this.setSize(600, 500);
            this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            this.setVisible(true);
    
        }
    }
    
    // 我的面板,不要在JFram上面画坦克,会很乱
    class Mypanel1_2 extends JPanel implements java.awt.event.KeyListener {
    
        // 定义一个我的坦克
        Hero1_2 hero = null;
    
        // 在构造函数里给坦克意义初始位置
        public Mypanel1_2() {
            hero = new Hero1_2(10, 10);
        }
    
        // 重写paint函数
        public void paint(Graphics g) {
            // 一定要调用
            super.paint(g);
            // 设置背景颜色
            g.fillRect(0, 0, 600, 500);
            // 调用绘画坦克
            this.drawTank(hero.getX(), hero.getY(), g, 0, 1);
    
        }
    
        // 画出坦克的函数
        public void drawTank(int x, int y, Graphics g, int direct, int type) {
            // 坦克类型
            switch (type) {
            case 0:
                g.setColor(Color.green);
                break;
            case 1:
                g.setColor(Color.yellow);
                break;
            }
            // 判断方向
            switch (direct) {
            // 向上
            case 0:
                // 画出坦克函数(已封装)
                // 画出左边的矩形
                g.fill3DRect(x, y, 5, 30, false);
                g.fill3DRect(x + 15, y, 5, 30, false);
                // 画出中间矩形
                g.fill3DRect(x + 5, y + 5, 10, 20, false);
                // 画出圆形
                g.fillOval(x + 5, y + 10, 10, 10);
                // 画出线
                g.drawLine(x + 10, y + 15, x + 10, y);
                break;
            }
    
        }
    
        @Override
        public void keyTyped(KeyEvent e) {
            // TODO Auto-generated method stub
    
        }
    
        @Override
        public void keyPressed(KeyEvent e) {
            // TODO Auto-generated method stub
            // e.getKeyCode() ==KeyEvent.VK_W 这句话我试了好久,都不能实现
            // 原因:我在测试的时候,输入法是搜狗输入法,应该切换到美式键盘或者英文状态下!!!!!
            if (e.getKeyCode() == KeyEvent.VK_UP || e.getKeyCode() == KeyEvent.VK_W) {
                // 这里有三处不好的地方:
                // 1.方向(比如this.hero.y--;)写死了,以后想改变移动速度,这里实现起来麻烦。更正(将“速度”在坦克类里封装成函数)
                // 2.重绘(this.repaint();)不用每个都写一遍,在for循环之外,一个就可以了
                // 3.方向设置最好按照顺时针或者逆时针,依次。我这个上下左右,容易乱
                this.hero.moveUp();// 之前版本:this.hero.y--;
                // this.repaint();
                // 设置我的坦克的方向
                this.hero.setDirect(0);
            } else if (e.getKeyCode() == KeyEvent.VK_DOWN
                    || e.getKeyCode() == KeyEvent.VK_S) {
                this.hero.moveDown();// 之前版本: this.hero.y++;
                // this.repaint();
                this.hero.setDirect(2);
            } else if (e.getKeyCode() == KeyEvent.VK_LEFT
                    || e.getKeyCode() == KeyEvent.VK_A) {
                this.hero.moveLeft();// 之前版本:this.hero.x--;
                // this.repaint();
                this.hero.setDirect(3);
            } else if (e.getKeyCode() == KeyEvent.VK_RIGHT
                    || e.getKeyCode() == KeyEvent.VK_D) {
                // this.repaint();
                this.hero.setDirect(1);
                this.hero.moveRight();// 之前版本:this.hero.x++;
            }
            this.repaint();
        }
    
        @Override
        public void keyReleased(KeyEvent e) {
            // TODO Auto-generated method stub
    
        }
    }
    
    // 坦克类 (自己和敌人坦克的父类)
    class Tank1_2 {
        // 坦克的坐标:x横坐标,y纵坐标
        int x = 0;
        int y = 0;
    
        // 坦克方向:0表示上,1表示右,2表示下,3表示左
        int direct = 0;
    
        // 坦克的速度(默认为1,如果将来想给自己和敌人的坦克设置速度,set一下就可以了)
        int speed = 1;
    
        public int getSpeed() {
            return speed;
        }
    
        public void setSpeed(int speed) {
            this.speed = speed;
        }
    
        public int getDirect() {
            return direct;
        }
    
        public void setDirect(int direct) {
            this.direct = direct;
        }
    
        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 Tank1_2(int x, int y) {
            this.x = x;
            this.y = y;
    
        }
    
    }
    
    // 我的坦克
    class Hero1_2 extends Tank1_2 {
        // 因为坦克里面没有定义无参构造函数
        // 会报错:Implicit super constructor Tank() is undefined for default
        // constructor. Must define an explicit constructor
        // 解决:
        // 1.在Tank类里面定义无参构造函数。
        // 2.用父类的构造函数,来初始化子类的成员变量。如下:
        public Hero1_2(int x, int y) {
            super(x, y);
        }
    
        // 坦克向上移动
        public void moveUp() {
            y -= speed;
        }
    
        // 坦克向右移动
        public void moveRight() {
            x += speed;
        }
    
        // 坦克向下移动
        public void moveDown() {
            y += speed;
        }
    
        // 坦克向左移动
        public void moveLeft() {
            x -= speed;
        }
    }

    接下来几天我会连续更新几篇博客,介绍该坦克大战的渐进完善过程,和中间需要初学者掌握的基础知识,有很多代码实例,也会渐进的增加坦克大战里面的元素和功能。

    PS:这个好久之前的了,现在看着有些想看小时候的日记,自我感觉很好玩。

  • 相关阅读:
    Java实现大批量数据导入导出(100W以上) -(三)超过25列Excel导出
    华为狼性文化与新员工引导
    盈利模式!商业保理 VS银行保理
    供应链金融保理业务最全解析-四大模式
    Spring Boot下Bean定义方式及调用方式
    Java非侵入式API接口即文档工具apigcc
    Java一个简单的重试工具包
    多层级汇总报表生成
    Spring事物隔离级别及事物传播行为@Transactional实现
    四种事物隔离级别详解
  • 原文地址:https://www.cnblogs.com/1693977889zz/p/8440075.html
Copyright © 2011-2022 走看看