虚拟美术馆项目在Virtual art space Volume下,Demo是场景展示

Player脚本
在脚本中通过chracter controller 控制移动

代码依靠 CharacterController + 相机朝向,实现跟着镜头方向走(WASD 前后左右)。
1. 获取输入方向
csharp
float horizontal = Input.GetAxis("Horizontal"); // A/D、左右箭头:-1 ~ 1
float vertical = Input.GetAxis("Vertical"); // W/S、上下箭头:-1 ~ 1
Horizontal:左右轴,A=-1、D=1、无按键=0Vertical:前后轴,W=1、S=-1、无按键=0
这一步拿到玩家按键的偏移值。
2. 对齐相机方向(关键:跟着镜头走)
csharp
Vector3 cameraForward = cameraTransform.forward;
cameraForward.y = 0f; // 去掉上下俯仰,只保留水平方向
cameraForward.Normalize(); // 单位化,保证移动速度均匀
Vector3 cameraRight = cameraTransform.right;
cameraRight.y = 0f;
cameraRight.Normalize();
cameraTransform.forward:相机正前方- 把
y置0 = 忽略高低,只算水平面,不会往天上/地下走 Normalize():把方向向量长度固定为1,避免斜着走速度变快。
3. 合成最终移动方向
csharp
Vector3 move = cameraForward * vertical + cameraRight * horizontal;
公式理解:
- 相机前方向 × 前后按键(W/S) = 相对镜头前后
- 相机右方向 × 左右按键(A/D) = 相对镜头左右
两者相加,得到基于相机视角的整体移动方向。
4. 执行移动(核心运动函数)
csharp
controller.SimpleMove(move * moveSpeed);
move * moveSpeed:方向 × 移动速度,算出最终移动矢量CharacterController.SimpleMove():
自带重力、碰撞检测,直接让角色沿目标方向移动,不用自己算位移。
csharp
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
// 相机控制脚本:实现第三人称跟随、鼠标旋转视角、滚轮缩放、点击交互
public class PlayerCamera : MonoBehaviour
{
[Header("=== 相机跟随目标 ===")]
public Transform playerTarget; // 要跟随的玩家对象
[Header("=== 鼠标视角控制 ===")]
public float mouseSensitivity = 2f; // 鼠标灵敏度
public float minYAngle = -20f; // 视角向下最大俯角
public float maxYAngle = 80f; // 视角向上最大仰角
public float targetHeight = 1.5f; // 相机看向玩家的高度(头顶/胸口)
private float mouseX; // 存储鼠标左右旋转值(水平)
private float mouseY; // 存储鼠标上下旋转值(垂直)
[Header("=== 相机距离(缩放)===")]
public float currentDistance = 3f; // 当前相机与玩家的距离
private float zoomSpeed = 2f; // 滚轮缩放速度
private float minDistance = 1f; // 最近缩放距离
private float maxDistance = 5f; // 最远缩放距离
[Header("=== UI 交互对象 ===")]
public GameObject QuestionsCanvas; // 问题UI面板
public GameObject DeepSeekCanvas; // 对话UI面板
public GameObject DrawCanvas; // 绘画UI面板
private CanvasShowArtMessage artUI; // 显示艺术信息的UI脚本引用
void Start()
{
// 1. 如果没有手动指定玩家,自动通过标签寻找Player
if (playerTarget == null)
{
GameObject player = GameObject.FindGameObjectWithTag("Player");
if (player != null)
{
playerTarget = player.transform;
}
}
// 2. 游戏开始时锁定鼠标,隐藏光标(FPS/第三人称常用)
Cursor.lockState = CursorLockMode.Locked;
Cursor.visible = false;
// 3. 找到场景中的艺术信息UI脚本
artUI = FindObjectOfType<CanvasShowArtMessage>();
}
// LateUpdate:所有Update执行完后再执行,保证相机跟随更平滑,不卡顿
void LateUpdate()
{
// 没有跟随目标直接退出,防止报错
if (playerTarget == null) return;
// 处理鼠标显示/隐藏(LeftAlt切换)
HandleCursorLock();
// 只有在光标隐藏时,才允许旋转视角
if (!Cursor.visible)
{
HandleMouseInput();
}
// 鼠标左键点击交互
HandleClick();
// 鼠标滚轮缩放
HandleZoom();
// 更新相机位置和角度
UpdateCameraPosition();
}
// 功能:鼠标左键点击物体,触发UI显示
void HandleClick()
{
// 检测鼠标左键按下
if (Input.GetMouseButtonDown(0))
{
// 从相机发射一条射线到鼠标点击的位置
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit hit;
// 如果射线碰到了物体
if (Physics.Raycast(ray, out hit))
{
if (artUI != null)
{
// 根据点击物体的名称,打开对应的UI面板
if(hit.collider.gameObject.name == "WorldQuestionsCanvas")
{
QuestionsCanvas.SetActive(true);
}
else if(hit.collider.gameObject.name == "WorldDeepSeekCanvas")
{
DeepSeekCanvas.SetActive(true);
}
else if(hit.collider.gameObject.name == "WorldDrawCanvas")
{
DrawCanvas.SetActive(true);
}
// 点击其他物体 → 显示对应的艺术介绍
else
{
artUI.ShowArtByName(hit.collider.gameObject.name + "Art");
}
}
}
}
}
// 功能:按 Left Alt 键 切换鼠标显示/隐藏
void HandleCursorLock()
{
if (Input.GetKeyDown(KeyCode.LeftAlt))
{
if (Cursor.visible)
{
// 隐藏光标 + 锁定到屏幕中心
Cursor.lockState = CursorLockMode.Locked;
Cursor.visible = false;
}
else
{
// 显示光标 + 解锁
Cursor.lockState = CursorLockMode.Locked;
Cursor.visible = true;
}
}
}
// 功能:获取鼠标输入,计算旋转角度
void HandleMouseInput()
{
// 水平旋转:鼠标左右移动 累加
mouseX += Input.GetAxis("Mouse X") * mouseSensitivity;
// 垂直旋转:鼠标上下移动 累加(减号=反转Y轴,符合正常操作习惯)
mouseY -= Input.GetAxis("Mouse Y") * mouseSensitivity;
// 限制垂直视角角度,防止相机翻到角色底下或天上
mouseY = Mathf.Clamp(mouseY, minYAngle, maxYAngle);
}
// 功能:鼠标滚轮控制相机远近(缩放)
void HandleZoom()
{
// 获取滚轮输入
float scroll = Input.GetAxis("Mouse ScrollWheel");
// 调整相机距离
currentDistance -= scroll * zoomSpeed;
// 限制距离在最大/最小范围内
currentDistance = Mathf.Clamp(currentDistance, minDistance, maxDistance);
}
// 核心功能:计算相机最终位置 + 旋转,让相机环绕玩家
void UpdateCameraPosition()
{
// 相机跟随的目标点(玩家位置 + 向上偏移高度)
Vector3 targetPosition = playerTarget.position + Vector3.up * targetHeight;
// 将鼠标的X、Y值转为旋转角度
Quaternion rotation = Quaternion.Euler(mouseY, mouseX, 0);
// 相机向后移动的距离(沿着相机自身的Z轴后退)
Vector3 negDistance = new Vector3(0.0f, 0.0f, -currentDistance);
// 计算相机最终位置:目标点 + 旋转后的后退位置
Vector3 desiredPosition = targetPosition + rotation * negDistance;
// 应用旋转和位置 → 相机完成跟随+视角旋转
transform.rotation = rotation;
transform.position = desiredPosition;
}
}

game这里固定为1920*1080 。

角色动画
Player中有了角色动画资源,如何使用?


播放行走动作

在Player脚本中使用角色动画资源
定义动画组件
csharp
private Animation animation1;
- 这是 Unity 旧版动画系统 Animation 组件
- 角色身上已经挂载了这个组件,并放入:
- 走路动画(名字叫 walk)
- 待机动画(名字叫 wait)
代码在哪里初始化动画?
让脚本找到角色身上的 Animation 组件,以后可以用代码控制它。
csharp
void Start()
{
animation1 = GetComponent<Animation>();
}
核心:如何判断播放什么动画?
代码用 move移动量(move前面已经解释过,是一个Vector3方向向量) 来判断角色是在走还是站着, magnitude是模长:
csharp
if (move.magnitude > 0.1f) // 如果正在移动
{
animation1.Play("walk"); // 播放走路动画
}
else // 如果没移动
{
animation1.Play("wait"); // 播放待机动画
}
最关键的一句:动画是怎么播放的?
播放 Animation 组件里,名字叫 walk 的动画片段。
csharp
animation1.Play("walk");
同理,播放名字叫 wait 的动画。
csharp
animation1.Play("wait");
当游戏运行时,按住左ALT键,可以显示鼠标。