news 2026/4/16 4:07:36

Python + Ursina设计一个有趣的3D小游戏

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Python + Ursina设计一个有趣的3D小游戏

Python + Ursina设计一个有趣的3D小游戏

Ursina使用基础知识可见 https://blog.csdn.net/cnds123/article/details/155709276

Python + Ursina设计一个有趣的3D小游戏:《天空跑酷:寻找金立方》

项目文件夹结构是这样的:

你的文件夹/
├── main.py (下面的代码)
├── SimHei.ttf (必须有!用于显示中文)
└── sounds/ (文件夹)
├── jump.wav (跳跃音效,可选)
└── win.wav (胜利音效,可选)

运行截图:

完整代码如下:

## 玩法说明 ## 脚踩 灰色 起点(出生地)。 ## 一路跳过 绿色 方块(稳扎稳打)。绿色块是安全踏板。 ## 小心应对 蓝色 方块(看准时机)。左右摆动的蓝色块是给游戏增加难度的“拦路虎”。 ## 绝对不要碰 红色 地面(碰了就重来)。红色区域是万丈深渊的底部。 ## 最终摸到 黄色 小方块(通关胜利)。 ## 鼠标移动:转动视角(看天、看地、看路)。注意:进入游戏后鼠标光标会消失,这是正常的 FPS 模式。 ## 在所有绿色平台的尽头,悬浮着一个金黄色的大方块(还会旋转)。 ## W 键:向前走。S 键:向后退。A 键:向左移。D 键:向右移。空格键 (Space):跳跃。 ## 按住W冲刺,看准时机按空格,飞向下一个绿色方块;有的平台离得远,需要按住 W 助跑再按空格;有的离得近,原地起跳就行。 ## ESC 键:直接强制退出游戏。 from ursina import * from ursina.prefabs.first_person_controller import FirstPersonController import random import os # os._exit(0) 用到 # 初始化引擎 app = Ursina() # --- 1. 设置中文字体 (必须!) --- Text.default_font = 'SimHei.ttf' # --- 2. 音频设置 (运用你刚学的知识) --- # 即使文件不存在,Ursina 通常只是报警告而不会崩溃,但建议你放进去体验更好 jump_sound_path = 'sounds/jump.wav' # 显式路径写法,稳定可靠 win_sound_path = 'sounds/win.wav' def play_audio_if_exists(path): # 一个安全播放音频的小函数 if os.path.exists(path): Audio(path, autoplay=True) # --- 3. 场景搭建 --- # 天空盒 (给游戏一个背景) Sky() # 地面 (Death Zone) - 用红色表示危险,掉在上面会重置 death_zone = Entity( model='plane', scale=(100, 1, 100), color=color.red, y=-10, collider='box', texture='white_cube' # 内置纹理 ) # 起点平台 start_platform = Entity( model='cube', color=color.gray, scale=(5, 1, 5), position=(0, 0, 0), collider='box', texture='white_cube' ) # --- 4. 关卡生成算法 --- # 我们运用左手坐标系:Y是高,Z是前 platforms = [] z_pos = 0 y_pos = 0 # 生成 15 个随机跳跃平台 for i in range(15): # 每次往前(Z)走 4~6米,往上(Y)走 -1~2米 (可能高也可能低) z_pos += random.uniform(4, 7) # Z-Forward(向前是Z+)。降低难度修改:改成 3~5:z_pos += random.uniform(3, 5),缩小平台之间的缝隙 y_pos += random.uniform(-1, 2) # Y-Up(向上是Y+) # 随机左右偏移(X) x_pos = random.uniform(-3, 3) # 创建平台 p = Entity( model='cube', color=color.green, scale=(3, 0.5, 3), # 稍微扁一点。降低难度修改:改成 5或者更大 scale=(5, 0.5, 5) position=(x_pos, y_pos, z_pos), collider='box', texture='brick' ) platforms.append(p) # 给第 5 个和第 10 个平台加特效:它们是会移动的! if i == 5 or i == 10: p.color = color.azure p.is_moving = True # 自定义属性标记 else: p.is_moving = False # --- 5. 终点目标 --- goal_block = Entity( model='cube', color=color.gold, scale=(2, 2, 2), position=(0, y_pos + 1, z_pos + 6), # 在最后一个平台前面一点 collider='box', texture='white_cube' ) # --- 6. 玩家设置 --- player = FirstPersonController( model='cube', collider='box', gravity=0.8 # 重力参数。降低难度修改:降低到 0.5 或 0.4 ) player.cursor.visible = False # 隐藏鼠标 # --- 7. UI 文本 --- msg_text = Text( text='按 WASD 移动,空格跳跃\n目标:找到金色方块!', origin=(0, 0), y=0.3, scale=2, color=color.yellow ) # 胜利状态标记 game_won = False # --- 8. 游戏主逻辑 (Update) --- def update(): global game_won if game_won: return # 如果赢了,就不运行后面的逻辑了 # 1. 检测是否掉落 (Y轴判定) if player.y < -5: player.position = (0, 1, 0) # 回到起点 msg_text.text = '你掉下去了!\n已重置位置' msg_text.color = color.red invoke(reset_text, delay=2) # 2秒后重置文字 # 2. 检测移动平台逻辑 # time.time() 返回当前时间,sin 函数让数值在 -1 到 1 之间波动 for p in platforms: if hasattr(p, 'is_moving') and p.is_moving: # 让平台在 X 轴方向左右摇摆 p.x += math.sin(time.time() * 2) * 0.05 # 产生平滑左右摇摆的平台。降低难度修改:* 0.05 改成 * 0.01 # 3. 检测胜利 (检测玩家和金块的距离) # distance(a, b) 是 Ursina 内置函数 if distance(player.position, goal_block.position) < 2: win_game() # --- 9. 输入控制 (Input) --- def input(key): # 【调试大法】打印当前按下的键 print(f"检测到按键: {key}") if key == 'space': # 简单的跳跃音效逻辑 # 只有当玩家在地上时才播放声音(Userina的player.grounded属性) if player.grounded: play_audio_if_exists(jump_sound_path) # 用 ESC 退出 if key == 'escape': print("按下了 ESC") #application.quit() # 不用——不起效,它太温柔了 os._exit(0) # 重点! # 辅助函数 def reset_text(): if not game_won: msg_text.text = '加油!往 Z 轴正方向前进!' msg_text.color = color.white def win_game(): global game_won game_won = True msg_text.text = '恭喜!挑战成功!\n按 ESC 退出' msg_text.color = color.green msg_text.scale = 3 msg_text.background = True play_audio_if_exists(win_sound_path) # 一个小彩蛋:让金块旋转起来 goal_block.animate_rotation_y(360, duration=1, loop=True) app.run()

