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

在这里插入图片描述

Player脚本

在脚本中通过chracter controller 控制移动
​​​​​​​​​​​​​​​​​​​​​在这里插入图片描述

代码依靠 CharacterController + 相机朝向,实现跟着镜头方向走(WASD 前后左右)。


1. 获取输入方向

float horizontal = Input.GetAxis("Horizontal"); // A/D、左右箭头:-1 ~ 1
float vertical = Input.GetAxis("Vertical");     // W/S、上下箭头:-1 ~ 1
  • Horizontal:左右轴,A=-1、D=1、无按键=0
  • Vertical:前后轴,W=1、S=-1、无按键=0
    这一步拿到玩家按键的偏移值

2. 对齐相机方向(关键:跟着镜头走)

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. 合成最终移动方向

Vector3 move = cameraForward * vertical + cameraRight * horizontal;

公式理解:

  • 相机前方向 × 前后按键(W/S) = 相对镜头前后
  • 相机右方向 × 左右按键(A/D) = 相对镜头左右
    两者相加,得到基于相机视角的整体移动方向

4. 执行移动(核心运动函数)

controller.SimpleMove(move * moveSpeed);
  • move * moveSpeed:方向 × 移动速度,算出最终移动矢量
  • CharacterController.SimpleMove()
    自带重力、碰撞检测,直接让角色沿目标方向移动,不用自己算位移。
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脚本中使用角色动画资源

定义动画组件
private Animation animation1;
  • 这是 Unity 旧版动画系统 Animation 组件
  • 角色身上已经挂载了这个组件,并放入:
    • 走路动画(名字叫 walk
    • 待机动画(名字叫 wait

代码在哪里初始化动画?

让脚本找到角色身上的 Animation 组件,以后可以用代码控制它。

void Start()
{
    animation1 = GetComponent<Animation>(); 
}

核心:如何判断播放什么动画?

代码用 move移动量(move前面已经解释过,是一个Vector3方向向量) 来判断角色是在走还是站着, magnitude是模长:

if (move.magnitude > 0.1f)  // 如果正在移动
{
    animation1.Play("walk"); // 播放走路动画
}
else                       // 如果没移动
{
    animation1.Play("wait"); // 播放待机动画
}

最关键的一句:动画是怎么播放的?

播放 Animation 组件里,名字叫 walk 的动画片段。

animation1.Play("walk");

同理,播放名字叫 wait 的动画。

animation1.Play("wait");

当游戏运行时,按住左ALT键,可以显示鼠标。

画作显示

点击画作弹出相应的介绍,代码放在PlayerCamera里面。

制作画像UI展示

创建一个UI Canvas
在这里插入图片描述
然后在Canvas下创建两个UI image, 分别将画作和背景画框的图片改为 2D和UI模式,分别拖动到两个image上,改变两幅图的顺序来改变层级关系,使画框作为背景显示。
在这里插入图片描述
在这里插入图片描述
等比例的显示。
在这里插入图片描述

制作画像UI的放大显示

创建一个空物体,将刚刚的两个空物体拖动到空物体下。通过判断名字来显示和隐藏游戏物体。
在脚本中创建一个数组,储存gameobject,写一个函数,可以根据传入的字符串,控制数组中的其中一个显示,其余隐藏。
在Inspector面板显示数组中的gameobject,将刚刚创建的空物体画作拖动过来,此时数组中的gameobject显示为1。
在这里插入图片描述
在下面的脚本中通过空物体的名字控制画作介绍的显示与隐藏。
在这里插入图片描述

设置文字

创建UI text文本
在这里插入图片描述

拖动 text框 至合适大小,在右侧Text组件中编辑文字。
在这里插入图片描述
调整字体大小,可以给字体添加Shadow组件,增加阴影效果。其次,也可以调整文字颜色。
在这里插入图片描述

设置退出按钮

在空物体下创建一个Button, 编辑下面自带的子物体Text为X。
在这里插入图片描述

进一步设置点击X按钮,关闭画作介绍。

在脚本中写一个 CloseArt方法,调用HideAll() 方法。
在这里插入图片描述
将画布拖动到Button的 鼠标点击 On Click中,并选择方法为CloseArt()。
在这里插入图片描述
在这里插入图片描述
此时,点击X,可以关闭画布。

制作多个UI

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