当前位置: 代码迷 >> 综合 >> JavaGUI 19 动态小蛇(Timer)
  详细解决方案

JavaGUI 19 动态小蛇(Timer)

热度:102   发布时间:2023-11-24 13:52:29.0

8.3 动态小蛇


8.3.1 监听空格(开始游戏)

这次我们采取 将键盘事件 被 我们 GamePanel 实现的方式,就不 创建个 新的 事件类了。

package com.muquanyu.snake;import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;public class GamePanel extends JPanel implements KeyListener {
    //蛇的长度int length;//蛇头的 X坐标 和 Y坐标int[] snakeX = new int[900];int[] snakeY = new int[900];//蛇头方向String snakeDirection = null;//游戏当前的状态:开始、停止 默认为 "停止"boolean isStart = false;//初始化public void init() {
    //初始化蛇的长度length = 3;//初始化蛇头 坐标snakeX[0] = 125;snakeY[0] = 100;//初始化蛇身 坐标snakeX[1] = 100;snakeY[1] = 100;snakeX[2] = 75;snakeY[2] = 100;//蛇头方向snakeDirection = "right";}//绘制面板,我们游戏中的所有东西,都是用画笔来 画@Overridepublic void paintComponent(Graphics g) {
    //清屏,不会出现闪烁。super.paintComponent(g);//绘制静态的面板this.setBackground(Color.BLACK);//第一个参数是画到哪个设备上,那肯定是我们 创建的 面板上呀!Data.header.paintIcon(this, g, 25, 11);//画游戏区域g.fillRect(25, 75, 850, 600);//画静态小蛇switch(snakeDirection){
    case "right":Data.right.paintIcon(this, g, snakeX[0], snakeY[0]);break;case "left":Data.left.paintIcon(this, g, snakeX[0], snakeY[0]);break;case "up":Data.up.paintIcon(this, g, snakeX[0], snakeY[0]);break;case "down":Data.down.paintIcon(this, g, snakeX[0], snakeY[0]);break;default:break;}for(int i = 1;i<length;++i){
    Data.body.paintIcon(this, g, snakeX[i], snakeY[i]);}//游戏状态if(!isStart){
    g.setColor(Color.white);//设置字体Font 微软雅黑 = new Font("微软雅黑", Font.BOLD, 40);g.setFont(微软雅黑);g.drawString("按下空格开始游戏",300,300);}}public GamePanel() {
    init();//获得焦点和键盘事件this.setFocusable(true);//获得焦点事件this.addKeyListener(this);//获得键盘监听事件}//键盘监听事件@Overridepublic void keyTyped(KeyEvent e) {
    }@Overridepublic void keyPressed(KeyEvent e) {
    int keyCode = e.getKeyCode();if(keyCode == KeyEvent.VK_SPACE){
    System.out.println("按下了空格!");isStart = !isStart;repaint();//开始重画}}@Overridepublic void keyReleased(KeyEvent e) {
    }
}

我们知道,只要我们 把 isStart 设定为 true,在绘画 的时候,它就不会 去 绘画 提示的文字。那么 我们 通过 监听 空格键,把 isStart 取反,再进行 重画,更新所有的画面!不就实现了 游戏开始 和 停止的操作吗?

这里如果 懂的话,其实 让小蛇 动起来的操作,理解起来就不是很难了。无非就是 更新 小蛇的数据然后用 Timer 一直进行重画!!!


8.3.2 Timer 定时器(时钟)

使用定时器之前,就必须 先 继承或作为 Actionlistener 的实现。这是 为 了 Timer 做前奏准备。因为 我们 需要 用 Actionlistener 做最基本的监听事件!

  • 创建 Timer 对象(定时器)
//创建一个时钟 进行 监听Timer timer = new Timer(33,监听事件);

它是以毫秒为单位,进行监听的!1000ms = 1s。

所以要想模仿出 30 帧,那就得 33 ms 监听一次!

需要注意的是,Timer 开启后,默认 会去 监听 你一开始创建的时候,设定的那个 监听事件!这个监听事件可以是 很多组件的监听事件。


8.3.2.1 自动识别内容是否正确(不需要 按 回车键)

