推荐阅读

  • CSDN主页
  • GitHub开源地址
  • Unity3D插件分享
  • 简书地址
  • 我的个人博客
  • QQ群:1040082875

大家好,我是佛系工程师☆恬静的小魔龙☆,不定时更新Unity开发技巧,觉得有用记得一键三连哦。

一、前言

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

本篇文章会详细介绍构思、实现思路,希望可以帮助到有缘人。

二、构思

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

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

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

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

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

OK,下面就正式开发。

三、正式开发

3-1、搭建场景

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

接下来构建迷宫,先新建一个Plane,让它最够大,扩大10倍:
新建Cube,调整大小缩放,让它看起来像是一堵墙,然后构建迷宫:

3-2、设置出入口


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

3-3、添加角色

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

设置Drag抓地力为1。

就这样设置就行了,在实际运行中如果参数不合适还可以再调整。
将小球移动到入口的位置。

3-4、实现角色移动

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

public class RigidbodyFirstPersonController : MonoBehaviour{[Serializable]public class MovementSettings{public float ForwardSpeed = 8.0f;   // Speed when walking forwardpublic float BackwardSpeed = 4.0f;  // Speed when walking backwardspublic float StrafeSpeed = 4.0f;    // Speed when walking sidewayspublic float RunMultiplier = 2.0f;   // Speed when sprintingpublic 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_INPUTprivate bool m_Running;
#endifpublic void UpdateDesiredTargetSpeed(Vector2 input){if (input == Vector2.zero) return;if (input.x > 0 || input.x < 0){//strafeCurrentTargetSpeed = StrafeSpeed;}if (input.y < 0){//backwardsCurrentTargetSpeed = BackwardSpeed;}if (input.y > 0){//forwards//handled last as if strafing and moving forward at the same time forwards speed should take precedenceCurrentTargetSpeed = ForwardSpeed;}
#if !MOBILE_INPUTif (Input.GetKey(RunKey)){CurrentTargetSpeed *= RunMultiplier;m_Running = true;}else{m_Running = false;}
#endif}#if !MOBILE_INPUTpublic 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 characterpublic float slowDownRate = 20f; // rate at which the controller comes to a stop when there is no inputpublic 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;
#elsereturn 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 atVector3 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 pausedif (Mathf.Abs(Time.timeScale) < float.Epsilon) return;// get the rotation before it's changedfloat 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 lookingQuaternion 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 bottomprivate 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 helperCursor.lockState = CursorLockMode.None;Cursor.visible = true;}}public void UpdateCursorLock(){//if the user set "lockCursor" we check & properly lock the cursosif (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);}}
}

将代码附给Exit对象。

结束了。

四、总结

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

首先,搭建场景,然后实现角色移动,出入口逻辑。

整天代码比较简单,官方的移动代码也可以学习一下。

【Unity3D开发小游戏】Unity3D开发《3D迷宫》小游戏相关推荐

  1. 小虫子的冒险_Python迷宫类型游戏

    这是一个用Python制作的迷宫游戏,需要基于Python海龟画图模块精灵模块支持,安装方法为 pip install sprites. 如果安装很慢,请联系李兴球,微信scratch8, 在这个游戏 ...

  2. 微信小游戏|unity搭建3D篮球小游戏场景

    欢迎点击「算法与编程之美」↑关注我们! 本文首发于微信公众号:"算法与编程之美",欢迎关注,及时了解更多此系列文章. 欢迎加入团队圈子!与作者面对面!直接点击! 问题描述 上一次小 ...

  3. html枪战游戏代码大全,3D枪战射击游戏cs简单版源代码

    [实例简介] 3D枪战射击游戏cs简单版源代码,本代码用opengl开发,使用vc6.0适用于初学者 [实例截图] [核心代码] vccs └── vccs ├── CDSound.cpp ├── C ...

  4. 计算机3d 游戏制作,揭秘3D电影、游戏角色的制作过程!

