任务10 发射炮弹

当用户按下空格键时,通过游戏面板中实现的键盘监听器接口(KeyListener),在坦克的位置创建一颗炮弹对象,并通过Runable接口,不断更新炮弹的坐标,并刷屏绘制炮弹。


任务10 发射炮弹_第1张图片
图10-1 发射炮弹


支撑知识

10.1动画

计算机动画是采用连续播放静止图像的方法产生物体运动的效果。比如一颗移动的炮弹,先在初始位置绘制,然后当炮弹移动到下一个位置时,把原先的炮弹擦除,再把改变位置后的炮弹绘制出来。只要时间足够快,就能产生动画效果。案例11-1演示了炮弹移动的效果:
案例11-1:【Case11-1/src/GamePanel.java】


public class GamePanel extends JPanel{
    //定义小球位置
    int x = 10;
    int y = 100;    
    @Override
    public void paint(Graphics g) {
        super.paint(g);
        //通过for循环,炮弹移动50步
        for (int i = 0; i < 50; i++) {
        //擦除屏幕
            g.clearRect(0, 0, 300, 300);
            //绘制炮弹
            g.fillOval(x + i * 3, y, 10, 10);
        }
    }
}

案例11-1:【Case11-1/src/Test.java】


public class Test {
    public static void main(String[] args) {
        JFrame frame = new JFrame("移动炮弹");      
        GamePanel gamePanel = new GamePanel();
        frame.add(gamePanel);       
        frame.setSize(300, 300);
        frame.setVisible(true);
    }
}

运行Test类,发现炮弹直接跑到最右侧去了,我们并没有看到动画效果。这是应为计算机执行的动作太快了,我们可以使用线程Thread提供的sleep方法,每次重绘炮弹的时候让下面的循环代码等待一会,再重画。在绘制炮弹后面添加Thread.sleep方法:
案例11-1:【Case11-1/src/GamePanel.java】


public class GamePanel extends JPanel{
    ……
    public void paint(Graphics g) {
        ……
        for (int i = 0; i < 100; i++) {
            g.clearRect(0, 0, 300, 300);
            g.fillOval(x + i * 3, y, 10, 10);
            try {
                 //休眠30毫秒后再执行后面的代码
                Thread.sleep(30);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
         System.out.println("循环结束");
    }
}

运行代码,发现炮弹在运行结束前,我们不能在游戏面板中做任何事情,程序完全被循环语句占用了,当执行完for循环后,打印语句才被执行。由于计算机只有一个CPU,因此,不可能同时执行两段代码,不同的代码只能等上一段执行完后才有机会被执行。
在使用计算机过程中,我们经常一边听音乐,一边聊天,一边写文档,并没有感觉有什么停顿,这是使用了操作系统中的线程技术实现的,下面介绍什么是线程。

10.2线程

Java中使用线程实现动画效果,什么是线程呢?通俗点说就是线程技术通过CPU轮换,让程序(代码段)轮流执行的机制。由于轮流的时间切换太快,以至于用户察觉不到,以为几个程序(代码段)同时执行。
Java线程实现方式比较常用的有两种:继承Thread类和实现Runnable接口。
(1)继承Thread实现线程
创建完线程后需要使用start()方法启动一个新的线程,并执行run()方法。这种方式实现线程很简单,通过自己的类直接extend Thread,并重写run()方法,就可以启动新线程并执行自己定义的run()方法。
case10-2:【Case10-2/src/MyThread1.java】


public class MyThread1 extends Thread{
    @Override
    public void run() {
        super.run();
        while(true){
            System.out.println("线程1");
        }
    }
}

case10-2:【Case10-2/src/MyThread2.java】


public class MyThread2 extends Thread{
    @Override
    public void run() {
        super.run();
        while(true){
            System.out.println("线程2");
        }
    }
}

运行程序,将在控制台不断地随机打印出两条语句,表示通过start启动的两个线程不断地获得CPU执行权限。
(2)实现Runnable接口实现线程
由于Java语言单继承特性,如果编写的类已经extends另一个类,就无法直接extends Thread,此时,必须实现一个Runnable接口。修改案例10-1,让GamePanel实现线程接口,将变化的坐标代码放入run中。
case10-1:【Case10-1/src/GamePanel.java】


public class GamePanel extends JPanel implements Runnable{
    //定义小球位置
    int x = 100;
    int y = 100;    
    @Override
    public void paint(Graphics g) {
        super.paint(g);
        //绘制炮弹
        g.fillOval(x, y, 10, 10);
    }   
    @Override
    public void run() {
            while(true){
            y--;//不断改变炮弹坐标
            repaint();//刷新面板,重新回执(调用paint)
            try {
                    Thread.sleep(30); //休眠30毫秒后再执行后面的代码
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

case10-1:【Case10-1/src/Test.java】


public class Test {
    public static void main(String[] args) {
        JFrame frame = new JFrame("移动炮弹");
        GamePanel gamePanel = new GamePanel();
        //将实现Runnable接口的类转换为Thread对象,并启动线程
        new Thread(gamePanel).start();
        frame.add(gamePanel);       
        frame.setSize(300, 300);
        frame.setVisible(true);
    }
}

运行程序,炮弹不断向上移动。

任务实施

任务实施讲解如何通过空格键发射炮弹(待续)

你可能感兴趣的:(Java入门,对象,动画)