下载 App

2D 等轴测视角:完整理论

05/25107 浏览开发交流
2D 等轴测视角:完整理论
一、视角的本质
什么是等轴测
人站在高处斜着往下看地面,地面上的方格子不再是正方形,而变成了菱形。这就是等轴测的视觉本质。
俯视(正上方看下去):         等轴测(斜上方看下去):
  ┌──┬──┬──┐                      ◇
  ├──┼──┼──┤                    ◇   ◇
  ├──┼──┼──┤                  ◇   ◇   ◇
  └──┴──┴──┘                    ◇   ◇
                                  ◇
正方形网格经过旋转 + 压缩,变成了菱形网格。
为什么是 2:1
业界最通用的等轴测比例是菱形宽:高 = 2:1。
        ╱╲         宽 = 2 单位
       ╱  ╲        高 = 1 单位
      ╱    ╲
     ╱      ╲
    ╲      ╱
     ╲    ╱
      ╲  ╱
       ╲╱
为什么选 2:1:
比例 视觉效果 问题
1:1 正菱形,像扑克牌方块♦ 太陡,像从很低的角度看
2:1 最经典,视野开阔 无
3:1 非常扁,接近俯视 建筑太矮,缺乏立体感
2:1 对应的理论观察角度约为 30°(从水平线往上抬 30° 的仰角去看),但在像素游戏中不需要精确角度,只需要记住"宽是高的两倍"这一条规则。
投影公式
这是整个系统的数学基石。假设每个格子宽 W、高 H(W = 2H):
网格坐标 (col, row) → 屏幕坐标 (sx, sy)
sx = (col - row) × W/2
sy = (col + row) × H/2
逆变换(屏幕坐标反推网格坐标):
col = (sx / (W/2) + sy / (H/2)) × 0.5
row = (sy / (H/2) - sx / (W/2)) × 0.5
直觉理解:
col 增大 → 屏幕往右下走
row 增大 → 屏幕往左下走
col 和 row 同时增大 → 纯粹往屏幕下方走
col 增大 row 减小 → 纯粹往屏幕右方走
二、地图的制作原理
层级结构
等轴测地图不是一张大图片,而是由多层数据叠加而成:
┌─────────────────────────────┐
│  第四层:UI / HUD           │  ← 固定在屏幕上,不随地图滚动
├─────────────────────────────┤
│  第三层:角色 / NPC          │  ← 按 Y 坐标排序(遮挡关系)
├─────────────────────────────┤
│  第二层:建筑 / 障碍物       │  ← 有高度的物体
├─────────────────────────────┤
│  第一层:地面瓦片            │  ← 最底层,铺满整个地图
└─────────────────────────────┘
地面层:瓦片铺设
地面是一个二维数组,每个格子存一个类型编号:
tileType[row][col] = GRASS / ROAD / WATER / PLAZA / ...
渲染时遍历可见范围内的格子,根据类型选择对应的菱形贴图:
对于每个可见格子 (col, row):
    1. 用投影公式算出屏幕坐标 (sx, sy)
    2. 查表得到瓦片类型 → 选择贴图
    3. 在 (sx, sy) 处绘制菱形贴图
关键优化:只绘制屏幕可见区域。一张 281×242 的地图有 6.8 万格子,全部遍历太慢。通过相机位置和缩放级别,反算出可见的 col/row 范围,只遍历这个子集。
道路系统:参数化定义
道路不是逐格手工填充,而是用参数化线段定义:
一条道路 = {
    方向:   水平 或 垂直,
    中心线: 第几行/列,
    起止:   从第几格到第几格,
    宽度:   占几格,
}
示例:一条宽 5 格的水平主干道
       中心线 coord = 50
  ──────────────────────────
  │  row 48  │░░░░░░░░░░│    ← coord - 2
  │  row 49  │░░░░░░░░░░│
  │  row 50  │░░░░░░░░░░│    ← 中心
  │  row 51  │░░░░░░░░░░│
  │  row 52  │░░░░░░░░░░│    ← coord + 2
  ──────────────────────────
             from → to
判断某格是否是道路:
for 每条道路 do
    half = floor(宽度 / 2)
    if 水平道路 then
        if row 在 [coord-half, coord+half] 且 col 在 [from, to] then
            → 是道路
    else -- 垂直道路
        if col 在 [coord-half, coord+half] 且 row 在 [from, to] then
            → 是道路
