news 2026/9/5 14:44:47

Python Pygame实战:事件驱动与状态机构建趣味交互应用

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Python Pygame实战:事件驱动与状态机构建趣味交互应用

在实际游戏开发或创意编程项目中,我们常常会遇到需要将多个看似不相关的元素——比如“龙岛异兽”这样的奇幻设定与“奶茶摇一摇”这样的趣味交互——融合成一个可运行的、有逻辑的趣味程序。这不仅是创意的体现,更是对开发者模块化设计、事件驱动编程和状态管理能力的一次综合考验。本文将以“龙岛异兽,来杯奶茶摇一摇”为创意原型,带你从零开始,使用 Python 和 Pygame 库,构建一个集角色展示、随机事件与趣味交互于一体的小型桌面应用。

本文适合有一定 Python 基础,希望了解如何将创意转化为具体代码实现,并学习游戏化交互逻辑的开发者。你将跟随教程完成一个包含异兽展示、随机奶茶生成、摇一摇动画及结果反馈的完整流程。最终,你将掌握如何设计游戏对象、处理用户输入、管理应用状态以及实现简单的动画效果。

1. 理解项目核心:事件驱动与状态管理

在开始编码之前,我们需要厘清这个项目的核心逻辑。它不是一个复杂的 RPG 游戏,而是一个基于事件和状态的交互式演示程序。整个应用可以抽象为几个关键部分:

  • 数据层:定义“龙岛异兽”和“奶茶”的数据结构。例如,异兽可能有名称、形象(图片路径)、简介;奶茶可能有口味、配料、描述等属性。
  • 状态层:管理应用当前处于哪个阶段。典型的状态包括:IDLE(待机,展示异兽)、SHAKING(摇动动画中)、RESULT(显示摇出的奶茶结果)。
  • 视图层:负责将数据和状态渲染到屏幕上。包括绘制背景、异兽图片、文字提示、奶茶结果动画等。
  • 控制层:处理用户输入(如鼠标点击、按键),触发状态转换。例如,点击“摇一摇”按钮,状态从IDLE切换到SHAKING,经过一段动画时间后,再切换到RESULT

这种“数据-状态-视图-控制”的分离设计,使得代码结构清晰,易于维护和扩展。例如,未来想增加新的异兽或奶茶口味,只需修改数据层,视图和控制层可以基本不变。

2. 环境准备与项目初始化

我们将使用 Python 的 Pygame 库来实现图形界面和交互。Pygame 简单易用,非常适合制作这类2D小型桌面应用。

2.1 安装 Python 与 Pygame

首先,确保你的系统已安装 Python(建议使用 Python 3.7 及以上版本)。你可以通过命令行检查:

python --version # 或 python3 --version

接下来,使用 pip 安装 Pygame。建议在虚拟环境中进行:

# 创建虚拟环境(可选但推荐) python -m venv venv # 激活虚拟环境 # Windows: venv\Scripts\activate # macOS/Linux: source venv/bin/activate # 安装 Pygame pip install pygame

2.2 创建项目结构

创建一个新的项目文件夹,例如dragon_island_tea,并在其中组织你的文件:

dragon_island_tea/ ├── main.py # 程序主入口 ├── config.py # 配置参数(屏幕大小、颜色、字体等) ├── game_state.py # 状态枚举和状态机逻辑 ├── assets/ # 资源文件夹 │ ├── images/ # 存放图片 │ │ ├── beast_1.png │ │ ├── beast_2.png │ │ └── tea_icon.png │ └── fonts/ # 存放字体文件(可选) │ └── simhei.ttf ├── data/ # 数据定义 │ ├── beasts.py # 异兽数据 │ └── teas.py # 奶茶数据 └── utils.py # 工具函数(如加载图片、文本渲染)

这种结构将逻辑、数据、资源和配置分离,是保持项目整洁的好习惯。

2.3 基础配置 (config.py)

config.py中定义全局常量,便于统一修改。

