Documentos de Académico
Documentos de Profesional
Documentos de Cultura
This report describes the design and implementation of a 3D game called Maze
Runner. The game is created using Unity-3D where the player works his/her way
through a maze consisting eight rooms. Each room introduces certain tasks the
player must perform in order to progress through the game. The objective of the
game is to navigate through the maze and perform the tasks required to reach
the final room and win the game.
Table of Content
ABSTRACT .....................................................................................................................
Table of Content ..............................................................................................................
List of Figures ..................................................................................................................
1.0 INTRODUCTION ......................................................................................................
2.0 GAME OVERVIEW ..................................................................................................
2.1 Game Concept and Goals .......................................................................................
2.2 User Controls ..........................................................................................................
2.3 Scene layout ............................................................................................................
3.0 SOFTWARE ARCHITECTURE ...............................................................................
4.0 MAIN FEATURES ....................................................................................................
4.1 Basic Features .........................................................................................................
4.2 Advanced Features ...............................................................................................
5.0 GAME DESCRIPTION ...........................................................................................
5.1 3D Maze ............................................................................................................
5.2 Rooms ................................................................................................................
6.0 DIFFICULTIES FACED ..........................................................................................
7.0 FUTURE IMPROVEMENTS ..................................................................................
8.0 CONCLUSION .......................................................................................................
Reference.....................................................................................................
List of Figures
1.0
INTRODUCTION
Creating a 3D game in Unity-3D is both challenging and rewarding. There
are many resources and libraries available to create a very realistic and
high-end video game. We were able to make use of these resources to
create a 3D maze game called the Maze Runner. This game requires
navigating through a 3D maze as well as solving riddles and puzzles to
finish the game. By implementing advanced features, the overall game
play quality went up as well as the look and feel of the game. We learned
all the basics to designing and implementing a 3D game in Unity-3D as
well as some of the more advanced techniques used when creating such a
game. Much of our time was spent on adding features to the game as well
as improving the storyline of the game. We were able to create an
interesting game that was a mix of 3D maze game and other role playing
games.
2.0
GAME OVERVIEW
The game idea chosen for our project is a 3D maze. The first reason behind this
decision is that in a 3d maze we can explore any area we would like to develop
models for. We can construct furniture, animals, space objects, wizards, different
themes in different rooms. The idea seemed very practical for this project, and
left a large room for creativity. The second reason we all unanimously accepted
this idea is that we were all apparently affected by games of this style such as
Final Fantasy, Resident Evil etc... The idea behind the game is to make the maze
full of puzzles and mysterious themes.
8.0
CONCLUSION
Time Module:
using UnityEngine;
using System.Collections;
public class timer : MonoBehaviour {
float timeRemaining=30;
void Start () {
}
void Update () {
timeRemaining -= Time.deltaTime;
}
void OnGUI(){
if (timeRemaining>0){
GUI.Label (new Rect (100, 100, 200,100),"TimeRemaining = "+
(int)timeRemaining);
}
else{
GUI.Label (new Rect (100, 100, 100, 100), " Game Over ");
}
}
}
Camera control:
using UnityEngine;
using System.Collections;
public class cameracontroller : MonoBehaviour {
public GameObject player;
private Vector3 offset;
void Start () {
}
void LateUpdate () {
}
Door Module:
using UnityEngine;
using System.Collections;
using System;
public class doors : MonoBehaviour {
Animator animator;
bool DoorOpen;
void Start(){
DoorOpen = false;
animator = GetComponent<Animator> ();
}
void OnTriggerEnter(Collider other){
if (other.gameObject.tag == "Player") {
DoorOpen = true;
door ("Open");
}
}
void OnTriggerExit(Collider other)
{
if (DoorOpen) {
DoorOpen = false;
door ("Close");
}
}
void door(String direction)
{
animator.SetTrigger(direction);
}
}
Pickup Module:
using UnityEngine;
using System.Collections;
public class PickUp : MonoBehaviour {
void Update () {
transform.Rotate (new Vector3 (0, 180,0 )*Time.deltaTime);
}
}
using System;
using System.Collections;
using UnityEngine;
namespace UnityStandardAssets.Utility
{
public class DragRigidbody : MonoBehaviour
{
const float k_Spring = 50.0f;
const float k_Damper = 5.0f;
const float k_Drag = 10.0f;
const float k_AngularDrag = 5.0f;
const float k_Distance = 0.2f;
const bool k_AttachToCenterOfMass = false;
private SpringJoint m_SpringJoint;
private void Update()
{
// Make sure the user pressed the mouse down
if (!Input.GetMouseButtonDown(0))
{
return;
}
Camera Refocus:
using System;
using UnityEngine;
namespace UnityStandardAssets.Utility
{
public class CameraRefocus
{
public Camera Camera;
public Vector3 Lookatpoint;
public Transform Parent;
private Vector3 m_OrigCameraPos;
private bool m_Refocus;
public CameraRefocus(Camera camera, Transform parent, Vector3 ori
gCameraPos)
{
m_OrigCameraPos = origCameraPos;
Camera = camera;
Parent = parent;
}
public void ChangeCamera(Camera camera)
{
Camera = camera;
}
public void ChangeParent(Transform parent)
{
Parent = parent;
}
public void GetFocusPoint()
{
RaycastHit hitInfo;
if (Physics.Raycast(Parent.transform.position + m_OrigCameraPos,
Parent.transform.forward, out hitInfo,
100f))
{
Lookatpoint = hitInfo.point;
m_Refocus = true;
return;
}
m_Refocus = false;
}
public void SetFocusPoint()
{
if (m_Refocus)
{
Camera.transform.LookAt(Lookatpoint);
}
}
}
}
Mouse Look:
using System;
using UnityEngine;
using UnityStandardAssets.CrossPlatformInput;
namespace UnityStandardAssets.Characters.FirstPerson
{
[Serializable]
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") * XSe
nsitivity;
float xRot = CrossPlatformInputManager.GetAxis("Mouse Y") * YSe
nsitivity;
m_CharacterTargetRot *= Quaternion.Euler (0f, yRot, 0f);
m_CameraTargetRot *= Quaternion.Euler (-xRot, 0f, 0f);
if(clampVerticalRotation)
m_CameraTargetRot = ClampRotationAroundXAxis (m_CameraTa
rgetRot);
if(smooth)
{
character.localRotation = Quaternion.Slerp (character.localRotati
on, 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;
}
}
}
void Start()
{
m_Animator = GetComponent<Animator>();
m_Rigidbody = GetComponent<Rigidbody>();
m_Capsule = GetComponent<CapsuleCollider>();
m_CapsuleHeight = m_Capsule.height;
m_CapsuleCenter = m_Capsule.center;
m_Rigidbody.constraints = RigidbodyConstraints.FreezeRotationX |
RigidbodyConstraints.FreezeRotationY | RigidbodyConstraints.FreezeRotati
onZ;
m_OrigGroundCheckDistance = m_GroundCheckDistance;
}
public void Move(Vector3 move, bool crouch, bool jump)
{
// convert the world relative moveInput vector into a local-relative
// turn amount and forward amount required to head in the desired
// direction.
if (move.magnitude > 1f) move.Normalize();
move = transform.InverseTransformDirection(move);
CheckGroundStatus();
move = Vector3.ProjectOnPlane(move, m_GroundNormal);
m_TurnAmount = Mathf.Atan2(move.x, move.z);
m_ForwardAmount = move.z;
ApplyExtraTurnRotation();
// control and velocity handling is different when grounded and air
borne:
if (m_IsGrounded)
{
HandleGroundedMovement(crouch, jump);
}
else
{
HandleAirborneMovement();
}
ScaleCapsuleForCrouching(crouch);
PreventStandingInLowHeadroom();
// send input and other state parameters to the animator
UpdateAnimator(move);
}
RaycastHit hitInfo;
#if UNITY_EDITOR
// helper to visualise the ground check ray in the scene view
Debug.DrawLine(transform.position + (Vector3.up * 0.1f), transfor
m.position + (Vector3.up * 0.1f) + (Vector3.down * m_GroundCheckDistan
ce));
#endif
// 0.1f is a small offset to start the ray from inside the character
// it is also good to note that the transform position in the sample
assets is at the base of the character
if (Physics.Raycast(transform.position + (Vector3.up * 0.1f), Vector
3.down, out hitInfo, m_GroundCheckDistance))
{
m_GroundNormal = hitInfo.normal;
m_IsGrounded = true;
m_Animator.applyRootMotion = true;
}
else
{
m_IsGrounded = false;
m_GroundNormal = Vector3.up;
m_Animator.applyRootMotion = false;
}
}}}}
e(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 ti
me 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 chara
cter
public float slowDownRate = 20f; // rate at which the controller co
mes to a stop when there is no input
public bool airControl; // can the user control the direction that is b
eing 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 g
etting stuck in wall (a value of 0.1f is nice)
}
public Camera cam;
public MovementSettings movementSettings = new MovementSettin
gs();
public MouseLook mouseLook = new MouseLook();
public AdvancedSettings advancedSettings = new AdvancedSettings(
);
private
private
private
private
private
Rigidbody m_RigidBody;
CapsuleCollider m_Capsule;
float m_YRotation;
Vector3 m_GroundContactNormal;
bool m_Jump, m_PreviouslyGrounded, m_Jumping, m_IsGroun
ded;
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 th
at it being aimed at
Vector3 desiredMove = cam.transform.forward*input.y + cam.tr
ansform.right*input.x;
desiredMove = Vector3.ProjectOnPlane(desiredMove, m_Ground
ContactNormal).normalized;
desiredMove.x = desiredMove.x*movementSettings.CurrentTarg
etSpeed;
desiredMove.z = desiredMove.z*movementSettings.CurrentTarg
etSpeed;
desiredMove.y = desiredMove.y*movementSettings.CurrentTarg
etSpeed;
if (m_RigidBody.velocity.sqrMagnitude <
(movementSettings.CurrentTargetSpeed*movementSettings.C
urrentTargetSpeed))
{
m_RigidBody.AddForce(desiredMove*SlopeMultiplier(), ForceM
ode.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.Ju
mpForce, 0f), ForceMode.Impulse);
m_Jumping = true;
}
if (!m_Jumping && Mathf.Abs(input.x) < float.Epsilon && Math
f.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, ~0,
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 t
he character is looking
Quaternion velRotation = Quaternion.AngleAxis(transform.euler
Menu Module:
using UnityEngine;
using System.Collections;
using UnityEngine.SceneManagement;
public class MenuObject : MonoBehaviour
{
public bool isQuit = false;
public Renderer rend;
void start(){
rend.GetComponent<Renderer> ();
}
void OnMouseEnter()
{
rend.material.color = Color.red;
}
void OnMouseExit()
{
rend.material.color= Color.black;
}
void OnMouseDown()
{
if (isQuit){
Application.Quit();
}
else
{
SceneManager.LoadScene(1);
rend.material.color= Color.white;
}
}}
Scene1
topview of the design of the Central
maze--
Scripts
For Rotating Coins during playmode.
using UnityEngine;
using System.Collections;
using System.Threading;
public class PickUp : MonoBehaviour {
void Update () {
transform.Rotate (new Vector3 (0, 360,0 )
*Time.deltaTime);
}
}
TimeController
using
using
using
using
using
using
UnityEngine;
UnityEngine.UI;
System.Collections;
System.Globalization;
System.Threading;
System;
UnityEngine;
System.Collections;
System;
UnityStandardAssets.Utility;
DoorOpen = false;
animator = GetComponent<Animator> ();
}
void OnTriggerEnter(Collider other){
if (other.gameObject.tag == "Player") {
DoorOpen = true;
door ("Open");
}
}
void OnTriggerExit(Collider other)
{
if (DoorOpen) {
DoorOpen = false;
door ("Close");
}
}
void door(String direction)
{
animator.SetTrigger(direction);
}
}