这种方式用十几条数据就能定义整个城市的路网,比逐格填充高效几个数量级。
区域系统:矩形标记
建筑、广场、水域等用矩形区域定义:
一个区域 = {
    左上角: (col1, row1),
    右下角: (col2, row2),
    类型:   建筑 / 广场 / 水域,
    名称:   "xxx",
}
查询某格属于什么区域:
function getTileInfo(col, row)
    -- 优先判断道路(道路覆盖在区域之上)
    for 每条道路 do
        if 在道路范围内 then return "道路", 可走
    end
    -- 再判断区域
    for 每个区域 do
        if col 在 [x1, x2] 且 row 在 [y1, y2] then
            return 区域类型, 是否可走
        end
    end
    -- 默认是草地
    return "草地", 可走
end
通行性
每种瓦片类型有固定的通行规则:
类型 可通行 说明
草地 是 默认地面
道路 是 主要行走路线
广场 是 开阔区域
建筑 否 角色绕行
水域 否 不可踏入
城门 是 出入口
三、建筑的制作原理
等轴测建筑的核心思想:在菱形底面上向上"挤出"墙壁,再盖上屋顶。虽然整个画面是纯平面绘制,但通过几何技巧模拟出立体感。
步骤一:确定地面菱形
建筑占据一个矩形区域 (col1,row1) 到 (col2,row2),投影到屏幕后是一个菱形:
                 顶点 (col1,row1)
                    ◇
                  ╱    ╲
       左点    ╱        ╲   右点
   (col1,row2+1)        (col2+1,row1)
                ╲        ╱
                  ╲    ╱
                    ◇
              底点 (col2+1,row2+1)
4 个角的屏幕坐标用投影公式算出。
步骤二:向上挤出墙壁
将地面菱形的 4 个顶点各向屏幕 Y 方向上移 wallHeight 像素,得到顶面 4 点:
        顶面 (上移 wallH)
            ◇ ─ ─ ─ ─ ─ ◇
          ╱ │           ╱ │
        ╱   │         ╱   │
      ◇     │       ◇     │    ← 只画可见的两个面
        ╲   │         ╲   │       (左墙面 + 右墙面)
          ╲ │           ╲ │
            ◇ ─ ─ ─ ─ ─ ◇
        地面菱形
等轴测视角下,只能看到建筑的两个侧面:
左墙面(西南面):顶点连线为 左点→底点→底点上方→左点上方
右墙面(东南面):顶点连线为 底点→右点→右点上方→底点上方
北面和西面被自身遮挡,不需要画。
步骤三:光影区分
两个可见面用不同明度区分,制造光照感:
光源假设在右上方:
  左墙面(背光):基色 - 35 明度    较暗
  右墙面(受光):基色 + 8 明度     较亮
假设墙壁基色 RGB = (190, 170, 140)
左墙: (155, 135, 105)   ← 减 35,阴影面
右墙: (198, 178, 148)   ← 加 8,受光面
仅这一步就能让平面绘制产生很强的立体感。
步骤四:添加屋顶
两种常见屋顶形态:
尖顶(四棱锥):
              尖顶点
                △
              ╱ │ ╲
            ╱   │   ╲
          ╱     │     ╲
     左上 ╱─────│─────╲ 右上
          ╲     │     ╱
            ╲   │   ╱
              ╲ │ ╱
               底上
  尖顶点 = 顶面中心再上移 peakHeight
  4 个三角面,分别用不同深浅的屋顶色
平顶:
     顶面直接画一个填充菱形
         ◇
       ╱    ╲
     ◇      ◇
       ╲    ╱
         ◇
步骤五:装饰细节
在墙面上叠加细节增加真实感:
砖缝线:
  沿墙面水平方向画几条等距细线
  颜色比墙面暗 20-30,半透明
  模拟石砖或木板纹理
门:
  右墙面底部中央画一个深色矩形
  宽度约占墙面 16%,高度约占墙高 45%
窗户(可选):
  墙面上方画小矩形,浅色描边
步骤六:阴影
在地面菱形偏移 (3, 3) 像素处画一个半透明黑色菱形,模拟地面投影:
  真实菱形位置
      ◇
    ╱    ╲         ◇ ← 阴影 (偏移3px, 黑色半透明)
  ◇      ◇      ╱    ╲
    ╲    ╱     ◇      ◇
      ◇          ╲    ╱
                   ◇