# config.py import pygame import os # 屏幕尺寸 SCREEN_WIDTH = 800 SCREEN_HEIGHT = 600 # 颜色定义 (R, G, B) WHITE = (255, 255, 255) BLACK = (0, 0, 0) GREEN = (100, 200, 100) BROWN = (139, 69, 19) LIGHT_BLUE = (173, 216, 230) # 资源路径 ASSET_DIR = os.path.join(os.path.dirname(__file__), ‘assets‘) IMAGE_DIR = os.path.join(ASSET_DIR, ‘images‘) FONT_DIR = os.path.join(ASSET_DIR, ‘fonts‘) # 字体 FONT_PATH = os.path.join(FONT_DIR, ‘simhei.ttf‘) # 确保你有这个字体文件,或使用系统字体 FONT_SIZE_TITLE = 48 FONT_SIZE_NORMAL = 28 FONT_SIZE_SMALL = 20 # 游戏参数 SHAKING_DURATION = 2000 # 摇一摇动画持续时间(毫秒)

3. 定义核心数据与游戏状态

3.1 定义异兽与奶茶数据 (data/beasts.py,data/teas.py)

数据层使用简单的类或字典列表来定义。

# data/beasts.py class Beast: def __init__(self, id, name, image_file, description): self.id = id self.name = name self.image_file = image_file # 图片文件名,如 ‘beast_1.png‘ self.description = description # 示例数据 BEASTS = [ Beast(1, “烈焰龙“, “beast_1.png“, “栖息于龙岛火山口,鳞片如熔岩,性情暴躁但尊重强者。“), Beast(2, “翡翠翼蛇“, “beast_2.png“, “龙岛森林的守护者,身披翡翠般鳞片,飞行无声,智慧超群。“), # 可以继续添加更多异兽 ]
# data/teas.py class Tea: def __init__(self, id, name, base, toppings, description): self.id = id self.name = name # 如 “龙息茉香奶绿“ self.base = base # 茶底,如 “茉莉绿茶“ self.toppings = toppings # 配料列表,如 [“珍珠“, “椰果“] self.description = description # 示例数据 TEAS = [ Tea(1, “龙息茉香奶绿“, “茉莉绿茶“, [“珍珠“, “椰果“], “清新茉香中带着一丝神秘气息,仿佛龙族低语。“), Tea(2, “熔岩黑糖波霸“, “阿萨姆红茶“, [“黑糖波霸“, “布丁“], “炙热黑糖与醇厚红茶碰撞,如熔岩般热烈。“), Tea(3, “翡翠柠檬多多“, “四季春茶“, [“柠檬片“, “寒天“], “酸甜清爽,宛如翡翠翼蛇掠过林间的微风。“), Tea(4, “幽兰芝士乌龙“, “乌龙茶“, [“芝士奶盖“, “奥利奥碎“], “咸香芝士与幽兰乌龙交融,沉稳而深邃。“), ]

3.2 管理游戏状态 (game_state.py)

我们使用一个简单的状态机来管理应用流程。

# game_state.py import pygame import time from enum import Enum class GameState(Enum): """游戏状态枚举""" IDLE = 1 # 空闲,展示异兽 SHAKING = 2 # 摇动动画中 RESULT = 3 # 显示摇出的奶茶结果 class StateManager: def __init__(self): self.current_state = GameState.IDLE self.current_beast_index = 0 # 当前展示的异兽索引 self.current_tea = None # 当前摇出的奶茶 self.shaking_start_time = 0 # 开始摇动的时间戳 def change_state(self, new_state): """切换状态,并处理状态进入时的逻辑""" old_state = self.current_state self.current_state = new_state if new_state == GameState.SHAKING: # 进入摇动状态时,记录开始时间,并随机选择一杯奶茶 self.shaking_start_time = time.time() * 1000 # 转换为毫秒 self._select_random_tea() print(f“状态切换: {old_state} -> {new_state}, 选中奶茶: {self.current_tea.name}“) elif new_state == GameState.RESULT: print(f“状态切换: {old_state} -> {new_state}, 展示结果“) elif new_state == GameState.IDLE: print(f“状态切换: {old_state} -> {new_state}“) def _select_random_tea(self): """从奶茶列表中随机选择一杯""" import random from data.teas import TEAS self.current_tea = random.choice(TEAS) def update(self): """每帧更新,主要用于处理状态超时等逻辑""" current_time = time.time() * 1000 if self.current_state == GameState.SHAKING: # 如果摇动时间超过设定时长,自动切换到结果状态 if current_time - self.shaking_start_time > SHAKING_DURATION: self.change_state(GameState.RESULT) def get_current_beast(self): """获取当前展示的异兽对象""" from data.beasts import BEASTS if 0 <= self.current_beast_index < len(BEASTS): return BEASTS[self.current_beast_index] return None def next_beast(self): """切换到下一只异兽(循环)""" from data.beasts import BEASTS self.current_beast_index = (self.current_beast_index + 1) % len(BEASTS)

