有没有想过?在只有巴掌大的掌控板上,居然也能跑出类似《毁灭战士》的3D画面?
没有建模,没有图形卡——靠的只是聪明的数学头脑和一种神奇的技术:✨光线追踪(Ray Casting)!
别眨眼,让我们走进这场“像素幻觉”的魔术表演!
🎩 光线追踪到底是啥?
想象你被困在一个黑漆漆的迷宫中,只能靠手里的一只手电筒照明。
你一边转动身体,一边发射出一束束“光线”,看看哪些方向被挡住了、哪些地方能走通。
你的大脑很聪明,它会根据“光照的距离”,自动在脑海里勾勒出立体的迷宫墙!
这就是“光线追踪”的灵感来源!我们用程序来模拟这种人眼+手电筒的探路逻辑!
👾 程序里怎么“假装看见立体”?
别担心,这里没有高数和公式怪兽,我带你用最直白的话来理解:
第一步:发射“无形的激光眼”!
我们站在地图上的某个位置,然后像雷达一样向前方发出几十条光线,每条线略微有一点角度变化,像扇子一样张开,形成一个视野。
第二步:每条光线一路狂奔,直到撞墙!
每一条光线像个勇敢的小探险家,一步步往前冲,不撞南墙不回头!只要碰到了地图里的“墙壁”,它就会立刻回报:“我在第3格撞到了墙!”
第三步:根据“撞墙的距离”,画出墙的高度
这是最神奇的部分!
如果光线走得很短就撞墙,那这面墙就离我们很近 → 画得高高的!
如果走了很远才撞墙,那这面墙很远 → 画得矮矮的!
第四步:每条光线画一条“竖线”,屏幕瞬间3D化!
把这些“高高矮矮”的线一根根排在屏幕上,远近高低、错落有致——
嘿!你看到的就像站在迷宫里,左右有墙,前方还有转角!
🕹 掌控板怎么操作?
别看这是个技术活,玩起来可简单得很!
A按钮 👉 左转视角
B按钮 👉 右转视角
触摸键 T 👉 像勇者一样向前冲!
触摸键 H 👉 小心后退,别撞墙啦!
就这样,你在掌控板的小小屏幕里,像第一人称射击游戏一样自由探索!
🗺 地图是“像素级”的世界
你走的每一步,其实都是在一个 二维数组中穿梭:
1111111111
1000000001
…………
你就像一个活跃在数组中的小精灵,凭着“光线”去认清世界,真有点《黑客帝国》的感觉~
💡 光线追踪是“3D错觉大师”!
说到底,屏幕永远是2D的,但光线追踪却能用数学制造出立体的错觉:
近大远小
角度偏差
墙面高度变化
再加一点点线条间距优化,就能节省性能也更真实
这些细节,正是构建“视觉幻觉”的关键!
⚙️代码
from mpython import *
import math
import time
# 地图
game_map = [
[1,1,1,1,1,1,1,1],
[1,1,0,0,0,0,0,1],
[1,0,1,0,1,0,1,1],
[1,0,0,0,0,0,0,1],
[1,0,1,1,0,1,0,1],
[1,0,0,0,0,0,0,1],
[1,0,1,0,0,1,0,1],
[1,1,1,1,1,1,1,1],
]
# 玩家初始位置和角度
player_x = 3.5
player_y = 3.5
player_angle = 0.0
# 常量
SCREEN_WIDTH = 128
SCREEN_HEIGHT = 64
FOV = math.pi / 3
MAX_DEPTH = 8.0
STEP_SIZE = 0.11 # 光线步长,越小越精确但越慢
# 线条间距函数:每隔1格方块距离,线条间隔+1像素,最多6像素
def get_line_spacing(distance):
spacing = int(distance) + 1
if spacing > 6:
spacing = 6
return spacing
last_time = time.ticks_ms() # 记录上一帧时间
# 视野绘制函数
def cast_rays(fps):
oled.fill(0)
x = 0
while x < SCREEN_WIDTH:
ray_angle = player_angle - FOV / 2 + (x / SCREEN_WIDTH) * FOV
cos_a = math.cos(ray_angle)
sin_a = math.sin(ray_angle)
distance = 0
hit = False
# 光线追踪
while not hit and distance < MAX_DEPTH:
distance += STEP_SIZE
test_x = int(player_x + cos_a * distance)
test_y = int(player_y + sin_a * distance)
if test_x < 0 or test_x >= 8 or test_y < 0 or test_y >= 8:
hit = True
distance = MAX_DEPTH
elif game_map[test_y][test_x] == 1:
hit = True
# 鱼眼修正
corrected_dist = distance * math.cos(ray_angle - player_angle)
if corrected_dist == 0:
corrected_dist = 0.1
# 墙高度计算
wall_height = int(SCREEN_HEIGHT / corrected_dist)
if wall_height > SCREEN_HEIGHT:
wall_height = SCREEN_HEIGHT
wall_start = max(0, int(SCREEN_HEIGHT / 2 - wall_height / 2))
wall_end = min(SCREEN_HEIGHT, int(SCREEN_HEIGHT / 2 + wall_height / 2))
# 绘制墙壁垂直线
oled.line(x, wall_start, x, wall_end, 1)
# 根据距离调整线条间距
spacing = get_line_spacing(distance)
x += spacing
# 左上角显示 FPS
oled.DispChar("FPS:%d" % fps, 0, 0)
oled.show()
# 游戏主循环
def game_loop():
global player_x, player_y, player_angle, last_time
while True:
now = time.ticks_ms()
elapsed = time.ticks_diff(now, last_time)
last_time = now
if elapsed == 0:
elapsed = 1 # 防止除零
fps = 1000 // elapsed
# 左转
if button_a.value() == 0:
player_angle -= 0.1
# 右转
if button_b.value() == 0:
player_angle += 0.1
# 角度归一化
player_angle %= 2 * math.pi
# 前进:触摸键T
if touchPad_T.read() < 400:
dx = math.cos(player_angle) * 0.12
dy = math.sin(player_angle) * 0.12
new_x = player_x + dx
new_y = player_y + dy
if game_map[int(new_y)][int(new_x)] == 0:
player_x = new_x
player_y = new_y
# 后退:触摸键H
if touchPad_H.read() < 400:
dx = math.cos(player_angle) * 0.12
dy = math.sin(player_angle) * 0.12
new_x = player_x - dx
new_y = player_y - dy
if game_map[int(new_y)][int(new_x)] == 0:
player_x = new_x
player_y = new_y
cast_rays(fps)
time.sleep(0.01)
# 启动游戏
game_loop()
⚙️ 技术细节科普
视角范围(FOV):一般设置为60度(π/3弧度),越大视野越广。
角度单位:用的是弧度(1圈 = 2π)。
鱼眼修正:边缘光线看起来会比中间更远,需修正距离避免画面拉伸。
帧率(FPS)显示:可以实时观察游戏运行流畅度。
🧪 有趣的拓展玩法
别满足于“只会看见墙”,试试加入:
🌟 “宝箱”、“钥匙” → 变身解谜游戏
🧟 “怪物NPC” → 第一人称射击(别担心,激光是你画的!)
🕹 自动地图生成 → 每次进入都是新的挑战!
还能加入光影效果、色彩深浅、贴图模仿,让这个迷宫更“魔幻”!
🧙 总结:数学+创意 = 掌控板上的3D奇迹!
谁说“3D”一定要靠大屏幕、高显卡?
只要你肯动脑,哪怕是小小的掌控板,也能跑出惊艳的立体世界!
学技术,不如造作品;玩代码,不如玩游戏!
下次,当有人说“我用Unity做了个3D迷宫”时,你可以笑着说:
“我在掌控板上用数学‘画’了一个!” 😎
如果你喜欢,欢迎留言/点赞。
也欢迎你自己创作迷宫地图、换个主角皮肤,甚至做个3D版“跳一跳”!
世界很小,创意无限——让我们在像素里冒险,在屏幕里穿越吧!
欢迎留言/点赞。
评论