说明

1.在代码的input(key)函数里只写了Space播放声音,没写if key == 'w': move_forward(),为什么它自己就会走呢?

因为使用了一个“现成的超级零件” ——FirstPersonController。这个零件(类)是 Ursina 官方帮你写好的,它内部封装了复杂的数学运算和物理逻辑。

from ursina.prefabs.first_person_controller import FirstPersonController 这行代码导入了 Ursina 的一个预制的第一人称控制器,它是一个已经封装好的、功能完整的角色控制器。也可以说,FirstPersonController是 Ursina 引擎中用于快速创建第一人称视角玩家控制器的预制组件(prefab)。FirstPersonController的作用包含以下功能:

• 鼠标控制视角(左右/上下看)

• WASD 移动

• 空格键跳跃

• 重力与地面碰撞检测

• 自动站在地面上(不会掉下去)

• 可调节速度、跳跃高度、视角灵敏度等参数

简单示例:

from ursina import * from ursina.prefabs.first_person_controller import FirstPersonController # 设置窗口大小(宽, 高) window.size = (1280, 720) app = Ursina() # 创建地面 ground = Entity(model='plane', scale=10, color=color.green, collider='box') # 创建第一人称玩家 player = FirstPersonController() app.run()

现在你可以试试这个简单的示例是否正常运行:

• 移动鼠标:视角应该会转动(即使窗口小,也能看到地面颜色变化)。

• 按 WASD:角色会移动(虽然看不到自己,但相机位置在变)。

• 按空格:会跳起(可配合向下看观察地面距离变化)。

如果想用箭头键取代WASD键控制角色移动怎么办?

在内置函数update()中使用held_keys字典映射是最简便的方式

update()是Ursina 引擎中内置函数,一个每帧自动调用的函数,用于实现持续更新的游戏逻辑,比如角色移动、动画、物理、AI 行为等。