4. 构建主程序与视图渲染

4.1 工具函数 (utils.py)

创建一些辅助函数来加载资源和渲染文本。

# utils.py import pygame import os from config import IMAGE_DIR, FONT_PATH, FONT_SIZE_NORMAL, FONT_SIZE_TITLE, FONT_SIZE_SMALL _image_cache = {} _font_cache = {} def load_image(filename, scale=None): """加载图片并缓存,支持缩放""" path = os.path.join(IMAGE_DIR, filename) if path not in _image_cache: try: image = pygame.image.load(path).convert_alpha() _image_cache[path] = image except pygame.error as e: print(f“无法加载图片 {path}: {e}“) # 返回一个替代的Surface _image_cache[path] = pygame.Surface((100, 100)) _image_cache[path].fill((255, 0, 255)) # 品红色,用于提示缺失 image = _image_cache[path] if scale: return pygame.transform.scale(image, scale) return image def get_font(size): """获取字体对象并缓存""" key = (FONT_PATH, size) if key not in _font_cache: try: font = pygame.font.Font(FONT_PATH, size) except: # 如果指定字体文件不存在,使用系统默认字体 font = pygame.font.SysFont(‘simhei‘, size) # 或 ‘arial‘ _font_cache[key] = font return _font_cache[key] def draw_text(surface, text, position, font_size=FONT_SIZE_NORMAL, color=BLACK, center=False): """在Surface上绘制文本""" font = get_font(font_size) text_surface = font.render(text, True, color) text_rect = text_surface.get_rect() if center: text_rect.center = position else: text_rect.topleft = position surface.blit(text_surface, text_rect) return text_rect

4.2 主程序逻辑 (main.py)

这是程序的核心,负责初始化、事件循环、状态更新和画面绘制。

