跳到主要内容

场景5—小地图功能

概述

这个案例在屏幕右下角生成了一个小地图,地图上可以显示地面画面,并标识出相机所在的位置,完整的项目介绍请见应用教程

场景准备

场景搭建

  1. 创建一个3D场景(本案例使用带有几何体和迷宫的一个场景,你可以在基础场景和节点变换案例的场景中找到这些素材),将默认的飞行相机替换为第三人称相机

  2. 新建一个纹理图,用于将视口的画面绘制到屏幕上,实现小地图的画面

  3. 在小地图的纹理图下再创建一个纹理图节点,用作小地图上显示人物位置的小三角图标

  4. 新建一个视口节点,在这个视口下创建一个空相机,命名为”地图相机“,视口将通过这个相机渲染画面

  5. 节点结构如下:

将地图相机画面显示到小地图

设置视口、纹理图的相关属性,实现在纹理图上显示3D画面的效果:

  1. 将视口的大小调整为500×500,这表示视口渲染的分辨率大小

  2. 启用视口的“垂直翻转”属性,这是因为默认情况下,视口渲染的画面是上下颠倒的。

  3. 右键点击纹理图的纹理属性,选择新建ViewportTexture,在弹出的选择框里选择”视口“节点

    此时,纹理图应该上应该会显示视口的画面,尝试调整相机可以看到画面的变化

  4. 启用“小地图”纹理图的扩展属性,将大小调整为合适的大小,这里调整为250×250

地图相机设置

将相机置于场景正上方并启用”正交“,使相机画面变为二维俯视平面:

  1. X轴旋转角度设为-90,位置设为(0, 20, 0)
  2. 将属性投影模式设为“正交”,大小设为50,这表示相机拍摄的范围为一个50 * 50的水平面

纹理图设置

  1. 将文件夹下的小三角图标设为纹理并启用垂直翻转,垂直翻转的目的是将三角图标的朝向设为二维坐标系Y轴的正方向

  2. 设置"小三角图标"纹理图的大小为20×20,中心点偏移设为10×10,使旋转中心置于几何中心。

脚本实现

在小地图的纹理图节点上创建脚本。在脚本中主要需要实现将人物在三维坐标系的位置和小地图上的二维坐标系的位置映射。

创建变量

创建一个NodePath类型的变量,添加export关键字,然后用一个变量通过这个路径获取对应的人物节点。这样做的目的是当需要更改小地图追踪的人物时,可以在属性栏中快速修改,而不用每次都在脚本中修改。

export var character_path:NodePath #可以在属性栏调整的节点路径
onready var character = get_node(character_path) #节点路径对应的节点

在后续的代码中,需要添加判断,当没有获取到人物节点时则不进行后续操作:

func _physics_process(delta):
if character == null:
return
tip

本案例小地图追踪的是第三人称相机,但注意不要直接指定第三人称相机根节点,将其展开后指定内部的”商务男“节点,因为该节点用于记录第三人称相机的位移和旋转信息。

坐标系转换

人物在移动时改变的时三维坐标,而小地图绘制在UI上,使用二维坐标,要实现两者的转化,可以参考下图进行理解:

坐标轴和坐标原点映射

人物从红框的左上角的位置移动到右下角的位置,小地图中的人物位置也从左上角移动到右下角,即三维X轴和二维X轴对应,三维Z轴和二维Y轴对应。

二维坐标原点的位置对应的三维X-Z坐标为(-25, -25),二维X-Y坐标为(0, 0),相差25(这个值是视口大小的一半),为每一个三维X坐标、Z坐标加上这个值,赋给两个变量,作为二维X坐标、Y坐标,则完成了坐标系原点和坐标轴的映射:

    #将三维中的X、Z坐标转换为二维中的X、Y坐标
var viewport_size = get_node("../视口/地图相机").size
var position_2d_x = character.global_transform.origin.x + viewport_size / 2
var position_2d_y = character.global_transform.origin.z + viewport_size / 2

坐标单位映射

经过映射后,人物走到红框右下角时的小地图坐标为(50, 50),这个单位是米。但小地图中坐标系的单位是像素,右下角的值为它自身的矩形大小(250, 250)。通过将坐标值除以50(这个值是视口大小),可以进行归一化,归一化后,再和小地图矩形的大小相乘,即可完成坐标单位的映射:

    var position_2d_normalized = Vector2(position_2d_x, position_2d_y) / viewport_size
var position_2d = position_2d_normalized * rect_size

旋转映射

三维中的旋转方向和二维相反,将三维中Y轴的旋转取反即可完成映射。

    var rotation_2d = -character.rotation_degrees.y

完成

将得到的位移和旋转的值赋给小地图下的人物位置节点:

    $小三角图标.rect_position = position_2d - $小三角图标.rect_size / 2
$小三角图标.rect_rotation = rotation_2d