Unity VRForHK

本文详细介绍了使用Unity引擎开发VR游戏的过程,包括第一人称视角的实现、场景切换、鼠标锁定、按钮交互、动画播放、文字显示及天空盒设置等关键技术。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

和一些小伙伴们一起做了一个关于香港的VR,由于大家之前都没有接触过所以做的比较草率。即使如此,还是学到了不少东西。

1. 第一人称视角

创建一个胶囊(Capsule),重命名为Player,把主摄像机(Main Camera)放到Player下。创建脚本FPSInput,实现可以调节速度的人物移动。代码如下:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class FPSInput : MonoBehaviour
{
    public float speed = 1.0f;
    public float gravity = -9.8f;  //重力

    private float deltaX = 0.0f;
    private float deltaZ = 0.0f;

    private CharacterController _characterController;

    // Start is called before the first frame update
    void Start()
    {
        _characterController = GetComponent<CharacterController>();
    }

    // Update is called once per frame
    void Update()
    {
        deltaX = Input.GetAxis("Horizontal") * speed;
        deltaZ = Input.GetAxis("Vertical") * speed;
        Vector3 movement = new Vector3(deltaX, 0, deltaZ);
        movement = Vector3.ClampMagnitude(movement, speed);
        movement.y = gravity;
        movement *= Time.deltaTime;
        movement = transform.TransformDirection(movement);
        _characterController.Move(movement);
    }
}

在Player下增加组件Character Controller,Rigidbody,把这个脚本放到Player下。这个脚本能够实现角色的移动,但是不能实现视野的变换。新建脚本MouseLook,代码如下:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class MouseLook : MonoBehaviour
{
    public enum RotationAxes
    {
        MouseXAndY = 0,
        MouseX = 1,
        MouseY = 2
    }
    public RotationAxes axes = RotationAxes.MouseXAndY;

    public float sensitivityHor = 9.0f;
    public float sensitivityVert = 9.0f;

    public float minimumVert = -45.0f;
    public float maximumVert = 45.0f;

    private float _rotationX = 0.0f;

    // Start is called before the first frame update
    void Start()
    {
        Rigidbody body = GetComponent<Rigidbody>();
        if (body != null)
        {
            body.freezeRotation = true;
        }
    }

    // Update is called once per frame
    void Update()
    {
        if(axes == RotationAxes.MouseX)
        {
            transform.Rotate(0, Input.GetAxis("Mouse X") * sensitivityHor, 0);
        }
        else if(axes == RotationAxes.MouseY)
        {
            _rotationX -= Input.GetAxis("Mouse Y") * sensitivityVert;
            _rotationX = Mathf.Clamp(_rotationX, minimumVert, maximumVert);

            float rotationY = transform.localEulerAngles.y;

            transform.localEulerAngles = new Vector3(_rotationX, rotationY, 0.0f);
        }
        else
        {
            _rotationX -= Input.GetAxis("Mouse Y") * sensitivityVert;
            _rotationX = Mathf.Clamp(_rotationX, minimumVert, maximumVert);

            float delta = Input.GetAxis("Mouse X") * sensitivityHor;
            float rotationY = transform.localEulerAngles.y + delta;

            transform.localEulerAngles = new Vector3(_rotationX, rotationY, 0.0f);
        }
    }
}

把这个脚本放到Player和Main Camera下,在Player中选择MouseX,使物体只能横向旋转,在Main Camera下选择MouseY,使摄像机只能纵向变换。

2. 场景切换

打开File->Build Setting,添加所有的场景,使所有场景都有属于自己的Build Index。
在这里插入图片描述
新建脚本ChangeScenes,代码如下:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;

public class ChangeScenes : MonoBehaviour
{
    private int ScenesCount = 5;
    private Scene sm;
    // Start is called before the first frame update
    void Start()
    {
        sm = SceneManager.GetActiveScene();
    }

    // Update is called once per frame
    void Update()
    {
        
    }
    private void OnTriggerEnter(Collider other)
    {
        for(int i=0; i<ScenesCount; i++)
        {
            if (other.gameObject.CompareTag(i.ToString()))
            {
                SceneManager.UnloadSceneAsync(i, UnloadSceneOptions.UnloadAllEmbeddedSceneObjects);
                SceneManager.LoadScene(++i, LoadSceneMode.Additive);
                other.gameObject.SetActive(false);
                break;
            }
        }
    }
}

这个脚本的大概意思是走到一个地方检测是否发生碰撞,如果有碰撞检测它的标志(Tag),如果它是我们想要切换到Build Index下一个场景的标志,首先关掉当前场景,然后读取下一个场景,同时使标志物消失防止在读取下一个场景的时间内不断激发此函数从而陷入循环。所以此脚本附在Player下。
设置Tag的方法,可以参考前一篇《滚球游戏》。

3.锁死鼠标