# main.py import pygame import sys from config import * from game_state import GameState, StateManager from utils import load_image, draw_text from data.beasts import BEASTS def main(): # 初始化 Pygame pygame.init() screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT)) pygame.display.set_caption(“龙岛异兽 - 奶茶摇一摇“) clock = pygame.time.Clock() # 初始化状态管理器 state_manager = StateManager() # 加载资源 # 注意:确保 assets/images/ 下有对应的图片文件 beast_bg = load_image(“beast_bg.jpg“, (SCREEN_WIDTH, SCREEN_HEIGHT)) # 背景图 button_img = load_image(“button_shake.png“, (200, 60)) # 摇一摇按钮 tea_cup_img = load_image(“tea_cup.png“, (150, 200)) # 奶茶杯图片 # 按钮矩形区域(用于碰撞检测) button_rect = button_img.get_rect(center=(SCREEN_WIDTH // 2, 500)) # 主循环 running = True while running: # 处理事件 for event in pygame.event.get(): if event.type == pygame.QUIT: running = False elif event.type == pygame.KEYDOWN: if event.key == pygame.K_ESCAPE: running = False elif event.key == pygame.K_SPACE and state_manager.current_state == GameState.IDLE: # 空格键触发摇一摇 state_manager.change_state(GameState.SHAKING) elif event.key == pygame.K_RIGHT: # 右键切换异兽 state_manager.next_beast() elif event.type == pygame.MOUSEBUTTONDOWN: if event.button == 1: # 左键点击 mouse_pos = pygame.mouse.get_pos() if button_rect.collidepoint(mouse_pos) and state_manager.current_state == GameState.IDLE: # 点击“摇一摇”按钮 state_manager.change_state(GameState.SHAKING) elif state_manager.current_state == GameState.RESULT: # 在结果状态点击任意位置返回空闲状态 state_manager.change_state(GameState.IDLE) # 更新状态(例如检查摇动是否结束) state_manager.update() # 绘制背景 screen.blit(beast_bg, (0, 0)) # 根据当前状态绘制不同内容 current_state = state_manager.current_state if current_state == GameState.IDLE: # 绘制当前异兽信息 beast = state_manager.get_current_beast() if beast: beast_image = load_image(beast.image_file, (300, 300)) img_rect = beast_image.get_rect(center=(SCREEN_WIDTH // 2, 250)) screen.blit(beast_image, img_rect) # 绘制异兽名称和描述 draw_text(screen, beast.name, (SCREEN_WIDTH // 2, 400), font_size=FONT_SIZE_TITLE, color=WHITE, center=True) # 描述文字可能需要换行,这里简化处理 draw_text(screen, beast.description, (50, 450), font_size=FONT_SIZE_SMALL, color=LIGHT_BLUE) # 绘制“摇一摇”按钮 screen.blit(button_img, button_rect) draw_text(screen, “来杯奶茶摇一摇 (或按空格键)“, (SCREEN_WIDTH // 2, 530), font_size=FONT_SIZE_SMALL, color=BLACK, center=True) # 提示文字 draw_text(screen, “点击按钮或按空格键为异兽摇一杯奶茶!“, (SCREEN_WIDTH // 2, 570), font_size=FONT_SIZE_SMALL, color=WHITE, center=True) draw_text(screen, “按 → 键切换异兽“, (SCREEN_WIDTH // 2, 590), font_size=FONT_SIZE_SMALL, color=WHITE, center=True) elif current_state == GameState.SHAKING: # 摇动动画:可以绘制动态的奶茶杯和文字 elapsed = pygame.time.get_ticks() - state_manager.shaking_start_time # 简单的左右晃动效果 offset_x = int(20 * (elapsed % 200) / 100) # 在0-20像素之间来回 if (elapsed // 100) % 2 == 0: offset_x = -offset_x cup_pos = (SCREEN_WIDTH // 2 - 75 + offset_x, 200) screen.blit(tea_cup_img, cup_pos) # 绘制摇动提示文字 draw_text(screen, “摇晃中...“, (SCREEN_WIDTH // 2, 420), font_size=FONT_SIZE_TITLE, color=WHITE, center=True) draw_text(screen, f“正在为 {state_manager.get_current_beast().name} 调配特饮“, (SCREEN_WIDTH // 2, 470), font_size=FONT_SIZE_NORMAL, color=LIGHT_BLUE, center=True) elif current_state == GameState.RESULT: # 绘制摇出的奶茶结果 tea = state_manager.current_tea if tea: screen.blit(tea_cup_img, (SCREEN_WIDTH // 2 - 75, 150)) draw_text(screen, “调配完成!“, (SCREEN_WIDTH // 2, 380), font_size=FONT_SIZE_TITLE, color=GREEN, center=True) draw_text(screen, f“{tea.name}“, (SCREEN_WIDTH // 2, 430), font_size=FONT_SIZE_TITLE, color=BROWN, center=True) draw_text(screen, f“茶底: {tea.base}“, (SCREEN_WIDTH // 2, 480), font_size=FONT_SIZE_NORMAL, color=BLACK, center=True) draw_text(screen, f“配料: {‘, ‘.join(tea.toppings)}“, (SCREEN_WIDTH // 2, 510), font_size=FONT_SIZE_NORMAL, color=BLACK, center=True) draw_text(screen, tea.description, (SCREEN_WIDTH // 2, 550), font_size=FONT_SIZE_SMALL, color=BLACK, center=True) draw_text(screen, “点击任意位置或按 ESC 返回“, (SCREEN_WIDTH // 2, 580), font_size=FONT_SIZE_SMALL, color=WHITE, center=True) # 更新屏幕 pygame.display.flip() # 控制帧率 clock.tick(60) pygame.quit() sys.exit() if __name__ == “__main__“: main()