package com.muquanyu.snake;import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;public class TimerDemo extends JFrame {
    MyAction m = new MyAction();Timer t = new Timer(300,m);JTextField jTextField;public TimerDemo(){
    setBounds(200,200,500,500);setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);jTextField = new JTextField("请输入密钥,我们会一直判定!");jTextField.addActionListener(m);add(jTextField);t.start();setVisible(true);}public static void main(String[] args) {
    new TimerDemo();}class MyAction implements ActionListener {
    @Overridepublic void actionPerformed(ActionEvent e) {
    if(jTextField.getText().equals("helloworld")){
    System.out.println("输入密钥正确!");t.stop();}else{
    System.out.println("输入密钥错误!");}}}
}

在这里插入图片描述

这个 案例,是为了让你明不白,Timer 对象 一旦被创造 出来,就可以 捆绑 一个 事件。然后 一旦开启,就会一直 执行那个 事件的监听。

如果是这样的话,我们是否可以 把 GamePanel 的 action 事件 绑定 在 上面呢?? 完全是可以的!

这样就能在 Action 事件里,进行 数据的刷新和重画了。


8.3.2.2 实现动态小蛇

@Overridepublic void actionPerformed(ActionEvent e) {
    //如果游戏开始的话if(isStart){
    //宽度:850 高度:600//右移//头移动switch(snakeDirection){
    case "right":{
    if(snakeX[0] == 850){
    //那就直接让它 从左边 穿过来就行了snakeX[0] = 25;}else{
    //编程思想的写法,并不是什么高深算法!//我们通过自己画图,也会发现这个 现象//就是 蛇身的每一块 在移动的时候,恰好移动到了 前一个块的坐标!!!//你们 自己画图 观察,就能看出来!那么我们只需要 从 最后一块 开始遍历//然后 让它每次刷新 都 变成 前一块的 坐标不就完事了!!for(int i = length-1;i>0;i--){
    snakeX[i] = snakeX[i-1];snakeY[i] = snakeY[i-1];}snakeX[0] = snakeX[0] + 25;}repaint();break;}case "left":{
    if(snakeX[0] == 25){
    snakeX[0] = 850;}else{
    for(int i = length-1;i>0;i--){
    snakeX[i] = snakeX[i-1];snakeY[i] = snakeY[i-1];}snakeX[0] = snakeX[0] - 25;}repaint();break;}case "up":{
    if(snakeY[0] == 75){
    snakeY[0] = 600;}else{
    for(int i = length-1;i>0;i--){
    snakeX[i] = snakeX[i-1];snakeY[i] = snakeY[i-1];}snakeY[0] = snakeY[0] - 25;}repaint();break;}case "down":{
    if(snakeY[0] == 650){
    snakeY[0] = 75;}else{
    for(int i = length-1;i>0;i--){
    snakeX[i] = snakeX[i-1];snakeY[i] = snakeY[i-1];}snakeY[0] = snakeY[0] + 25;}repaint();break;}default:break;}

编程思想的写法,并不是什么高深算法!
我们通过自己画图,也会发现这个 现象
就是 蛇身的每一块 在移动的时候,恰好移动到了 前一个块的坐标!!!你们 自己画图 观察,就能看出来!那么我们只需要 从 最后一块 开始遍历
然后 让它每次刷新 都 变成 前一块的 坐标不就完事了!!

在每次 进行刷新判定的时候,都要 重画哟!

在这里插入图片描述

8.3.3 实现方向控制

  • 实现方向控制
 @Overridepublic void keyPressed(KeyEvent e) {
    int keyCode = e.getKeyCode();if(keyCode == KeyEvent.VK_SPACE){
    System.out.println("按下了空格!");isStart = !isStart;repaint();//开始重画}if(keyCode == KeyEvent.VK_UP){
    System.out.println("上方向键!");snakeDirection = "up";}if(keyCode == KeyEvent.VK_DOWN){
    System.out.println("下方向键!");snakeDirection = "down";}if(keyCode == KeyEvent.VK_LEFT){
    System.out.println("左方向键!");snakeDirection = "left";}if(keyCode == KeyEvent.VK_RIGHT){
    System.out.println("右方向键!");snakeDirection = "right";}}

直接改变 snakeDirection 的值,就完事了,因为你改变了这个值,我们的 action 事件在 更新数据的时候 就会 不一样。

  相关解决方案