示例代码:

from ursina import * from ursina.prefabs.first_person_controller import FirstPersonController # 设置窗口大小(宽, 高) window.size = (1280, 720) app = Ursina() # 创建地面 ground = Entity(model='plane', scale=10, color=color.green, collider='box') # 创建第一人称玩家 player = FirstPersonController() # 将方向键映射到 WASD def update(): held_keys['w'] = held_keys['up arrow'] held_keys['s'] = held_keys['down arrow'] held_keys['a'] = held_keys['left arrow'] held_keys['d'] = held_keys['right arrow'] app.run()

你可以运行试试看。

2.如何调整游戏的难度?

可以通过调整几个关键参数,如想降低游戏的难度:

①调整引力

原代码

gravity=0.8

修改为:降低到 0.5 或 0.4

gravity=0.5

②踏板变大 (增大落脚面积)

原代码 (3米宽)

scale=(3, 0.5, 3)

修改为:改成 5米或者更大

scale=(5, 0.5, 5)

③拉近平台距离 (减少跳跃跨度)

原代码 (间距 4~7米)

z_pos += random.uniform(4, 7)

修改为:改成 3~5米

z_pos += random.uniform(3, 5)

④降低两个捣乱的蓝色方块移动速度

原代码 (0.05 是移动速度幅度)

p.x += math.sin(time.time() * 2) * 0.05

修改为:改成 0.01,几乎不动了

p.x += math.sin(time.time() * 2) * 0.01

你可以修改试试。

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

AI如何帮你快速掌握kubectl exec -it命令

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容&#xff1a; 创建一个交互式学习工具&#xff0c;能够根据用户输入自动生成kubectl exec -it命令示例。当用户输入如何进入Pod的bash shell时&#xff0c;自动生成kubectl exec -it <pod-nam…

作者头像 李华
网站建设 2026/4/16 1:20:01

联想刃7000k BIOS权限深度解析与性能释放终极指南

联想刃7000k BIOS权限深度解析与性能释放终极指南 【免费下载链接】Lenovo-7000k-Unlock-BIOS Lenovo联想刃7000k2021-3060版解锁BIOS隐藏选项并提升为Admin权限 项目地址: https://gitcode.com/gh_mirrors/le/Lenovo-7000k-Unlock-BIOS 对于追求极致性能的技术爱好者而…

作者头像 李华
网站建设 2026/4/15 19:46:19

ProfibusDP转ModbusTCP:工业通讯网关实现西门子S7-300PLC与MES生产线通信

一、项目背景某大型机械制造企业启动智慧工厂升级项目&#xff0c;核心目标是实现8条精密零部件生产线的全流程数字化管控&#xff0c;涵盖生产数据实时采集、设备状态远程监控、生产工艺追溯等功能。车间现有现场控制层采用成熟的ProfibusDP总线架构&#xff0c;每条生产线的核…

作者头像 李华
网站建设 2026/4/9 19:22:01

K8S系列之6.2:调度进阶(污点、容忍、亲和性与自定义调度器)

Kubernetes调度器被称为集群的"大脑",负责将Pod分配到合适的节点。本章将从基础调度深入到高级调度策略,让你从"能调度"进阶到"调度好",实现资源的最优利用和业务的最佳性能。 引言:调度器的进化之路 从简单的随机调度到智能的感知调度,Ku…

作者头像 李华
网站建设 2026/4/10 17:30:07

vmtools在企业虚拟化环境中的5个实战场景

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容&#xff1a; 创建一个演示项目&#xff0c;展示vmtools在以下场景的应用&#xff1a;1) 自动扩展虚拟机磁盘空间 2) 跨主机迁移虚拟机 3) 批量更新虚拟机工具 4) 监控虚拟机性能指标 5) 自动化备…

作者头像 李华
网站建设 2026/4/12 3:33:07

Zotero行高设置:三招解决阅读体验优化难题

Zotero行高设置&#xff1a;三招解决阅读体验优化难题 【免费下载链接】zotero-better-notes Everything about note management. All in Zotero. 项目地址: https://gitcode.com/gh_mirrors/zo/zotero-better-notes 你是否曾经在Zotero-Better-Notes中阅读长篇笔记时感…

作者头像 李华