云天 发表于 2024-8-31 16:25:04

行空板K10之GamePad弹球游戏

【项目背景】

[*]随着科技的发展,教育和娱乐领域越来越注重互动性和学习体验的结合。微型智能弹球游戏项目旨在通过 UNIHIKER_K10 硬件平台和 GamePad for micro:bit V4.0 手柄,为用户打造一个既具有教育意义又充满乐趣的互动游戏。这款游戏不仅能够锻炼玩家的反应速度和手眼协调能力,还能通过编程和硬件操作的结合,增加对 STEM(科学、技术、工程和数学)领域的兴趣和理解。
[*]UNIHIKER_K10 是一款集成了显示屏、多种传感器和可编程接口的微型计算机,非常适合用于教育和娱乐项目。它支持多种编程语言和库,使得开发者能够轻松地实现复杂的功能。GamePad for micro:bit V4.0 手柄则为游戏提供了直观的控制方式,通过物理操作增强了游戏的互动性。

【项目硬件】UNIHIKER_K10 和 GamePad for micro:bit V4.0 手柄,实现交互式游戏。









【程序设计】

#include "unihiker_k10.h"
Music      music;
// 创建对象
UNIHIKER_K10 k10;
uint8_t screen_dir = 2;
int speed=0;
// 定义屏幕宽度和高度
#define SCREEN_WIDTH 240
#define SCREEN_HEIGHT 320
uint8_t score = 0;
// 游戏对象定义
#define BALL_SIZE 20
struct GameObject {
    int x;
    int y;
    int width;
    int height;
    int dx;
    int dy;
} ball, paddle;

// 初始化游戏对象
void initGameObjects() {
    ball.x = SCREEN_WIDTH / 2;
    ball.y = SCREEN_HEIGHT / 2;
    ball.width = BALL_SIZE;
    ball.height = BALL_SIZE;
    ball.dx = 2;
    ball.dy = 2;

    paddle.x = SCREEN_WIDTH / 2 - 20;
    paddle.y = SCREEN_HEIGHT - 30;
    paddle.width = 80;
    paddle.height = 20;
    paddle.dx = 0;
}

// 绘制游戏对象
void drawGameObjects() {
    //k10.canvas->canvasClear();
    k10.canvas->canvasCircle(ball.x, ball.y, BALL_SIZE, 0x000000, 0xFF0000, true);
    k10.canvas->canvasRectangle(paddle.x, paddle.y, paddle.width, paddle.height, 0x000000, 0x00FF00, true);
    k10.canvas->updateCanvas();
}
// LED 灯显示分数
void LEDshow(){
switch (score) {
    case 0:
      k10.rgb->write(-1,0x000000);
      break;
    case 1:
      k10.rgb->write(-1, 0x000000);
      k10.rgb->write( 2, 0x0000FF);
      
      break;
    case 2:
      k10.rgb->write(-1, 0x000000);
      k10.rgb->write( 1, 0x0000FF);
      break;
    case 3:
      k10.rgb->write(-1, 0x000000);
      k10.rgb->write( 1, 0x0000FF);
      k10.rgb->write( 2, 0x0000FF);
      break;
    case 4:
      k10.rgb->write(-1, 0x000000);
      k10.rgb->write( 0, 0x0000FF);
      break;
    case 5:
      k10.rgb->write(-1, 0x000000);
      k10.rgb->write( 0, 0x0000FF);
      k10.rgb->write( 2, 0x0000FF);
      break;
    case 6:
      k10.rgb->write(-1, 0x000000);
      k10.rgb->write( 0, 0x0000FF);
      k10.rgb->write( 1, 0x0000FF);
      break;
    case 7:
      k10.rgb->write( 0, 0x0000FF);
      k10.rgb->write( 1, 0x0000FF);
      k10.rgb->write( 2, 0x0000FF);
      break;
    // 可以继续添加case 5, 6, 7...
    default:
      k10.rgb->setRangeColor(0, 2, 0x000000); // 默认所有灯灭
}
}
// 更新游戏逻辑
void updateGame() {
    // 更新球的位置
    ball.x += ball.dx;
    ball.y += ball.dy;

    // 检测球是否碰到左右边界
    if (ball.x <= BALL_SIZE/2 || ball.x >= SCREEN_WIDTH - BALL_SIZE/2) {
      ball.dx = -ball.dx;
    }
    // 检测球是否碰到顶部边界
    if (ball.y <= BALL_SIZE/2) {
      ball.dy = -ball.dy;
    }
    // 检测球是否碰到挡板
    if (ball.x >= paddle.x && ball.x <= paddle.x + paddle.width &&
      ball.y +ball.height/2>= paddle.y&& ball.y <= paddle.y + paddle.height) {
      ball.dy = -ball.dy;
      score++;
      LEDshow();
      //music.playTone(262, 1000);
    }
    // 检测球是否掉出底部
    if (ball.y > SCREEN_HEIGHT - BALL_SIZE) {
      // 重置球的位置
      ball.x = SCREEN_WIDTH / 2;
      ball.y = SCREEN_HEIGHT / 2;
      k10.canvas->canvasClear();
            k10.canvas->updateCanvas();
    }

    // 绘制更新后的游戏对象
    drawGameObjects();
}