先画阴影,再画建筑本体,阴影就自然出现在建筑边缘。
建筑配色体系
不同功能的建筑用不同色系区分:
建筑类型 墙面色调 屋顶色调 屋顶形态
城堡/官方 灰蓝石 深蓝 平顶
商店 暖砂岩 红瓦 尖顶
民居 木色 红棕 尖顶
宗教 白石 铜绿 尖顶
竞技/军事 砂石 灰褐 平顶
公共服务 浅石 棕瓦 尖顶
这样玩家不看文字标注,光凭颜色就能大致分辨建筑功能。
四、绘制顺序(遮挡关系)
等轴测最关键的问题:谁画在谁前面?
规则很简单:先画远的,后画近的。"远近"的判断标准是 col + row 的值(即屏幕 Y 方向):
绘制顺序(从远到近):
  row=0, col=0  ← 最先画(最远,屏幕最上方)
  row=0, col=1
  row=1, col=0
  row=1, col=1
  ...
  row=N, col=M  ← 最后画(最近,屏幕最下方)
画面叠加效果:
      远处建筑 (先画)
          ┊
    近处角色 (后画,覆盖在建筑下半部分之上)
          ┊
    最近的树 (最后画,覆盖角色)
对于建筑和角色混合的场景,统一按 col + row(或直接用屏幕 Y 坐标)排序后依次绘制,自然就形成了正确的前后遮挡。
五、完整渲染流水线
每一帧:
1. 清屏(填充背景色)
         │
2. 计算可见网格范围(根据相机位置和缩放)
         │
3. 绘制地面层
   │  遍历可见格子,逐行逐列
   │  根据类型铺菱形贴图(草地/道路/广场/水面)
         │
4. 收集所有需要绘制的立体物体
   │  建筑、角色、NPC、树木……
   │  按 (col + row) 或屏幕 Y 排序
         │
5. 按排序顺序依次绘制
   │  先画阴影 → 墙壁(暗面+亮面)→ 屋顶 → 装饰
         │
