温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

Unity怎么实现3D迷宫小游戏

发布时间:2022-03-05 16:09:52 来源:亿速云 阅读:242 作者:iii 栏目:开发技术

这篇文章主要介绍了Unity怎么实现3D迷宫小游戏的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇Unity怎么实现3D迷宫小游戏文章都会有所收获,下面我们一起来看看吧。

    一、前言

    闲来无事,从零开始整个《3D迷宫》小游戏。

    二、构思

    首先,要实现一个小游戏,心里肯定要有一个大概的想法,然后就是将想法完善起来。

    我的想法就是一个用立体的墙搭建的迷宫,然后控制人物在迷宫中移动,最后找到出口,就这么简单。

    当然,这是一个雏形,比如可以加点音效、背景、关卡、解密等。

    那么整理一下实现思路就是:

    • 构建3D迷宫

    • 实现人物移动

    • 实现出入口逻辑

    OK,下面就正式开发。

    三、正式开发

    3-1、搭建场景

    首先,新建个项目,我用了Unity 2019.4.7f1版本,项目名称跟位置按照自己的喜好设置即可:

    Unity怎么实现3D迷宫小游戏

    Unity怎么实现3D迷宫小游戏

    接下来构建迷宫,先新建一个Plane,让它最够大,扩大10倍:

    新建Cube,调整大小缩放,让它看起来像是一堵墙,然后构建迷宫:

    Unity怎么实现3D迷宫小游戏

    3-2、设置出入口

    Unity怎么实现3D迷宫小游戏

    放两个Cube,设置缩放,将出口名字改成Exit,这样就行了,到时候通过碰撞检测检测小球是否到达出口即可。

    3-3、添加角色

    在Hierarchy视图,右击选择3D Objcet→Capsule,新建一个球体,添加Rigibody组件:

    Unity怎么实现3D迷宫小游戏

    设置Drag抓地力为1。

    就这样设置就行了,在实际运行中如果参数不合适还可以再调整。

    将小球移动到入口的位置。

    3-4、实现角色移动

    这里直接使用官方的第一人称移动代码RigidbodyFirstPersonController .cs:

    public class RigidbodyFirstPersonController : MonoBehaviour
        {
            [Serializable]
            public class MovementSettings
            {
                public float ForwardSpeed = 8.0f;   // Speed when walking forward
                public float BackwardSpeed = 4.0f;  // Speed when walking backwards
                public float StrafeSpeed = 4.0f;    // Speed when walking sideways
                public float RunMultiplier = 2.0f;   // Speed when sprinting
    	        public KeyCode RunKey = KeyCode.LeftShift;
                public float JumpForce = 30f;
                public AnimationCurve SlopeCurveModifier = new AnimationCurve(new Keyframe(-90.0f, 1.0f), new Keyframe(0.0f, 1.0f), new Keyframe(90.0f, 0.0f));
                [HideInInspector] public float CurrentTargetSpeed = 8f;
    
    #if !MOBILE_INPUT
                private bool m_Running;
    #endif
    
                public void UpdateDesiredTargetSpeed(Vector2 input)
                {
    	            if (input == Vector2.zero) return;
    				if (input.x > 0 || input.x < 0)
    				{
    					//strafe
    					CurrentTargetSpeed = StrafeSpeed;
    				}
    				if (input.y < 0)
    				{
    					//backwards
    					CurrentTargetSpeed = BackwardSpeed;
    				}
    				if (input.y > 0)
    				{
    					//forwards
    					//handled last as if strafing and moving forward at the same time forwards speed should take precedence
    					CurrentTargetSpeed = ForwardSpeed;
    				}
    #if !MOBILE_INPUT
    	            if (Input.GetKey(RunKey))
    	            {
    		            CurrentTargetSpeed *= RunMultiplier;
    		            m_Running = true;
    	            }
    	            else
    	            {
    		            m_Running = false;
    	            }
    #endif
                }
    
    #if !MOBILE_INPUT
                public bool Running
                {
                    get { return m_Running; }
                }
    #endif
            }
    
    
            [Serializable]
            public class AdvancedSettings
            {
                public float groundCheckDistance = 0.01f; // distance for checking if the controller is grounded ( 0.01f seems to work best for this )
                public float stickToGroundHelperDistance = 0.5f; // stops the character
                public float slowDownRate = 20f; // rate at which the controller comes to a stop when there is no input
                public bool airControl; // can the user control the direction that is being moved in the air
                [Tooltip("set it to 0.1 or more if you get stuck in wall")]
                public float shellOffset; //reduce the radius by that ratio to avoid getting stuck in wall (a value of 0.1f is nice)
            }
    
    
            public Camera cam;
            public MovementSettings movementSettings = new MovementSettings();
            public MouseLook mouseLook = new MouseLook();
            public AdvancedSettings advancedSettings = new AdvancedSettings();
    
    
            private Rigidbody m_RigidBody;
            private CapsuleCollider m_Capsule;
            private float m_YRotation;
            private Vector3 m_GroundContactNormal;
            private bool m_Jump, m_PreviouslyGrounded, m_Jumping, m_IsGrounded;
    
    
            public Vector3 Velocity
            {
                get { return m_RigidBody.velocity; }
            }
    
            public bool Grounded
            {
                get { return m_IsGrounded; }
            }
    
            public bool Jumping
            {
                get { return m_Jumping; }
            }
    
            public bool Running
            {
                get
                {
     #if !MOBILE_INPUT
    				return movementSettings.Running;
    #else
    	            return false;
    #endif
                }
            }
    
    
            private void Start()
            {
                m_RigidBody = GetComponent<Rigidbody>();
                m_Capsule = GetComponent<CapsuleCollider>();
                mouseLook.Init (transform, cam.transform);
            }
    
    
            private void Update()
            {
                RotateView();
    
                if (CrossPlatformInputManager.GetButtonDown("Jump") && !m_Jump)
                {
                    m_Jump = true;
                }
            }
    
    
            private void FixedUpdate()
            {
                GroundCheck();
                Vector2 input = GetInput();
    
                if ((Mathf.Abs(input.x) > float.Epsilon || Mathf.Abs(input.y) > float.Epsilon) && (advancedSettings.airControl || m_IsGrounded))
                {
                    // always move along the camera forward as it is the direction that it being aimed at
                    Vector3 desiredMove = cam.transform.forward*input.y + cam.transform.right*input.x;
                    desiredMove = Vector3.ProjectOnPlane(desiredMove, m_GroundContactNormal).normalized;
    
                    desiredMove.x = desiredMove.x*movementSettings.CurrentTargetSpeed;
                    desiredMove.z = desiredMove.z*movementSettings.CurrentTargetSpeed;
                    desiredMove.y = desiredMove.y*movementSettings.CurrentTargetSpeed;
                    if (m_RigidBody.velocity.sqrMagnitude <
                        (movementSettings.CurrentTargetSpeed*movementSettings.CurrentTargetSpeed))
                    {
                        m_RigidBody.AddForce(desiredMove*SlopeMultiplier(), ForceMode.Impulse);
                    }
                }
    
                if (m_IsGrounded)
                {
                    m_RigidBody.drag = 5f;
    
                    if (m_Jump)
                    {
                        m_RigidBody.drag = 0f;
                        m_RigidBody.velocity = new Vector3(m_RigidBody.velocity.x, 0f, m_RigidBody.velocity.z);
                        m_RigidBody.AddForce(new Vector3(0f, movementSettings.JumpForce, 0f), ForceMode.Impulse);
                        m_Jumping = true;
                    }
    
                    if (!m_Jumping && Mathf.Abs(input.x) < float.Epsilon && Mathf.Abs(input.y) < float.Epsilon && m_RigidBody.velocity.magnitude < 1f)
                    {
                        m_RigidBody.Sleep();
                    }
                }
                else
                {
                    m_RigidBody.drag = 0f;
                    if (m_PreviouslyGrounded && !m_Jumping)
                    {
                        StickToGroundHelper();
                    }
                }
                m_Jump = false;
            }
    
    
            private float SlopeMultiplier()
            {
                float angle = Vector3.Angle(m_GroundContactNormal, Vector3.up);
                return movementSettings.SlopeCurveModifier.Evaluate(angle);
            }
    
    
            private void StickToGroundHelper()
            {
                RaycastHit hitInfo;
                if (Physics.SphereCast(transform.position, m_Capsule.radius * (1.0f - advancedSettings.shellOffset), Vector3.down, out hitInfo,
                                       ((m_Capsule.height/2f) - m_Capsule.radius) +
                                       advancedSettings.stickToGroundHelperDistance, Physics.AllLayers, QueryTriggerInteraction.Ignore))
                {
                    if (Mathf.Abs(Vector3.Angle(hitInfo.normal, Vector3.up)) < 85f)
                    {
                        m_RigidBody.velocity = Vector3.ProjectOnPlane(m_RigidBody.velocity, hitInfo.normal);
                    }
                }
            }
    
    
            private Vector2 GetInput()
            {
                
                Vector2 input = new Vector2
                    {
                        x = CrossPlatformInputManager.GetAxis("Horizontal"),
                        y = CrossPlatformInputManager.GetAxis("Vertical")
                    };
    			movementSettings.UpdateDesiredTargetSpeed(input);
                return input;
            }
    
    
            private void RotateView()
            {
                //avoids the mouse looking if the game is effectively paused
                if (Mathf.Abs(Time.timeScale) < float.Epsilon) return;
    
                // get the rotation before it's changed
                float oldYRotation = transform.eulerAngles.y;
    
                mouseLook.LookRotation (transform, cam.transform);
    
                if (m_IsGrounded || advancedSettings.airControl)
                {
                    // Rotate the rigidbody velocity to match the new direction that the character is looking
                    Quaternion velRotation = Quaternion.AngleAxis(transform.eulerAngles.y - oldYRotation, Vector3.up);
                    m_RigidBody.velocity = velRotation*m_RigidBody.velocity;
                }
            }
    
            /// sphere cast down just beyond the bottom of the capsule to see if the capsule is colliding round the bottom
            private void GroundCheck()
            {
                m_PreviouslyGrounded = m_IsGrounded;
                RaycastHit hitInfo;
                if (Physics.SphereCast(transform.position, m_Capsule.radius * (1.0f - advancedSettings.shellOffset), Vector3.down, out hitInfo,
                                       ((m_Capsule.height/2f) - m_Capsule.radius) + advancedSettings.groundCheckDistance, Physics.AllLayers, QueryTriggerInteraction.Ignore))
                {
                    m_IsGrounded = true;
                    m_GroundContactNormal = hitInfo.normal;
                }
                else
                {
                    m_IsGrounded = false;
                    m_GroundContactNormal = Vector3.up;
                }
                if (!m_PreviouslyGrounded && m_IsGrounded && m_Jumping)
                {
                    m_Jumping = false;
                }
            }
        }

    MouseLook.cs:

    public class MouseLook
        {
            public float XSensitivity = 2f;
            public float YSensitivity = 2f;
            public bool clampVerticalRotation = true;
            public float MinimumX = -90F;
            public float MaximumX = 90F;
            public bool smooth;
            public float smoothTime = 5f;
            public bool lockCursor = true;
    
    
            private Quaternion m_CharacterTargetRot;
            private Quaternion m_CameraTargetRot;
            private bool m_cursorIsLocked = true;
    
            public void Init(Transform character, Transform camera)
            {
                m_CharacterTargetRot = character.localRotation;
                m_CameraTargetRot = camera.localRotation;
            }
    
    
            public void LookRotation(Transform character, Transform camera)
            {
                float yRot = CrossPlatformInputManager.GetAxis("Mouse X") * XSensitivity;
                float xRot = CrossPlatformInputManager.GetAxis("Mouse Y") * YSensitivity;
    
                m_CharacterTargetRot *= Quaternion.Euler (0f, yRot, 0f);
                m_CameraTargetRot *= Quaternion.Euler (-xRot, 0f, 0f);
    
                if(clampVerticalRotation)
                    m_CameraTargetRot = ClampRotationAroundXAxis (m_CameraTargetRot);
    
                if(smooth)
                {
                    character.localRotation = Quaternion.Slerp (character.localRotation, m_CharacterTargetRot,
                        smoothTime * Time.deltaTime);
                    camera.localRotation = Quaternion.Slerp (camera.localRotation, m_CameraTargetRot,
                        smoothTime * Time.deltaTime);
                }
                else
                {
                    character.localRotation = m_CharacterTargetRot;
                    camera.localRotation = m_CameraTargetRot;
                }
    
                UpdateCursorLock();
            }
    
            public void SetCursorLock(bool value)
            {
                lockCursor = value;
                if(!lockCursor)
                {//we force unlock the cursor if the user disable the cursor locking helper
                    Cursor.lockState = CursorLockMode.None;
                    Cursor.visible = true;
                }
            }
    
            public void UpdateCursorLock()
            {
                //if the user set "lockCursor" we check & properly lock the cursos
                if (lockCursor)
                    InternalLockUpdate();
            }
    
            private void InternalLockUpdate()
            {
                if(Input.GetKeyUp(KeyCode.Escape))
                {
                    m_cursorIsLocked = false;
                }
                else if(Input.GetMouseButtonUp(0))
                {
                    m_cursorIsLocked = true;
                }
    
                if (m_cursorIsLocked)
                {
                    Cursor.lockState = CursorLockMode.Locked;
                    Cursor.visible = false;
                }
                else if (!m_cursorIsLocked)
                {
                    Cursor.lockState = CursorLockMode.None;
                    Cursor.visible = true;
                }
            }
    
            Quaternion ClampRotationAroundXAxis(Quaternion q)
            {
                q.x /= q.w;
                q.y /= q.w;
                q.z /= q.w;
                q.w = 1.0f;
    
                float angleX = 2.0f * Mathf.Rad2Deg * Mathf.Atan (q.x);
    
                angleX = Mathf.Clamp (angleX, MinimumX, MaximumX);
    
                q.x = Mathf.Tan (0.5f * Mathf.Deg2Rad * angleX);
    
                return q;
            }
    
        }

    将所有的墙的父物体设置为地板。

    设置摄像机的位置和父物体:

    Unity怎么实现3D迷宫小游戏

    运行程序:

    Unity怎么实现3D迷宫小游戏

    3-5、出入口逻辑

    出口用碰撞检测,新建脚本ExitControl.cs,编辑代码:

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.SceneManagement;
    
    public class ExitControl : MonoBehaviour
    {
        void OnCollisionEnter(Collider col)
        {
            if (col.gameObject.name == "Capsule")
            {
                SceneManager.LoadScene(SceneManager.GetActiveScene().name);
            }
        }
    }

    关于“Unity怎么实现3D迷宫小游戏”这篇文章的内容就介绍到这里,感谢各位的阅读!相信大家对“Unity怎么实现3D迷宫小游戏”知识都有一定的了解,大家如果还想学习更多知识,欢迎关注亿速云行业资讯频道。

    向AI问一下细节

    免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

    AI