5. 运行验证与交互测试

完成以上代码后,你需要准备相应的图片资源(如beast_1.png,beast_2.png,beast_bg.jpg,button_shake.png,tea_cup.png)并放入assets/images/目录。可以使用任何图片,建议尺寸匹配代码中的预期。

在项目根目录下运行程序:

python main.py

如果一切正常,你将看到一个窗口:

  1. 初始状态 (IDLE):窗口中央显示一只“龙岛异兽”的图片、名称和描述,底部有一个“摇一摇”按钮。
  2. 交互:点击按钮或按空格键,程序进入SHAKING状态。你会看到奶茶杯左右晃动的动画,并提示“摇晃中...”。
  3. 结果:约2秒后(由SHAKING_DURATION控制),自动切换到RESULT状态,显示随机生成的一杯奶茶的详细信息(名称、茶底、配料、描述)。
  4. 返回:在结果界面点击鼠标或按 ESC 键,会返回IDLE状态。在空闲状态按右键可以切换展示不同的异兽。

这是一个最小可行产品(MVP),它完整实现了“展示-交互-反馈”的核心循环。

6. 常见问题排查与调试

在开发或运行过程中,你可能会遇到以下问题:

问题现象可能原因检查与解决方式
运行后窗口一闪而过或立即报错1. Python 或 Pygame 未正确安装。
2. 导入模块路径错误。
3. 资源文件缺失或路径不对。
1. 在命令行执行python -c “import pygame; print(pygame.ver)“确认 Pygame 能正常导入。
2. 检查config.py中的ASSET_DIR路径是否正确指向你的assets文件夹。
3. 确认assets/images/下存在代码中引用的图片文件(如beast_1.png)。
图片显示为彩色方块(品红色)load_image函数未能找到图片文件,返回了替代的 Surface。查看命令行输出,通常会有无法加载图片 ...的错误提示。核对文件名和路径,注意大小写。
点击按钮或按键无反应1. 事件处理逻辑未正确捕获到事件。
2. 状态判断条件有误。
3. 按钮矩形区域 (button_rect) 计算错误。
1. 在事件循环内添加print(event)打印所有事件,确认点击事件被触发。
2. 检查state_manager.current_state的值是否符合预期。
3. 在绘制循环中,用pygame.draw.rect(screen, (255,0,0), button_rect, 2)临时绘制按钮边框,看是否与图片位置匹配。
文字显示为乱码或方框系统或指定路径下没有中文字体。1. 将simhei.ttf字体文件放入assets/fonts/,或修改FONT_PATH指向一个确实存在的字体文件。
2. 在get_font函数中,回退到系统字体pygame.font.SysFont(‘simhei‘, size)‘simhei‘是常见中文字体名,也可尝试‘microsoftyahei‘‘arial‘(英文)。
摇动动画结束后未切换到结果状态SHAKING_DURATION设置过长,或状态更新逻辑state_manager.update()未被调用。1. 检查config.py中的SHAKING_DURATION值(单位毫秒)。
2. 确保在主循环中调用了state_manager.update()
切换异兽时索引越界BEASTS列表为空,或current_beast_index计算错误。1. 检查data/beasts.pyBEASTS列表是否至少有一个元素。
2. 在next_beast方法中添加print,确认索引计算正确。

调试建议:在关键函数开始或状态变更时,使用print语句输出变量值(如current_state,current_beast_index,current_tea.name),这是快速定位逻辑错误的最简单方法。

7. 扩展方向与最佳实践

当前项目是一个基础原型,你可以从以下几个方向进行扩展和优化,使其更完整、更健壮:

7.1 功能扩展

  1. 更多交互

    • 音效:在摇动和结果出现时添加音效。使用pygame.mixer.Sound加载.wav.ogg文件。
    • 更复杂的动画:使用pygame.transform.rotate实现奶茶杯旋转,或使用精灵帧动画。
    • 异兽与奶茶的关联:可以根据异兽的属性(如“火属性”)来影响奶茶的生成概率(提高“熔岩”系列奶茶的出现权重)。
  2. 数据丰富

    • 从外部文件(如 JSON、CSV)加载异兽和奶茶数据,便于非程序员修改内容。
    • 为异兽和奶茶添加更多属性,如稀有度、特效、解锁条件等。
  3. 状态持久化

    • 使用jsonsqlite3模块记录用户“摇”过的奶茶组合,形成一个收集册。