6. 绘制 UI 层(固定在屏幕上,不随地图移动)
总结
概念 核心原理
视角 正交网格旋转 45° + Y 轴压缩 50%,菱形宽高比 2:1
投影 sx = (col-row)×W/2,sy = (col+row)×H/2,及其逆变换
地图 多层叠加:地面瓦片 + 道路参数化线段 + 区域矩形标记
建筑 地面菱形 → 向上挤出墙壁 → 光影分
TapTap
TapTap
面 → 加屋顶 → 加装饰
遮挡 按 col + row 从小到大绘制,后画覆盖先画
交互 屏幕坐标逆投影回网格坐标,判断通行性后移动角色
这套体系从 90 年代的《暗黑破坏神》《仙境传说》到现在的独立游戏一直在用,原理完全相同,区别只在于美术精度和优化手段。
01:27
《大二暑假,我用AI做了一款属于自己的游戏》截图
《大二暑假,我用AI做了一款属于自己的游戏》
本人自制游戏现已加入taptap封闭测试(仅适配安卓机型)欢迎大家前来尝试(八月十号可以正式开始游玩) 如果有建议或者bug反馈可以加入qq群928501443 #发现好游戏 #游戏日常 #浅评一下 #今天游戏圈发生了啥
3 赞
别再烧积分了!从每次 2000 到每次 50 的血泪经验截图
别再烧积分了!从每次 2000 到每次 50 的血泪经验
适用场景:所有在用 TapTap Code 开发游戏的小白 难度:★☆☆☆☆ 背景最近群里总有人"炫耀"一次操作花了几千积分,说实话这不是值得高兴的事——这是在告诉所有人你的开发方式有根本性问题。我也走过这条弯路,所以来说说怎么改。 积分消耗的本质是什么积分 = AI 处理的 token 数量 = 你发给 AI 的内容 + AI 回给你的内容所以烧积分的本质只有两种: 你让 AI 做了大量无效/重
精华
68 赞
21 回复
03:06
为了不被斩杀,我只能做到这些了截图
为了不被斩杀,我只能做到这些了
之前一直申请不到计划3,之前说太花哨,后面说体量完成度不足,在我一番小作文下,编辑终于给了我解答,什么原生质感,玩家开局体验啥的。 本来计划2也够用,准备以后再优化了,结果计划2赠送的积分要砍半了,学生党实在消费不起,于是只能再冲一波计划3了 从周六中午到现在一天半时间,优化了一遍角色卡,战斗卡,还有抽卡界面,优化了新手教程,该说不说确实比之前要舒服些。 前半部分为新版,后半部分为旧版。 明天再次
37 赞
6 回复
如何提升你游戏中的UI美术水平截图
如何提升你游戏中的UI美术水平
一、请为你的游戏挑选一款合适的字体 很多开发者没有注意到其实UI界面中最重要的元素是字体,一款合适的字体能给整个游戏的界面感官带来蜕变。 请看案例 那么如何挑选适合自己的字体呢? 我总结出了一些小经验可供参考: 黑体:通用 宋体:古风、武侠、修仙 楷体:古风、武侠、修仙 圆体:卡通、动漫、Q版 科技:科幻、未来、电子 顺手分享一个免费可商用字体网站: 当然 如果你不知道自己的游戏适合什么风格
精华
123 赞
44 回复
TapTap制造踩坑实录|只写游戏名称的后果截图
TapTap制造踩坑实录|只写游戏名称的后果
今天在TapTap制造复刻Inflation RPG,踩了一个大坑,分享给准备做游戏的创作者。 我只在对话框输入了游戏原名「Inflation RPG」,AI直接自动脑补整套游戏方案,一次性生成全部美术、战斗系统、轮回机制。 一次性消耗接近3000积分,直接把积分打到负数。 生成预览之后发现:AI擅自改动了原版核心玩法。原版Inflation RPG核心是一局固定30次战斗点数,本局属性暴涨,打完
开发心得-界面布局心得截图
开发心得-界面布局心得
大家好,我正在用 TapTap 制造制作一款2D 治愈林间徒步旅行游戏《徒步荒野》。 我分享一下我的开发心得,希望能有用,下面是一些界面布局的心得。 第一步:定版式、操作 先确定游戏是横版还是竖版、需要哪些操作按钮,敲定整体玩法思路。 我的玩法灵感参考《边境之旅》,主打散步看风景、沿途触发随机事件。 原版是 3D,考虑到自己是新手,选择2D 横版街机式来做,制作更简单、好上手。 第二步:敲定全局美
6 赞
3 回复
00:26
塔啦啦科研:三渲二(风格1)截图
塔啦啦科研:三渲二(风格1)
最近在研究像素风格的三渲二,一直想做小丑牌那种风格,但是塔啦啦一直做不出来,发现是有一部分的功能做不了,只能实现简单的材质制作和描边,因此,我从零直接搭建了一整套引擎基础。目前进度可以看视频。 @嗒啦啦 什么时候出shader 评论区随意提问 #TapTap制造 #TapTap制造社区 #TapTap制造
4 赞
5 回复
01:13
【游戏自荐】《王朝崛起》——一个人做的2D骑马砍杀,但真的上头截图
【游戏自荐】《王朝崛起》——一个人做的2D骑马砍杀,但真的上头
略沙盒,玩法硬核,还在修bug,但真的上头 先声明:我不是托,是开发者自己来安利的。如果你喜欢《骑马与砍杀》那种从零拉起部队、跑商、招降将领、攻城叛变的玩法,那这款游戏大概率会对你的胃口。 一、这游戏玩什么? · 超大的2D沙盒地图:64座城市 + 128个村庄,四大势力割据,满地图的蛮族部落。· 动态世界 & AI:AI势力之间会自己宣战、结盟、叛变;武将忠诚度低了会自立为王,最多能冒出8个新势
10 赞
7 回复
浅记《阿方的旅程》开发历程截图
浅记《阿方的旅程》开发历程
预计阅读时长10分钟,欢迎您先品鉴游戏,再回来看这篇“流水账” 这是我第一次实际接触“用自然语言制作游戏”,也是我第一次接触游戏开发工作,所以一切都是从零开始,跌跌撞撞,懵懵懂懂。[表情_豹哭] 我是通过获得的本次开发资格,6月22日晚,在微信公众号收到了测试资格的消息,最开始公布主题“跳跃”的时候,脑子里最先想到的就是几款非常经典的游戏「马里奥」「Flappy Bird」「Doodle Jump
10 赞
1 回复
游戏自荐《少女终焉契约》截图
游戏自荐《少女终焉契约》
之前玩放置类型的rpg游戏的时候我就在想,现在游戏的操作有的太过于繁琐了,有没有一款休闲一点的,想上线就上线,离线的时候角色能自动行动的游戏呢?感谢TapTap制造,我按照我的想法开发出了现在这款游戏。 一、故事背景和UI 游戏的故事背景是传统的异世界穿越故事,玩家被女神召唤到异世界,随后组建工会,招募美少女,打怪升级探索世界。所以我选择了更加二次元萌系画风的UI风格,主页为各个主要的功能,点开来
8 赞
3 回复