    原标题:揭秘3D电影.游戏角色的制作过程! 从来没有接触过建模的小白们是否都很好奇,3D电影.游戏角色是怎样做出来的呢?比如说<捉妖记>里的胡巴.今年大火的国漫<哪吒>,< ...

  5. android飞行射击游戏代码,android 3D飞行射击游戏《夜鹰行动》源码

    压缩包内容概览: android 3D飞行射击游戏<夜鹰行动>源码-airattacker ; 清单 ; 资产 ; 项目 ; 飞骥11 ; 飞骥22 ; 飞骥33 ; 折叠按钮 ; 弗雷格 ...

  6. 《游戏学习》| 3d网页小游戏 | 公路赛车 源码

    游戏介绍 基于three.js实现的3d网页游戏,适配移动端和pc端网页,可以选择简单.普通.困难.地狱四个游戏难度等级,通过控制左右,超过其他车辆得分. 游戏截图 游戏主页 游戏界面 结束界面 项目 ...

  7. python语言迷宫游戏_一个Python迷宫小游戏

    该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 # 设置屏幕宽度和高度为全局变量 global screen_width screen_width = 800 global screen_height ...

  8. c语言简单射击小游戏源程序,简单的迷宫小游戏 C语言程序源代码

    #include #include #include #include #define Height 31 //迷宫的高度,必须为奇数 #define Width 25 //迷宫的宽度,必须为奇数 # ...

  9. qt 3d迷宫游戏_《加雷利亚的地下迷宫与魔女的旅团》最新情报公布

    日本一旗下最新作品<加雷利亚的地下迷宫与魔女的旅团(Coven and labyrinth of Galleria)>公布了有关本作角色和新登场Facet的最新情报,让我们一起来看看吧! ...

  10. 大型3d射击类游戏源码【突击风暴】,中文版本,可私服

    <突击风暴>(英文名称:Sudden Attack)是由韩国GAMEHI公司制作,盛大游戏运营的第一人称射击类网络游戏.<突击风暴>于2011年6月9日开服,2012年12月3 ...

最新文章

  1. Silverlight中的拖拽实现的图片上传---1
  2. linux elf 文件查看工具 readelf
  3. 微信小程序开发记录一,开发工具的使用
  4. 25个好用到爆的一行Python代码,建议收藏
  5. 前端学习(3303):函数组件组件子组件useRef聚焦
  6. SpannableString与SpannableStringBuilder使用
  7. rtsp,rtp,gb28181直接转化为html5播放(二)
  8. owncloud mysql版本_Linux Deploy Owncloud php7.0+apache2+mysql5.7+owncloud9.1
  9. java计算器课程报告_java课程设计报告计算器设计.doc
  10. 用python实现pdf转word(带格式)_Python 实现加密过的PDF文件转WORD格式
  11. 人行征信报告介绍(一)
  12. linux文件权限数字754,linux555、644、666、755、777权限详解数字代表什么意思
  13. 万字长文讲述:任正非,“血洗”华为
  14. c语言第五章答案许合利,C语言习题答案贾宗璞许合利较全-.doc
  15. ESP8266人体感应项目
  16. AHK 键盘控制鼠标点击屏幕不同位置
  17. 这位闯进程序员界的维密天使,她到底可以编出什么?!
  18. jQuery如何根据元素值删除数组元素
  19. 模块-E18-D80NK红外避障传感器
  20. Android 高质量开发之崩溃优化,2020-2021字节跳动Android面试真题解析

热门文章

  1. Mongodb实战:豆瓣电影排行榜分析及结果展示设计
  2. 抓住暴涨点,通达信洗盘回调介入指标公式图解
  3. 研究生初学机器学习的几点建议
  4. Ubuntu 更改默认浏览器
  5. hexo文章中插入图片
  6. linux tc取消网卡流量限制,Linux高级流量控制tc使用
  7. HTML5 Canvas制作数独游戏(四)
  8. 三维空间中椭圆的参数方程
  9. php 解析lrc文件格式,前端LRC歌词解析播放插件
  10. 随机存取存储器与只读存储器