7.2 代码优化与最佳实践

  1. 资源管理

    • 预加载:在游戏初始化时 (__init__),将所有图片、音效、字体加载到缓存,避免在游戏循环中反复进行 IO 操作,导致卡顿。
    • 错误处理load_image函数应有更完善的错误处理,比如提供一张默认的“缺失图片”,而不是让程序崩溃。
  2. 状态机增强

    • 当前的状态机较为简单。对于更复杂的状态流转(如需要条件触发、有进入/退出动作),可以设计一个更通用的状态机基类,每个状态是一个独立的类,负责自己的绘制和更新逻辑。
  3. 配置化

    • 将更多的参数(如动画时长、颜色、屏幕尺寸、按钮位置)移至config.py或单独的 JSON 配置文件中,使调整更灵活。
  4. 模块化与解耦

    • 将渲染逻辑进一步分离。可以创建BeastView,TeaView,Button等类,每个类负责绘制自己对应的部分,主程序只负责协调和调用。这符合单一职责原则,让代码在功能增加时依然清晰。
  5. 性能考虑

    • 在绘制文本时,如果文本内容不变,可以渲染一次后保存为Surface对象,而不是每帧都重新渲染。这对于静态的标题和描述文字特别有效。

通过这个项目,你实践了一个小型交互应用从创意构思、模块设计、代码实现到调试排错的完整流程。关键在于理解事件循环如何驱动状态变化,以及如何将不同的数据、状态和视图清晰地组织起来。你可以以此为基础,融入更多自己的想法,创造出更独特、更丰富的交互体验。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/5 14:42:59

STM32C011 Flash操作深度指南:擦写、IAP与Option Bytes实战

简介&#xff1a;本资源是面向嵌入式初学者与STM32C0系列开发者的技术实践包&#xff0c;聚焦STM32C011F4P6芯片的Flash存储器底层操作&#xff0c;解决程序运行中非易失数据保存、固件参数持久化及读写保护配置等典型工程问题。压缩包为12.76MB的ZIP文件&#xff0c;内含基于S…

作者头像 李华
网站建设 2026/9/5 14:42:32

WebShell检测:深度学习与集成学习协同建模实战

简介&#xff1a;本资源是一个面向网络安全从业者与AI安全研究者的WebShell检测实战系统&#xff0c;融合深度学习&#xff08;LSTM、CNN特征提取&#xff09;与集成学习&#xff08;随机森林&#xff09;构建多层检测策略&#xff0c;有效识别隐蔽性强、变种频繁的恶意WebShel…

作者头像 李华
网站建设 2026/9/5 14:41:51

拼搭式个人主页:一句话部署,零运维成本打造动态数字名片

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/5 14:39:57

Vibex定制化AI开发:5000万免费Token与领域工作台实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/5 14:39:36

BR-VP2000A拼接控制器软件:软硬协同的拼接屏中枢系统

简介&#xff1a;本资源为博睿BR-VP2000A系列拼接控制器配套软件安装包及完整使用文档&#xff0c;面向安防监控中心、指挥调度室、展览展示等场景下的系统集成工程师、运维技术人员及大屏显示项目实施人员&#xff0c;解决多屏拼接配置复杂、信号源管理低效、画面不同步等实际…

作者头像 李华
网站建设 2026/9/5 14:37:13

ROS2 Humble仿真闭环:SLAM+MoveIt+Matlab协同工程实践

简介&#xff1a;本资源是一套面向人工智能、自动化、电子信息等专业学生的ROS综合实践项目&#xff0c;聚焦机器人仿真核心能力训练&#xff0c;涵盖SLAM建图与自主导航、MoveIt机械臂运动规划、MATLAB与Gazebo双向通信控制三大典型任务&#xff0c;适用于课程设计、期末大作业…

作者头像 李华