// 处理用户输入
void handleInput() {
    if (analogRead(P1) < 1000) {
      paddle.x -= 5;
    } else if (analogRead(P1) > 3000) {
      paddle.x += 5;
    } else if((k10.buttonA->isPressed())){
      speed=speed+100;
    } else if((k10.buttonB->isPressed())){
      speed=speed-100;
      if(speed<0){
      speed=0;
      }
    }

    // 确保挡板不会超出屏幕
    if (paddle.x < 0) {
      paddle.x = 0;
    } else if (paddle.x > SCREEN_WIDTH - paddle.width) {
      paddle.x = SCREEN_WIDTH - paddle.width;
    }
}

void setup() {
    k10.begin();
    k10.initScreen(screen_dir);
    k10.creatCanvas();
    k10.setScreenBackground(0x000000);
    Serial.begin(9600);
    initGameObjects();
    drawGameObjects();
}

void loop() {
    handleInput();
    updateGame();
    delay(speed); // 控制游戏速度
}
【程序解析】
[*]包含头文件

[*]#include "unihiker_k10.h":包含用于控制 UNIHIKER_K10 硬件平台的库。
[*]声明全局变量和对象

[*]Music music;:声明一个音乐对象。
[*]UNIHIKER_K10 k10;:声明一个 UNIHIKER_K10 类型的对象,用于与硬件进行交互。
[*]uint8_t screen_dir = 2;:定义屏幕方向变量,并初始化为 2。
[*]int speed = 0;:定义一个速度变量,用于控制游戏循环的速度。
[*]定义屏幕尺寸

[*]#define SCREEN_WIDTH 240 和 #define SCREEN_HEIGHT 320:定义屏幕的宽度和高度。
[*]定义分数和游戏对象结构

[*]uint8_t score = 0;:定义一个变量来存储玩家的分数。
[*]struct GameObject { ... } ball, paddle;:定义一个结构体来存储游戏对象(球和挡板)的属性,包括位置、尺寸和移动速度。
[*]初始化游戏对象

[*]void initGameObjects() {...}:初始化球和挡板的位置、尺寸和移动速度。
[*]绘制游戏对象

[*]void drawGameObjects() {...}:在屏幕上绘制球和挡板的当前位置。
[*]LED 显示分数

[*]void LEDshow() {...}:根据当前分数,通过 LED 灯显示分数。
[*]更新游戏逻辑

[*]void updateGame() {...}:更新球的位置,检测碰撞,更新分数,并重新绘制游戏对象。
[*]处理用户输入

[*]void handleInput() {...}:处理来自手柄的输入,调整挡板的位置和游戏速度。
[*]设置初始化函数

[*]void setup() {...}:在程序开始时调用,用于初始化硬件设置和游戏对象。
[*]主循环函数

[*]void loop() {...}:程序的主循环,不断调用 handleInput() 和 updateGame() 函数,以及控制循环速度的 delay(speed)。
[*]游戏逻辑细节

[*]球的移动和边界检测:在 updateGame() 函数中,球的位置会根据其速度更新,并且会检测是否与屏幕的边界发生碰撞,如果是,则反转相应的移动方向。
[*]挡板的控制:在 handleInput() 函数中,通过读取手柄的模拟输入来控制挡板的水平移动,并确保挡板不会移出屏幕范围。
[*]得分和LED显示:当球与挡板碰撞时,分数增加,并通过 LEDshow() 函数更新 LED 灯的二进制显示。
[*]程序执行流程

[*]程序首先在 setup() 函数中进行初始化。
[*]然后进入 loop() 函数,不断循环执行用户输入处理和游戏逻辑更新。
[*]游戏状态的每次更新都会在屏幕上重新绘制游戏对象,并根据需要更新 LED 灯的显示。

【演示视频】
https://www.bilibili.com/video/BV1zEnZeBE7R/?share_source=copy_web

页: [1]
查看完整版本: 行空板K10之GamePad弹球游戏