运维开发网

3D迷宫游戏示例代码

运维开发网 https://www.qedev.com 2022-08-18 19:54 出处:网络
迷宫游戏作为经典的小游戏,一直深受大家的喜爱。本文小编将为大家详细介绍一下如何用Unity实现一个3D版的迷宫小游戏,感兴趣的可以动手试一试

迷宫游戏作为经典的小游戏,一直深受大家的喜爱。本文小编将为大家详细介绍一下如何用Unity实现一个3D版的迷宫小游戏,感兴趣的可以动手试一试


一、前言

闲来无事的时候,从头开始整个3D迷宫游戏。

本文将详细介绍构想和实现思路,希望对有缘人有所帮助。


二、构思

首先,要实现一个小游戏,你脑子里要有一个大概的想法,然后再去完善它。

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

当然,这是一个原型。比如可以添加一些音效、背景、关卡、解密等。

然后整理出的实现思路是:

构建3D迷宫实现人物移动实现出入口逻辑

好了,官方的发展会跟上。


三、正式开发


3-1、搭建场景

首先,创建一个新项目。我用的是Unity 2019.4.7f1的版本项目名称和位置可以根据自己的喜好设置:



接下来,建造一个迷宫。首先,创建一个新的平面,使其足够大,并将其扩展10倍:

创建一个新的立方体,调整它的大小使它看起来像一面墙,然后建立一个迷宫:



3-2、设置出入口


放置两个立方体,设置缩放比例,并将出口的名称改为Exit。就是这样。然后,通过碰撞检测来检测球是否到达出口就足够了。


3-3、添加角色

在层次视图中,右键单击并选择3dobjcaterar胶囊,创建一个新的球体并添加Rigibody组件:


将拖曳掣点设定为1。

设置它只需要这么多。在实际操作中,如果参数不合适,可以重新调整。

将球移到入口位置。


3-4、实现角色移动

这里直接使用官方第一人称移动代码rigidibodyfirstperson controller . 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 gt; 0 || input.x lt; 0){//strafeCurrentTargetSpeed = StrafeSpeed;}if (input.y lt; 0){//backwardsCurrentTargetSpeed = BackwardSpeed;}if (input.y gt; 0){//forwards//handled last as if strafing and moving forward at the same time forwards speed should take precedenceCurrentTargetSpeed = 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_INPUTreturn movementSettings.Running;#else return false;#endif } } private void Start() { m_RigidBody = GetComponentlt;Rigidbodygt;(); m_Capsule = GetComponentlt;CapsuleCollidergt;(); mouseLook.Init (transform, cam.transform); } private void Update() { RotateView(); if (CrossPlatformInputManager.GetButtonDown("Jump") amp;amp; !m_Jump) { m_Jump = true; } } private void FixedUpdate() { GroundCheck(); Vector2 input = GetInput(); if ((Mathf.Abs(input.x) gt; float.Epsilon || Mathf.Abs(input.y) gt; float.Epsilon) amp;amp; (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 lt; (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 amp;amp; Mathf.Abs(input.x) lt; float.Epsilon amp;amp; Mathf.Abs(input.y) lt; float.Epsilon amp;amp; m_RigidBody.velocity.magnitude lt; 1f) { m_RigidBody.Sleep(); } } else { m_RigidBody.drag = 0f; if (m_PreviouslyGrounded amp;amp; !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)) lt; 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) lt; 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 amp;amp; m_IsGrounded amp;amp; 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 amp; 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; } }

将所有墙的父对象设置为地板。

设定摄影机的位置和父对象:


运行程序:



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); } }}

将代码附加到出口对象。

结束了。


四、总结

本文实现了一个3D迷宫游戏。

先设置场景,再实现角色动作,出场出场逻辑。

全天代码简单,官方手机代码也可以学。

以上是基于Unity3D实现3D迷宫游戏的样例代码的详细内容。更多Unity3D迷宫游戏信息

0

精彩评论

暂无评论...
验证码 换一张
取 消