新建脚本附在Main Camera下:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class RayShooter : MonoBehaviour
{
    private Camera _camera;
    // Use this for initialization
    void Start()
    {
        _camera = GetComponent<Camera>();

        //隐藏屏幕中心的光标
        Cursor.lockState = CursorLockMode.Locked;
        Cursor.visible = false;
    }

    private void OnGUI()
    {
        int size = 12;
        float posX = _camera.pixelWidth / 2 - size / 4;
        float posY = _camera.pixelHeight / 2 - size / 2;
        GUI.Label(new Rect(posX, posY, size, size), "*");  //GUI.Label()命令在屏幕上显示文本
    }
    // Update is called once per frame
    void Update()
    {

    }
}

大概意思是将光标锁死在屏幕中心,并且设置不可解。同时利用UI,在屏幕中央打一个" * "。

4.按钮

在本项目中该按钮的作用是从主场景切换到其他场景,其中主场景无法隐藏。在Hierarchy中新建UI->Button,此时会出现Canvas和EventSystem。在Canvas下有Button,再向下有Text,这里是Button中心的文字。新建脚本附在Button下:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.SceneManagement;

public class MajorToTST : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
        GameObject btnObj = GameObject.Find("Button");//"Button"为你的Button的名称
        Button btn = btnObj.GetComponent<Button>();
        btn.onClick.AddListener(delegate ()
        {
            this.GoNextScene(btnObj);
        });
    }

    // Update is called once per frame
    void Update()
    {
        
    }
    public void GoNextScene(GameObject NScene)
    {
        SceneManager.UnloadSceneAsync(0, UnloadSceneOptions.UnloadAllEmbeddedSceneObjects);
        SceneManager.LoadScene(1, LoadSceneMode.Additive);
        NScene.SetActive(false);
    }
}

5.显示动画

在Project页面向右寻找能找到Animation卡片。点击create,保存动画。在时间轴合适的位置创建关键帧,改变物体状态。在Inspector界面下取消Loop Time。附加到你想要的物体上。
在这里插入图片描述
在Project界面下新建Animator Controller,作为该物体Animator组件下Controller选项的内容。在Animator界面下新建空结点:右击 -> Create State -> Empty。右击空结点,选择Set as Layer Default State,然后右击选择Make Transition,指向活动节点。
在这里插入图片描述
在左边设置好Tigger,右边Conditions下面选择这个Trigger。新建脚本附加在Player上,实现碰撞某物后播放动画,代码如下:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class GetTicket : MonoBehaviour
{
    public Animator animator;
    // Start is called before the first frame update
    void Start()
    {

    }

    // Update is called once per frame
    void Update()
    {
        
    }
    private void OnTriggerEnter(Collider other)
    {
        if (other.gameObject.CompareTag("2.1"))
        {
            animator.SetTrigger("ticket");
            other.gameObject.SetActive(false);
        }
    }
}

6.显示文字

新建脚本ShowName,代码如下:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ShowName : MonoBehaviour
{
    public string InGUI;
    public string MousePass;
    bool isShowTip;
    public bool WindowShow = false;
    // Use this for initialization
    void Start()
    {
        isShowTip = false;
    }
    void OnMouseEnter()
    {
        isShowTip = true;

    }
    void OnMouseExit()
    {
        isShowTip = false;
    }
    void OnGUI()
    {
        if (isShowTip)
        {
            GUIStyle style1 = new GUIStyle();
            style1.fontSize = 30;
            style1.normal.textColor = Color.red;
            GUI.Label(new Rect(Input.mousePosition.x, Screen.height - Input.mousePosition.y, 400, 50), MousePass, style1);

        }
        if (WindowShow)
            GUI.Window(0, new Rect(30, 30, 200, 100), MyWindow, "Name");
    }

    //对话框函数
    void MyWindow(int WindowID)
    {
        GUILayout.Label(InGUI);
    }
    //鼠标点击事件
    void OnMouseDown()
    {
        Debug.Log("show");
        if (WindowShow)
            WindowShow = false;
        else
            WindowShow = true;
    }
}

在想要显示的物体上添加Box Collider组件,再附上此文本。MousePass是鼠标滑过是显示的文字,不想显示可以设置为空。InGUI是鼠标点击时的文字,会出现在一个新的GUI界面下,再点击终止显示。

7.天空盒

一般来说,天空盒有两种构造方法,一个是给摄像机加天空盒,一个是给场景加天空盒。在这个项目中我们用的是给相机添加天空盒,这样在切换场景时,不同的摄像机看到的天空时不一样的,避免了场景切换时遗留的天空对下一个场景的影响。

首先新建一个材质Sky,在Inspector界面下找shader,选择skybox。具体的设置可以自由发挥。通常是6个面设置和CubeMap。

7.1 在摄像机中添加天空盒

给摄像机新建一个组件skybox,选择刚刚创建的材质Sky。

7.2 在场景中添加天空盒

不同版本的Unity可能不同,我的时2018.3的版本,他在Window->Rendering->Lighting Setting中,找Skybox Material进行修改。
在这里插入图片描述

参考文献

  1. 鼠标经过或点击显示文字:https://blog.youkuaiyun.com/HanGuangFei/article/details/78094214
  2. 天空盒:https://blog.youkuaiyun.com/www11e/article/details/78765147
  3. 按钮:https://blog.youkuaiyun.com/u014581901/article/details/51325955
项目位置:https://github.com/lyksunny/CCHU9056
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

73826669

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值