任务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);
    }
}

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

任务实施

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

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个基于超声波能上下左右跟随目标并发射炮弹的简单结构代码,需要注意的是这仅仅是一个演示代码,具体实现需要根据具体情况进行修改和完善。 ```python import RPi.GPIO as GPIO import time GPIO.setmode(GPIO.BCM) GPIO.setwarnings(False) trig_pin = 23 echo_pin = 24 GPIO.setup(trig_pin, GPIO.OUT) GPIO.setup(echo_pin, GPIO.IN) motor_x_pin = 17 motor_y_pin = 18 GPIO.setup(motor_x_pin, GPIO.OUT) GPIO.setup(motor_y_pin, GPIO.OUT) pwm_x = GPIO.PWM(motor_x_pin, 50) pwm_y = GPIO.PWM(motor_y_pin, 50) pwm_x.start(0) pwm_y.start(0) servo_pin = 25 GPIO.setup(servo_pin, GPIO.OUT) pwm_servo = GPIO.PWM(servo_pin, 50) pwm_servo.start(0) def distance(): GPIO.output(trig_pin, True) time.sleep(0.00001) GPIO.output(trig_pin, False) while GPIO.input(echo_pin) == False: start_time = time.time() while GPIO.input(echo_pin) == True: end_time = time.time() duration = end_time - start_time distance = duration * 34300 / 2 return distance def move_x(angle): duty_cycle = angle / 18 + 2 pwm_x.ChangeDutyCycle(duty_cycle) def move_y(angle): duty_cycle = angle / 18 + 2 pwm_y.ChangeDutyCycle(duty_cycle) def move_servo(angle): duty_cycle = angle / 18 + 2 pwm_servo.ChangeDutyCycle(duty_cycle) while True: dist = distance() print("Distance: ", dist) if dist < 50: move_x(0) move_y(0) move_servo(90) time.sleep(0.5) move_servo(0) # 发射炮弹的代码 else: x_angle = (dist - 50) * 0.5 y_angle = (dist - 50) * 0.3 if x_angle > 90: x_angle = 90 elif x_angle < 0: x_angle = 0 if y_angle > 90: y_angle = 90 elif y_angle < 0: y_angle = 0 move_x(x_angle) move_y(y_angle) ``` 该代码使用树莓派控制了两个舵机分别控制炮塔的上下左右运动,使用超声波传感器来计算目标距离,当目标距离小于50cm时,炮塔会自动对准目标并发射炮弹

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值