Add CT3536 Games Programming
BIN
third/semester1/CT3536: Games Programming/notes/CT3536-Notes.pdf
Normal file
991
third/semester1/CT3536: Games Programming/notes/CT3536-Notes.tex
Normal file
@ -0,0 +1,991 @@
|
||||
%! TeX program = lualatex
|
||||
\documentclass[a4paper,11pt]{article}
|
||||
% packages
|
||||
\usepackage{fontspec}
|
||||
\setmainfont{EB Garamond}
|
||||
% for tironian et fallback
|
||||
% % \directlua{luaotfload.add_fallback
|
||||
% % ("emojifallback",
|
||||
% % {"Noto Serif:mode=harf"}
|
||||
% % )}
|
||||
% % \setmainfont{EB Garamond}[RawFeature={fallback=emojifallback}]
|
||||
|
||||
\setmonofont[Scale=MatchLowercase]{Deja Vu Sans Mono}
|
||||
\usepackage[a4paper,left=2cm,right=2cm,top=\dimexpr15mm+1.5\baselineskip,bottom=2cm]{geometry}
|
||||
\setlength{\parindent}{0pt}
|
||||
|
||||
\usepackage{fancyhdr} % Headers and footers
|
||||
\fancyhead[R]{\normalfont \leftmark}
|
||||
\fancyhead[L]{}
|
||||
\pagestyle{fancy}
|
||||
|
||||
\usepackage{multicol}
|
||||
\usepackage{microtype} % Slightly tweak font spacing for aesthetics
|
||||
\usepackage[english]{babel} % Language hyphenation and typographical rules
|
||||
\usepackage[final, colorlinks = true, urlcolor = blue, linkcolor = black]{hyperref}
|
||||
% \urlstyle{tt}
|
||||
\usepackage{changepage} % adjust margins on the fly
|
||||
|
||||
\usepackage{minted}
|
||||
\usemintedstyle{algol_nu}
|
||||
\usepackage{xcolor}
|
||||
|
||||
\usepackage{pgfplots}
|
||||
\pgfplotsset{width=\textwidth,compat=1.9}
|
||||
|
||||
\usepackage{caption}
|
||||
\newenvironment{code}{\captionsetup{type=listing}}{}
|
||||
|
||||
\usepackage[yyyymmdd]{datetime}
|
||||
\renewcommand{\dateseparator}{-}
|
||||
|
||||
\usepackage{titlesec}
|
||||
|
||||
\begin{document}
|
||||
\begin{titlepage}
|
||||
\begin{center}
|
||||
\hrule
|
||||
\vspace*{0.6cm}
|
||||
\huge \textbf{CT3536}
|
||||
\vspace*{0.6cm}
|
||||
\hrule
|
||||
\LARGE
|
||||
\vspace{0.5cm}
|
||||
GAMES PROGRAMMING
|
||||
\vspace{0.5cm}
|
||||
\hrule
|
||||
|
||||
\vfill
|
||||
\includegraphics[width=0.8\textwidth]{images/unity-logo.png}
|
||||
\vfill
|
||||
|
||||
\Large
|
||||
\vspace{0.5cm}
|
||||
\hrule
|
||||
\vspace{0.5cm}
|
||||
\textbf{Andreas Ó hAoḋa}
|
||||
% \vspace{0.5cm}
|
||||
% \hrule
|
||||
% \vspace{0.5cm}
|
||||
|
||||
\normalsize
|
||||
University of Galway
|
||||
|
||||
\today
|
||||
|
||||
\vspace{0.5cm}
|
||||
\hrule
|
||||
\end{center}
|
||||
\end{titlepage}
|
||||
|
||||
\pagenumbering{roman}
|
||||
\newpage
|
||||
\tableofcontents
|
||||
\newpage
|
||||
\setcounter{page}{1}
|
||||
\pagenumbering{arabic}
|
||||
|
||||
\section{Introduction}
|
||||
\subsection{Lecturer Contact Information}
|
||||
\begin{itemize}
|
||||
\item Dr. Sam Redfern (\href{mailto://sam.redfern@nuigalway.ie}{\texttt{sam.redfern@nuigalway.ie}})
|
||||
\item Discord server: \url{https://discord.gg/nqD5JN95WT}
|
||||
\end{itemize}
|
||||
|
||||
\subsection{Assessment}
|
||||
There will be 1-3 person projects which will begin from approximately Week 5, which will be worth 30\% of the course marks.
|
||||
10\% of the overall mark will be from the six graded lab assignments, and the remaining 60\% will be from the final exam.
|
||||
\\\\
|
||||
The game project will have a demo in the final week, and will be submitted as a document containing images, discussions,
|
||||
code, etc.
|
||||
Marks are awarded for:
|
||||
\begin{itemize}
|
||||
\item Overall complexity.
|
||||
\item Code architecture \& neatness.
|
||||
\item Game design/elegance \& UX.
|
||||
\item Discussion.
|
||||
\item Graphics (if self-created).
|
||||
\item Audio (if self-control).
|
||||
\item Group size will also be taken into account.
|
||||
\end{itemize}
|
||||
|
||||
You should start to consider your ideas by Week 5.
|
||||
Discuss the idea with Dr. Redfern \& the lab tutors as they can advise on scope \& difficulty.
|
||||
Simple 3D games are no harder to make than 2D games.
|
||||
``Snake'' games are not allowd!'
|
||||
|
||||
|
||||
\subsection{Game Engines}
|
||||
\textbf{Game Engines} provide a powerful set of integrated sub-systems geared towards making games (and other high-performance
|
||||
\emph{realtime} media) including:
|
||||
\begin{itemize}
|
||||
\item Graphics Rendering (3D, 2D, terrain).
|
||||
\item Physics.
|
||||
\item Networking.
|
||||
\item Special Effects.
|
||||
\item 3D Audio.
|
||||
\item User Input.
|
||||
\end{itemize}
|
||||
|
||||
\subsection{Unity3D Game Engine}
|
||||
The Unity3D game engine is a closed-source games engine that is well designed \& elegant to use ``2\textsuperscript{nd}
|
||||
generation'' game engine.
|
||||
It has excellent GUI/HUD editing \& animation system, and is powerful \& very popular.
|
||||
It has a hugely successful Asset Store.
|
||||
Its core language is C\#, which is very similar to Java.
|
||||
Unity3D deploys to iOS, Android, Web (HTML5/WebGL), Windows, Mac OSX, Linux, Switch, \& more.
|
||||
\begin{figure}[H]
|
||||
\centering
|
||||
\includegraphics[width=0.9\textwidth]{./images/unity_ide.png}
|
||||
\caption{The Unity IDE}
|
||||
\end{figure}
|
||||
|
||||
The \textbf{Project Window} displays your library of assets that are available to use in your project.
|
||||
When you import assets into your project, they appear here.
|
||||
\begin{figure}[H]
|
||||
\centering
|
||||
\includegraphics[width=0.9\textwidth]{./images/project_window.png}
|
||||
\caption{The Project Window (Assets)}
|
||||
\end{figure}
|
||||
|
||||
The \textbf{Scene View} allows you to visually navigate \& edit your scene without running your game.
|
||||
The scene view can be a 3D or 2D perspective.
|
||||
\begin{figure}[H]
|
||||
\centering
|
||||
\includegraphics[width=0.9\textwidth]{./images/scene_view.png}
|
||||
\caption{The Scene View}
|
||||
\end{figure}
|
||||
|
||||
The \textbf{Hierarchy Window} is a hierarchical nested text representation of every ``\textbf{game object}'' in the scene.
|
||||
\begin{figure}[H]
|
||||
\centering
|
||||
\includegraphics[width=0.9\textwidth]{./images/hierarchy_window.png}
|
||||
\caption{The Hierarchy (Scene Graph) Window}
|
||||
\end{figure}
|
||||
|
||||
The \textbf{Inspector Window} allows you to view \& edit all the properties of the currently selected game object.
|
||||
\begin{figure}[H]
|
||||
\centering
|
||||
\includegraphics[width=0.9\textwidth]{./images/inspector_window.png}
|
||||
\caption{The Inspector Window}
|
||||
\end{figure}
|
||||
|
||||
The \textbf{toolbar} provides access to the most essential working features.
|
||||
On the left it contains the basic tools for manipulating the scene view \& the objects within it.
|
||||
In the centre are the play \& pause controls.
|
||||
The buttons to the right give you access to your Unity Cloud Services \& your Unity Account, followed by a \textbf{layer}
|
||||
visibility menu, and finally the editor layout menu which provides some alternate layouts for the editor windows, and allows
|
||||
you to save your own custom layouts.
|
||||
\begin{figure}[H]
|
||||
\centering
|
||||
\includegraphics[width=0.9\textwidth]{./images/toolbar.png}
|
||||
\caption{The Toolbar}
|
||||
\end{figure}
|
||||
|
||||
\subsubsection{The Game Loop}
|
||||
At their core, games operate a \textbf{game loop}, although game engines somewhat hide this from you.
|
||||
It operates at 60fps (or more), deal with inputs received asynchronously via events (e.g. keyboard or network data) or
|
||||
polled for right now, process game objects such as move the physics simulation (if any) forwards or move objects by
|
||||
physics simulation or direct control, redraw, wait (maybe) or run at maximum obtainable speed (maybe) but don't block the
|
||||
main thread.
|
||||
|
||||
\subsubsection{The Unity API}
|
||||
Luckily, everything is not just drag-n-drop.
|
||||
We can write C\# code to make the game work.
|
||||
Much of our code will involve the manipulation of the Unity API classes from the \verb|UnityEngine| \& \verb|UnityEngine.UI|
|
||||
namespaces.
|
||||
Of course, we can also do anything else supported by the core C\#/.NET library such as file handling, networking, collection
|
||||
classes, etc.
|
||||
|
||||
\subsubsection{Component-Based Architecture}
|
||||
2\textsuperscript{nd} generation game engines such as Unity3D use \textbf{Component-Based Architecture (CBA)}, which suits
|
||||
game logic very well.
|
||||
It's different to classic OOP as it's based on the \textbf{Composition} rather than \textbf{Inheritance} principle.
|
||||
Every \textbf{entity} consists of one or more \textbf{components} which add additional behaviour or functionality.
|
||||
The behaviour of an entity can even be changed at runtime by adding or removing components.
|
||||
This eliminates the ambiguity problems of inheritance class-hierarchies that are difficult to understand, maintain, \&
|
||||
extend.
|
||||
Each component is essentially a separate software object but all attached to some higher-level \verb|GameObject| which
|
||||
typically equates to an actual onscreen character, enemy, bullet, effect, vehicle, etc.
|
||||
\\\\
|
||||
Using composition rather than inheritance can be somewhat of a mantra, and not correct in all cases.
|
||||
Code re-use is often (incorrectly) considered to be the main principle of inheritance.
|
||||
In fact, designing hierarchical taxonomies of classes is the most appropriate reason to use inheritance.
|
||||
Composition is better when you would otherwise get tangles up in the murky world of multiple-inheritance.
|
||||
Composition is excellent for code re-use.
|
||||
|
||||
\section{Lab Session 1}
|
||||
Import a model of Mars (and a \verb|texture.jpg| for it).
|
||||
Create a simple demo which rotates Mars using the built-in physics engine.
|
||||
We could also take direct control of the Mars object and rotate it ourselves, a little bit on each frame, but here we're
|
||||
letting the physics engine do the work.
|
||||
No need to submit anything for this lab session as it's not graded.
|
||||
|
||||
\begin{code}
|
||||
\begin{minted}[texcl, mathescape, linenos, breaklines, frame=single]{csharp}
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
public class GameManagerScript : MonoBehaviour {
|
||||
public GameObject marsObject;
|
||||
// Use this for initialization
|
||||
void Start () {
|
||||
Camera.main.transform.position = new Vector3 (0f, 0f, -100f);
|
||||
Camera.main.transform.LookAt (marsObject.transform);
|
||||
// use the physics engine to rotate Mars
|
||||
// before this can run, you need to manually add a rigid body with 0 angular velocity and no gravity in the UI
|
||||
marsObject.GetComponent<Rigidbody>().AddTorque (new Vector3(0f,20f,0f));
|
||||
}
|
||||
}
|
||||
\end{minted}
|
||||
\caption{Lab 1 Code}
|
||||
\end{code}
|
||||
|
||||
\begin{code}
|
||||
\begin{minted}[texcl, mathescape, linenos, breaklines, frame=single]{csharp}
|
||||
public class GameManager : MonoBehaviour {
|
||||
// inspector settings
|
||||
public GameObject marsObject;
|
||||
void Start() {
|
||||
marsObject.transform.position = new Vector3(0,0,0);
|
||||
Camera.main.transform.position = new Vector3(0,0,100);
|
||||
Camera.main.transform.LookAt(marsObject.transform);
|
||||
}
|
||||
void Update() {
|
||||
// programmatically rotate Mars each frame:
|
||||
marsObject.transform.Rotate(new Vector3(0,10*Time.deltaTime,0));
|
||||
}
|
||||
}
|
||||
\end{minted}
|
||||
\caption{Alternative Lab 1 Code}
|
||||
\end{code}
|
||||
|
||||
\section{Key Concepts \& Classes}
|
||||
\subsection{\texttt{MonoBehaviour}}
|
||||
\textbf{\texttt{MonoBehaviour}} is the base class from which Unity C\# scripts normally derive.
|
||||
This hooks the class into the Game Loop so that it automatically receives calls to specific methods at specific times.
|
||||
It also provides various other useful Unity methods that are called by the game engine in specific situations, including but
|
||||
not limited to:
|
||||
\begin{multicols}{3}
|
||||
\begin{itemize}
|
||||
\item \verb|Start()|
|
||||
\item \verb|OnDestroy()|
|
||||
\item \verb|Awake()|
|
||||
\item \verb|Update()|
|
||||
\item \verb|FixedUpdate()|
|
||||
\item \verb|LateUpdate()|
|
||||
\item \verb|OnDisable()|
|
||||
\item \verb|OnEnabled()|
|
||||
\item \verb|OnBecameInvisible()|
|
||||
\item \verb|OnBecameVisible()|
|
||||
\item \verb|OnCollisionEnter()|
|
||||
\item \verb|OnCollisionExit()|
|
||||
\item \verb|OnCollisionStay()|
|
||||
\item \verb|OnTriggerEnter()|
|
||||
\item \verb|OnTriggerExit()|
|
||||
\item \verb|OnTriggerStay()|
|
||||
\item \verb|OnMouseEnter()|
|
||||
\item \verb|OnMouseExit()|
|
||||
\item \verb|OnMouseDown()|
|
||||
\end{itemize}
|
||||
\end{multicols}
|
||||
|
||||
In games, it is often useful to be able to execute code at programmer-controlled intervals (perhaps much less often than every
|
||||
frame), or at some specified time in the future.
|
||||
In Unity \verb|MonoBehaviour|, the methods \verb|Invoke()| \& \verb|StartCoroutine()| relate to this.
|
||||
We will elaborate on these later.
|
||||
\verb|MonoBehaviour| also provides several important data members such as:
|
||||
\begin{multicols}{2}
|
||||
\begin{itemize}
|
||||
\item \verb|enabled| (Boolean).
|
||||
\item \verb|gameObject| (GameObject).
|
||||
\item \verb|transform| (Transform).
|
||||
\item \verb|name| (String) (name of \verb|gameObject|).
|
||||
\end{itemize}
|
||||
\end{multicols}
|
||||
|
||||
Finally, there are some more methods provided which are useful for manipulating \verb|GameObject|s and their components:
|
||||
\begin{multicols}{3}
|
||||
\begin{itemize}
|
||||
\item \verb|SendMessage()|
|
||||
\item \verb|BroadcastMessage()|
|
||||
\item \verb|SendMessageUpwards()|
|
||||
\item \verb|GetComponent()|
|
||||
\item \verb|GetComponentInChildren()|
|
||||
\item \verb|GetComponentInParent()|
|
||||
\item \verb|GetComponents()|
|
||||
\item \verb|GetComponentsInChildren()|
|
||||
\item \verb|GetComponentsInParent()|
|
||||
\item \verb|GetInstanceID()|
|
||||
\end{itemize}
|
||||
\end{multicols}
|
||||
|
||||
Recall that \verb|GameObject|s can contain many independent scripts (components), each inheriting from \verb|MonoBehaviour|.
|
||||
Each script/component is an instance of a class.
|
||||
A \verb|GameObject| is therefore composed of multiple software objects.
|
||||
This is called a ``component-based system'' and is often seen as a superior approach to object-oriented class hierarchies --
|
||||
better for code re-use \& isolation of functionality.
|
||||
\\\\
|
||||
References:
|
||||
\begin{itemize}
|
||||
\item \url{https://docs.unity3d.com/ScriptReference/MonoBehaviour.html}
|
||||
\item \url{https://docs.unity3d.com/Manual/ExecutionOrder.html}
|
||||
\end{itemize}
|
||||
|
||||
\subsection{\texttt{GameObject}s in Unity}
|
||||
\verb|GameObject| is the base class for all entities that exist in a Unity scene.
|
||||
As discussed above, each \verb|GameObject| has a collection of components attached, and each component is an independent class
|
||||
object inheriting from \verb|MonoBehaviour|.
|
||||
The \verb|GameObject| is a special class that \emph{all} entities in the game are derived from and which you won't have to
|
||||
attach as a component.
|
||||
Some useful data members of \verb|GameObject| include:
|
||||
\begin{itemize}
|
||||
\item \verb|activeInHierarchy| (Boolean).
|
||||
\item \verb|transform| (Transform).
|
||||
\item \verb|tag| (Tag type as defined in the editor).
|
||||
\end{itemize}
|
||||
|
||||
Some useful methods of \verb|GameObject| include:
|
||||
\begin{itemize}
|
||||
\item \verb|AddComponet()|.
|
||||
\item \verb|SendMessage()| etc. (same as the method in \verb|MonoBehaviour| classes).
|
||||
\item \verb|GetComponent()| etc. (same as the method in \verb|MonoBehaviour| classes).
|
||||
\item \verb|SetActive()|.
|
||||
\end{itemize}
|
||||
|
||||
Some useful static methods of \verb|GameObject| include:
|
||||
\begin{itemize}
|
||||
\item \verb|Find()|.
|
||||
\item \verb|Destroy()|.
|
||||
\item \verb|Instantiate()|.
|
||||
\end{itemize}
|
||||
|
||||
\subsubsection{Getting References to \texttt{GameObject}s at Runtime}
|
||||
For a specific \verb|GameObject|:
|
||||
\begin{itemize}
|
||||
\item Have it referenced as a public member of the script that needs it, and associated at design-time in the Inspector.
|
||||
(This is what we did in the first lab for the Mars object, a reference to which was needed by the
|
||||
\verb|GameManager| class).
|
||||
\item Use \verb|GameObject.Find("<name>")| to find it by name. This is somewhat inefficient, so don't do this every frame.
|
||||
\item Use \verb|GameObject.FindGameObjectsWithTag("<tag>")| to find all game objects with a specified tag. This returns an array
|
||||
of \verb|GameObject|s.
|
||||
\end{itemize}
|
||||
|
||||
\subsubsection{Prefabs}
|
||||
When you have created a \verb|GameObject| in the hierarchy (at design time), added components to it, and set their various
|
||||
public values, you can drag the \verb|GameObject| into the Assets Window to make a \textbf{prefab}, essentially a template of
|
||||
that exact object with its settings.
|
||||
\\\\
|
||||
This approach means that you can make \verb|MonoBehaviour| scripts for monsters, guns, etc. and then make a separate prefab
|
||||
with different settings for each actual type of monster or gun you need in your game.
|
||||
Prefabs are therefore useful for creating \& editing your game's data.
|
||||
|
||||
\subsubsection{Runtime Instantiation \& Destruction of \texttt{GameObject}s}
|
||||
So far, we have created all of the \verb|GameObject|s that we need in the hierarchy at design-time (i.e., before starting the
|
||||
game).
|
||||
Often, we need to instantiate \& destroy some or all of our game objects at runtime, e.g. bullets, enemies, explosions, etc.
|
||||
Assuming that we have a \textbf{prefab} in our Assets, and that it is located in a directory called \verb|Resources| we can
|
||||
do the following.
|
||||
Here, \verb|prefabName| is the name of our asset prefab (as a String):
|
||||
\begin{minted}[texcl, mathescape, linenos, breaklines, frame=single]{csharp}
|
||||
GameObject go = Instantiate(Resources.Load(prefabName));
|
||||
|
||||
// later on, assuming we still have a reference to the object:
|
||||
GameObject.Destroy(go);
|
||||
// or
|
||||
GameObject.DestroyImmediate(go);
|
||||
\end{minted}
|
||||
|
||||
Alternatively, you can instantiate an object by supplying an existing instantiated object as a template.
|
||||
E.g., in Lab 1 our \verb|GameManagerScript| class had a \verb|GameObject| member called \verb|marsObject|, which is
|
||||
instantiated in the Inspector at design time, so you could use this to make another Mars:
|
||||
\begin{minted}[texcl, mathescape, linenos, breaklines, frame=single]{csharp}
|
||||
GameObject otherMarsObject = Instantiate(marsObject);
|
||||
\end{minted}
|
||||
|
||||
Another alternative, perhaps the easiest of all, is to have a public reference to a \verb|GameObject| and associate this
|
||||
with a prefab in the assets by dragging in the Inspector.
|
||||
Then you can use \verb|Instantiate()| on that to instantiate a copy of the prefab into the scene at runtime.
|
||||
|
||||
\subsubsection{Cameras}
|
||||
In computer graphics, \textbf{Cameras} are software objects that define a viewpoint in terms of position, orientation,
|
||||
field-of-view/zoom, etc. within the ``virtual world''.
|
||||
Mathematical projections are used to calculate how the 3D world should be displayed on the 2D camera surface.
|
||||
In Unity, Cameras are \verb|GameObject|s which have a \verb|Camera| component.
|
||||
Since they're \verb|GameObject|s, you can add other components, manipulate their \verb|Transform|, etc. just like any other
|
||||
\verb|GameObject|.
|
||||
The \verb|Transform| component provides methods that are very useful to Cameras (as well as other non-Camera objects) such as
|
||||
\verb|LookAt()|.
|
||||
\\\\
|
||||
\verb|Camera.main| is a static reference to the ``main'' Camera whose view is being displayed to the screen.
|
||||
This Camera should have the tag \verb|MainCamera|.
|
||||
Other Cameras can be used at the same time, e.g. to render to texture (e.g. mirrors, top-down minimaps) or to render to parts
|
||||
of the screen (e.g., split-screen multiplayer).
|
||||
You might also have multiple cameras in a scene and switch the active one during the game.
|
||||
\\\\
|
||||
The \verb|Camera| class provides methods for converting co-ordinates between Screen-space, Viewport-space, \& World-space
|
||||
(more on these later).
|
||||
\begin{itemize}
|
||||
\item \verb|CalculateFrustumCorners()|: Given viewport coordinates, calculates the view space vectors pointing to the
|
||||
four frustum corners at the specified camera depth.
|
||||
\item \verb|ScreenPointToRay()|: Returns a ray going from camera through a screen point.
|
||||
\item \verb|ScreenToViewportPoint()|: Transforms position from screen space into viewport space.
|
||||
\item \verb|ScreenToWorldPoint()|: Transforms position from screen space into world space.
|
||||
\item \verb|ViewportPointToRay()|: Returns a ray going from camera through a viewport point.
|
||||
\item \verb|ViewportToScreenPointTransforms()|: position from viewport space into screen space.
|
||||
\item \verb|ViewportToWorldPointTransforms()|: position from viewport space into world space.
|
||||
\item \verb|WorldToScreenPointTransforms()|: position from world space into screen space.
|
||||
\item \verb|WorldToViewportPointTransforms()|: position from world space into viewport space.
|
||||
\end{itemize}
|
||||
References:
|
||||
\begin{itemize}
|
||||
\item \url{https://docs.unity3d.com/ScriptReference/Camera.html}
|
||||
\item \url{https://docs.unity3d.com/Manual/class-Camera.html}
|
||||
\end{itemize}
|
||||
|
||||
\subsubsection{Transforms}
|
||||
A \textbf{Transform} defines the position, orientation, \& scale of an object.
|
||||
Child objects have their own Transforms which are interpreted as a nested co-ordinate system, i.e. a modification of the
|
||||
parent's.
|
||||
This is a very powerful concept and is fundamental to the concept of a SceneGraph/hierarchy.
|
||||
In Unity, the \verb|Transform| class has the following key members:
|
||||
\begin{itemize}
|
||||
\item \verb|position| (Vector3)
|
||||
\item \verb|localPosition| (Vector3)
|
||||
\item \verb|rotation| (Quaternion)
|
||||
\item \verb|localRotation| (Quaternion)
|
||||
\item \verb|lossyScale| (Vector3)
|
||||
\item \verb|localScale| (Vector3)
|
||||
\item \verb|parent| (Transform)
|
||||
\item \verb|right|: positive direction on the local x axis (Vector3, normalised).
|
||||
\item \verb|up|: positive direction on the local y axis (Vector3, normalised).
|
||||
\item \verb|forward|: positive direction on the local z axis (Vector3, normalised).
|
||||
\item \verb|gameObject| (GameObject)
|
||||
\end{itemize}
|
||||
|
||||
Methods of the \verb|Transform| class include:
|
||||
\begin{itemize}
|
||||
\item \verb|Rotate()|: Uses ``Euler angles'' ($x$, $y$, $z$) all in degrees.
|
||||
\item \verb|Translate()|
|
||||
\item \verb|TransformPoint()|: Transforms position from local space to world space.
|
||||
\item \verb|InverseTransformPoint()|: Transforms position from world space to local space.
|
||||
\item \verb|LookAt()|: (Vector3 point) turns so that the forward direction (i.e., positive $z$ axis) faces the specified
|
||||
position.
|
||||
\item \verb|RotateAround()|: (Vector3 point, Vector3 axis, float degrees).
|
||||
\item \verb|SetParent()|
|
||||
\end{itemize}
|
||||
|
||||
Reference: \url{https://docs.unity3d.com/ScriptReference/Transform.html}
|
||||
|
||||
\subsubsection{Skyboxes}
|
||||
\textbf{Skyboxes} are rendered around the whole scene in the background in order to give the impression of complex scenery at
|
||||
the horizon.
|
||||
To implement a Skybox, create a Skybox Material in your Assets.
|
||||
Then, add it to the scene by using the Window {\rightarrow} Rendering {\rightarrow} Lighting menu item and specifying your Skybox
|
||||
material as the Skybox on the Scene tab.
|
||||
\\\\
|
||||
Reference: \url{https://docs.unity3d.com/Manual/class-Skybox.html}
|
||||
|
||||
\subsubsection{Keyboard Input}
|
||||
We will revisit more details about Keyboard/Mouse/Joystick/Touchscreen input later, but for now we will just say that
|
||||
\verb|Input.GetKey()| returns true as long as a key is held down.
|
||||
E.g., this could be written in an \verb|Update()| method:
|
||||
\begin{minted}[texcl, mathescape, linenos, breaklines, frame=single]{csharp}
|
||||
if (Input.GetKey(KeyCode.LeftArrow)) {
|
||||
RotateCameraAroundMarsSomehow();
|
||||
}
|
||||
\end{minted}
|
||||
|
||||
References:
|
||||
\begin{itemize}
|
||||
\item \url{https://docs.unity3d.com/ScriptReference/Input.html}
|
||||
\item \url{https://docs.unity3d.com/ScriptReference/Input.GetKey.html}
|
||||
\end{itemize}
|
||||
|
||||
\subsubsection{Static Member Variables}
|
||||
By declaring a member variable \textbf{\texttt{static}}, you're creating a single copy of the variable which is owned by the
|
||||
class rather than by any specific instance object.
|
||||
Each instance does not have its own unique copy, they share one.
|
||||
A common use case for static member variables is if you want to retain a collection of all instances of the class for quick
|
||||
recall.
|
||||
|
||||
\subsubsection{Static Member Functions}
|
||||
By declaring a method \textbf{\texttt{static}}, you're creating a method that is called on the class itself, not an instance of
|
||||
it.
|
||||
This is very useful since you don not need to have a reference to an instantiated object from the class in order to call it.
|
||||
For obvious reasons, a static method only has access to static member variables of the class, while a non-static method
|
||||
(which is called on an actual instantiated object) has in addition, access to its own copies of non-static member variables.
|
||||
|
||||
\subsubsection{The Singleton Pattern}
|
||||
A common design approach in Unity is to create single-instance \textbf{singleton} classes for various ``management'' roles,
|
||||
e.g. \verb|GameManager|, \verb|GUIManager|, \verb|AudioManager|, \verb|SaveGameManager|, etc.
|
||||
The typical approach is to create a \verb|GameObject| in the hierarchy which holds the one-and-only instance of these
|
||||
components that will exist at run-time.
|
||||
One habit is to attach these to the Main Camera.
|
||||
Using statics can make the methods of these management singletons very easy \& clean to access, e.g. consider the ``instance''
|
||||
static member variable used here; it gives direct access to data attached to the instantiated singleton object, from anywhere
|
||||
in the game, via \verb|GameManager.instance|
|
||||
\begin{minted}[texcl, mathescape, linenos, breaklines, frame=single]{csharp}
|
||||
public class GameManager : MonoBehaviour {
|
||||
public static GameManager instance;
|
||||
|
||||
void Start () {
|
||||
instance = this;
|
||||
}
|
||||
}
|
||||
\end{minted}
|
||||
|
||||
\subsection{Lab 2: Fear \& Dread}
|
||||
In our first lab, we attached a \verb|Rigidbody| to the Mars object, applied angular velocity to it using \verb|AddTorque|,
|
||||
and let the game engine control the movement of it.
|
||||
The other way of moving game objectsis to directly manipulate their \verb|Transform| using code (this was our approach in
|
||||
second year Java).
|
||||
In Lab 2, we'll be making Mars' two moons (Phobos \& Deimos) orbit around it through direct manipulations of their Transforms.
|
||||
Your code for doing this would typically be written in the \verb|Update()| method of some script (it could either be a
|
||||
script attached to the \verb|GameObject| itself, or perhaps a script attached to a singleton ``manager'' object).
|
||||
It is important to consider the fact that \verb|Update()| is probably not happening at fixed time intervals.
|
||||
You can multiply all movement code by \verb|Time.deltaTime|.
|
||||
|
||||
\section{Co-ordinate Systems}
|
||||
The most important co-ordinate system distinction in Unity is between the \textbf{Global} (or World) co-ordinate system
|
||||
and the \textbf{Local} co-ordinate system of each \verb|GameObject|.
|
||||
Hence, to rotate the camera round the $y$-axis \emph{as perceived by the camera} (i.e., the $y$-axis of its Local Co-ordinate
|
||||
system) we can use:
|
||||
\begin{minted}[texcl, mathescape, linenos, breaklines, frame=single]{csharp}
|
||||
camera.transform.RotateAround(Vector3.zero, camera.transform.up, 50f * Time.deltaTime);
|
||||
\end{minted}
|
||||
|
||||
Or, to rotate it around the Global $y$-axis:
|
||||
\begin{minted}[texcl, mathescape, linenos, breaklines, frame=single]{csharp}
|
||||
camera.transform.RotateAroudn(Vector3.zero, Vector3.up, 50f * Time.deltaTime);
|
||||
\end{minted}
|
||||
|
||||
The first \verb|Vector3| argument defines the world point around which to rotate.
|
||||
\\\\
|
||||
Some methods of the \verb|Transform| class for translating from the local space of a transform to global space and
|
||||
vice-versa include:
|
||||
\begin{minted}[texcl, mathescape, linenos, breaklines, frame=single]{csharp}
|
||||
// local space to global
|
||||
public Vector3 TransformPoint(Vector3 position);
|
||||
public Vector3 TransformDirection(Vector3 direction);
|
||||
public Vector3 TransformVector(Vector3 vector);
|
||||
// global to local
|
||||
public Vector3 InverseTransformPoint(Vector3 position);
|
||||
public Vector3 InverseTransformDirection(Vector3 direction);
|
||||
public Vector3 InverseTransformVector(Vector3 vector);
|
||||
\end{minted}
|
||||
|
||||
\subsection{Examples}
|
||||
To find the world-coordinate of a point which is 10 units ``in front of'' a spaceship (in terms of its
|
||||
own direction facing, and assuming this code is located inside a script attached to the spaceship):
|
||||
\begin{minted}[texcl, mathescape, linenos, breaklines, frame=single]{csharp}
|
||||
Vector3 pt = transform.TransformPoint(new Vector3(0f, 0f, 10f));
|
||||
// another way of doing the same would be:
|
||||
Vector3 pt = transform.position + 10f * transform.forward;
|
||||
\end{minted}
|
||||
|
||||
To accelerate a spaceship forwards (assuming it has a \verb|Rigidbody| and we're using physics, and we're doing this in a
|
||||
\verb|FixedUpdate()| method on one of its scripts):
|
||||
\begin{minted}[texcl, mathescape, linenos, breaklines, frame=single]{csharp}
|
||||
Rigidbody rigid = GetComponent<Rigidbody>();
|
||||
rigid.AddForce(transform.forward * 200f * Time.fixedDeltaTime);
|
||||
\end{minted}
|
||||
|
||||
To get the direction \& distance between two \verb|GameObject|s:
|
||||
\begin{minted}[texcl, mathescape, linenos, breaklines, frame=single]{csharp}
|
||||
GameObject go1, go2; // it's assumed that these are not nulls!
|
||||
|
||||
Vector3 difference, direction;
|
||||
difference = go2.transform.position - go1.transform.position;
|
||||
direction = difference.normalized;
|
||||
float distance = difference.magnitude;
|
||||
\end{minted}
|
||||
|
||||
Iterating nested objects using \verb|foreach (Transoform t in Transform)|:
|
||||
\begin{minted}[texcl, mathescape, linenos, breaklines, frame=single]{csharp}
|
||||
public class Area : MonoBehaviour {
|
||||
// inspector settings
|
||||
public Transform innerWallsGroup;
|
||||
public Vector3 wallsPos;
|
||||
|
||||
private List<GameObject> innerWalls = new List<GameObject>();
|
||||
private bool[] wallIsRaised = null;
|
||||
|
||||
void Start() {
|
||||
foreach (Transform t in innerWallsGroup) {
|
||||
innerWalls.Add(t.gameObject);
|
||||
}
|
||||
|
||||
wallIsRaised = new bool[innerWalls.Count];
|
||||
|
||||
for (int i = 0; i < innerWalls.Coutn; i++) {
|
||||
innerWalls[i].transform.position = wallsPos;
|
||||
innerWalls[i].SetActive(false);
|
||||
wallIsRaised[i] = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
\end{minted}
|
||||
|
||||
\subsection{Screen Space, Viewport Space, \& World Space}
|
||||
Reference: \url{https://docs.unity3d.com/ScriptReference/Camera.html}
|
||||
\\\\
|
||||
The \verb|Camera| class provides methods for translating between three different ``spaces'', i.e. different ways of
|
||||
mapping the positions of things.
|
||||
\\\\
|
||||
Each of these is stored as a \verb|Vector3| (which is a \verb|struct|).
|
||||
A \textbf{screen space} point is defined in pixels.
|
||||
The bottom-left of the screen is $(0,0)$; the right-top is $(\texttt{Camera.pixelWidth}, \texttt{Camera.pixelHeight})$ .
|
||||
If you're using a \verb|Vector3| rather than a \verb|Vector2|, then the $z$ position is in \textbf{world units} in front
|
||||
of the Camera, rather than in screen pixels.
|
||||
See also the \verb|Screen| class: \url{https://docs.unity3d.com/ScriptReference/Screen.html}
|
||||
\\\\
|
||||
A \textbf{viewport space} point is normalised and relative to the Camera.
|
||||
The bottom-left of the Camera is $(0,0)$; the top-right is $(1,1)$.
|
||||
Again, the $z$ position (if any) is in world units in front of the Camera.
|
||||
E.g., this is appropriate for positioning GUI elements independent of actual pixel resolution of the screen.
|
||||
\\\\
|
||||
A \textbf{world space} is defined in global co-ordinates (for example, \verb|transform.position|.
|
||||
E.g., this is appropriate for \verb|GameObject|s in the game world.
|
||||
\verb|GameObject|s which are nested in the Hierarchy have both \verb|transform.position| \&
|
||||
\verb|transform.localPosition|; \verb|transform.rotation| \& \verb|transform.localRotation|, etc.
|
||||
|
||||
\subsubsection{Typical Space-Translation Operations}
|
||||
Find where the mouse is in world co-ordinates to see if a \verb|GameObject| is under the mouse:
|
||||
\begin{minted}[texcl, mathescape, linenos, breaklines, frame=single]{csharp}
|
||||
// note that Input.mousePosition gives a Vector4 where the $z$ component is 0
|
||||
// the screen is 2D of course; the $z$ component of the Vector3 supplied to ScreenToWorldPoint is a world-coordinate distance into the world.
|
||||
Vector3 mousePosInWorld = Camera.main.ScreenToWorldPoint(Input.mousePosition);
|
||||
\end{minted}
|
||||
|
||||
Find a \verb|GameObject| in screen-pixel coordinates to position a GUI item such as a healthbar above it:
|
||||
\begin{minted}[texcl, mathescape, linenos, breaklines, frame=single]{csharp}
|
||||
GameObject targ; // assumed not to be null
|
||||
Vector3 screenPos = Camera.main.WorldToScreenPoint(targ.transform.position);
|
||||
\end{minted}
|
||||
|
||||
\begin{code}
|
||||
\begin{minted}[texcl, mathescape, linenos, breaklines, frame=single]{csharp}
|
||||
// Here, we find the 3D position that's just above the enemy's head, and convert this to a vieweort position when viewed through the player's camera.
|
||||
// Finally, this viewport position is converted to a pixel position as required by the GUI sprite.
|
||||
public class MonsterManager : MonoBehaviour {
|
||||
void Update () {
|
||||
if (GameManager.gameState==GameStates.Playing) {
|
||||
if (numMonstersAlive==1) {
|
||||
// put the final enemy indicator (GUI object) above the final monster
|
||||
GameObject go = GUIManager.instance.finalEnemyIndicator;
|
||||
Monster m = allActiveMonsters[0];
|
||||
Bounds b = m.mycollider.bounds;
|
||||
Vector3 pos = new Vector3(b.center.x, b.max.y + 1f, b.center.z);
|
||||
Vector3 viewPos = Player.myPlayer.fpsCamera.WorldToViewportPoint(pos);
|
||||
if (viewPos.x<0f || viewPos.x>1f || viewPos.y<0f || viewPos.y>1f || viewPos.z<0f)
|
||||
go.SetActive(false);
|
||||
else {
|
||||
go.SetActive(true);
|
||||
go.transform.position = new Vector2(viewPos.x*Screen.width, viewPos.y*Screen.height);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
\end{minted}
|
||||
\caption{The ``Final Enemy Indicator'' in DemonPit}
|
||||
\end{code}
|
||||
|
||||
\section{Object Interactions with Colliders \& Triggers}
|
||||
Objects which have \verb|Collider|s \& \verb|Rigidbody|s will physically respond to impacts (i.e., they'll bounce off each
|
||||
other).
|
||||
Objects which have Triggers but not Colliders will \textbf{not} physically interact.
|
||||
\\\\
|
||||
Related to the physics engine are two sets of \verb|MonoBheaviour| methods which are called automatically when objects
|
||||
with Colliders or Triggers interact:
|
||||
\begin{minted}[texcl, mathescape, linenos, breaklines, frame=single]{csharp}
|
||||
// these happen for Collider-to-Collider collisions
|
||||
OnCollisionEnter(Collision coll);
|
||||
OnCollisionExit(Collision coll);
|
||||
OnCollisionStay(Collision coll);
|
||||
|
||||
// these happen for Trigger-to-Trigger collisions
|
||||
OnTriggerEnter(Collider coll);
|
||||
OnTriggerExit(Collider coll);
|
||||
OnTriggerStay(Collider coll);
|
||||
\end{minted}
|
||||
|
||||
The \verb|Collision| argument provides information on the game object that has collided with us, as well as additional
|
||||
information about the collision itself (e.g., the speed of impact).
|
||||
The \verb|Collider| argument is simply a reference to the Trigger component that interact with ours.
|
||||
\verb|OnCollision| refers to an actual physics interaction between two Colliders (e.g. \verb|BoxCollider| or
|
||||
\verb|SphereCollider| components).
|
||||
\verb|OnTrigger| is the same thing except here the Collider has its Trigger flag set to \verb|true|.
|
||||
Triggers enable game-logic interaction when you don't want physical collision responses.
|
||||
\\\\
|
||||
Reference: \url{https://docs.unity3d.com/ScriptReference/Collider.OnCollisionEnter.html}
|
||||
|
||||
\subsection{Lab 3: Asteroid Assault on Mars \& its Moons}
|
||||
This lab builds on the work from the last two weeks; we already have Mars rotating, with Phobos \& Deimos orbiting around
|
||||
it, and keyboard control of the camera.
|
||||
This week, we will be instantiating asteroids at runtime, and setting them moving (using physics).
|
||||
Asteroid which collide with anything will be destroyed, as will be asteroids which pass offscreen.
|
||||
|
||||
\subsection{Triggers (Sensors)}
|
||||
\textbf{Triggers} are invisible components that are activated (triggered) when a character or other object passes inside
|
||||
them.
|
||||
They are a very common \& useful mechanism in games.
|
||||
In Unity, Trigger is made by using a Collider with its Trigger property checked.
|
||||
|
||||
\subsection{Coroutines}
|
||||
\textbf{Coroutines} are special functions that can pause their execution.
|
||||
They're very useful for delayed execution, making things happen in steps (with a defined delay between each step), or for
|
||||
waiting for something else to complete before executing.
|
||||
Coroutines are a very useful feature provided by the \verb|MonoBehaviour| class.
|
||||
Their usefulness is because the code related to something occurring in the game is kept all in one place, even if that
|
||||
something takes a long time to occur, or occurs in stages.
|
||||
Coroutines are not threads, as they run in the same thread as the main Unity process, but they are much simpler to use than
|
||||
threads.
|
||||
In any case, most of the Unity SDK is not thread-safe.
|
||||
Coroutines are started with a call to \verb|StartCoroutine()|, and they must have the \verb|IEnumerator| return type.
|
||||
Technically, the way that these work is that Unity maintains a list of active Coroutines and on each game loop wakes up
|
||||
any that are now due to wake up.
|
||||
\\\\
|
||||
When the coroutine is activated, it well execute until the next \verb|yield| statement and then pause until it is
|
||||
resumed.
|
||||
Various values can be supplied with the \verb|yield| statement, e.g. \verb|yield return null| simply waits until the next
|
||||
frame.
|
||||
\begin{minted}[texcl, mathescape, linenos, breaklines, frame=single]{csharp}
|
||||
private void Start() {
|
||||
Debug.Log("Start method");
|
||||
StartCoroutine(TestCoroutine());
|
||||
Debug.Log("Start method ends");
|
||||
}
|
||||
|
||||
// this coroutine has a loop that runs as along as the calling object is active
|
||||
private IEnumerator TestCoroutine() {
|
||||
Debug.Log("TestCoroutine");
|
||||
while(true)
|
||||
{
|
||||
Debug.Log("Here");
|
||||
yield return null;
|
||||
Debug.Log("There");
|
||||
}
|
||||
}
|
||||
|
||||
private void Update() {
|
||||
Debug.Log("Update");
|
||||
}
|
||||
|
||||
// Output should be:
|
||||
/*
|
||||
Start method
|
||||
TestCoroutine
|
||||
Here
|
||||
Start method ends
|
||||
Update
|
||||
There
|
||||
Here
|
||||
Update
|
||||
There
|
||||
Here
|
||||
*/
|
||||
\end{minted}
|
||||
|
||||
Some of the most useful Coroutine \verb|yield| values include:
|
||||
\begin{itemize}
|
||||
\item \verb|yield return null;| -- the coroutine is continued the next time that it is eligible, normally on the
|
||||
next frame.
|
||||
\item \verb|yield return new WaitForSeconds(3f);| -- causes the coroutine to pause for a specified time period (three
|
||||
seconds in this example). Be aware of the garbage implications of this.
|
||||
\item \verb|yield return StartCoroutine(OtherCoroutine());| -- waits until the other coroutine has run to completion
|
||||
before the yielder is resumed.
|
||||
\item \verb|yield break;| -- stops the coroutine and exits (i.e., this is the equivalent of a \verb|return| statement
|
||||
in a normal method).
|
||||
\end{itemize}
|
||||
|
||||
Be aware of changes during the \verb|yield| time.
|
||||
You always have to be careful with asynchronous programming: something important may have changed during the ``down time''
|
||||
of a coroutine.
|
||||
\\\\
|
||||
Reference: \url{https://unitygem.wordpress.com/coroutines/}
|
||||
|
||||
\subsubsection{\texttt{Invoke} \& \texttt{InvokeRepeating}}
|
||||
\verb|Invoke| \& \verb|InvokeRepeating| provide a simpler way of running a complete method some time in the future, either
|
||||
as a one-off or a repeating call.
|
||||
\begin{minted}[texcl, mathescape, linenos, breaklines, frame=single]{csharp}
|
||||
public class ExampleScript : MonoBehaviour
|
||||
{
|
||||
// Launches a projectile after 2 seconds
|
||||
|
||||
Rigidbody projectile;
|
||||
|
||||
void Start() {
|
||||
Invoke("LaunchProjectile", 2f);
|
||||
}
|
||||
|
||||
void LaunchProjectile()
|
||||
{
|
||||
Rigidbody instance = Instantiate(projectile);
|
||||
instance.velocity = Random.insideUnitSphere * 5f;
|
||||
}
|
||||
}
|
||||
\end{minted}
|
||||
|
||||
To invoke repeatedly:
|
||||
\begin{minted}[texcl, mathescape, linenos, breaklines, frame=single]{csharp}
|
||||
InvokeRepeating("LaunchProjectile", 2.0f, 0.3f);
|
||||
\end{minted}
|
||||
|
||||
\subsection{Layers}
|
||||
\textbf{Layers} allow you to group game objects into categories.
|
||||
They are can be found at Edit {\rightarrow} Project Settings {\rightarrow} Tags and Layers.
|
||||
You can then decide which layers interact with each other in the physics simulation.
|
||||
You can also use an object's Layer to decide what happens when it collides with another object.
|
||||
You can also apply raycasts (see later) on specific objects only, e.g. to determine whether a monster can see a player,
|
||||
you would cast a ray between the position of the monster's head and the player's head, but only let the raycast consider
|
||||
walls/floors, i.e. it would ignore any creatures in the way.
|
||||
\\\\
|
||||
Don't confuse Layers with Sorting Layers: the latter is for deciding the draw order of Sprites.
|
||||
\\\\
|
||||
Reference: \url{https://docs.unity3d.com/560/Documentation/Manual/Layers.html}
|
||||
|
||||
\section{Physics}
|
||||
\subsection{Rigidbody}
|
||||
References:
|
||||
\begin{itemize}
|
||||
\item \url{https://docs.unity3d.com/Manual/RigidbodiesOverview.html}
|
||||
\item \url{https://docs.unity3d.com/ScriptReference/Rigidbody.html}
|
||||
\end{itemize}
|
||||
|
||||
A \verb|Rigidbody| is the main component that enables phyiscal behaviour for a \verb|GameObject|;
|
||||
it puts the \verb|GameObject| under the control of the physics engine.
|
||||
The object will respond to gravity if it has a \verb|Rigidbody| component attached, (provided that the \verb|useGravity|
|
||||
field is not set to \verb|false|.
|
||||
If one or more Collider components are added, the \verb|GameObject| is affected by incoming collisions (from other Colliders)
|
||||
according to its shape, mass, momentum, linear, \& angular velocities, as well as Physics Materials which defined
|
||||
bounciness \& friction.
|
||||
\\\\
|
||||
Since a \verb|Rigidbody| component takes over the movement of the \verb|GameObject| that it's attached to, you normally
|
||||
shouldn't try to move it from a script by changing the Transform properties such as position \& rotation; instead you
|
||||
should apply forces to push the \verb|GameObject| and let the physics engine calculate the results.
|
||||
When a \verb|Rigidbody| is moving slower than a defined minimum linear or rotational speed, the physics engine assumes
|
||||
that it has come to a halt.
|
||||
When this happens, the \verb|GameObject| does not move again until it receives a collision or force, and so it is set to
|
||||
``\textbf{sleeping}'' mode.
|
||||
This optimisation means that no processor time is spent updating the \verb|Rigidbody| until the next time that is
|
||||
``awoken'', i.e. set in motion again.
|
||||
Sleeping can also be useful as it removes small ``jitters'' that may happen due to inaccuracies in the physics simulation.
|
||||
In your scripts which apply physics forces to Rigidbodies, use the \verb|FixedUpdate()| method rather than the
|
||||
\verb|Update()| method, since \verb|FixedUpdate()| is synced with the physics simulation updates.
|
||||
\\\\
|
||||
\verb|Rigidbody| properties:
|
||||
\begin{itemize}
|
||||
\item \mintinline{csharp}{public float drag}
|
||||
\item \mintinline{csharp}{public float angularDrag}
|
||||
\item \mintinline{csharp}{public float mass}
|
||||
\item \mintinline{csharp}{public Vector3 velocity}
|
||||
\item \mintinline{csharp}{public Vector3 angularVelocity}
|
||||
\item \mintinline{csharp}{public Vector3 centerOfMass} (offset from Transform centre).
|
||||
\end{itemize}
|
||||
|
||||
\verb|Rigidbody| methods
|
||||
\begin{itemize}
|
||||
\item \mintinline{csharp}{public void AddForce(Vector3 force)} (\verb|force| is a vector in world co-ordinates
|
||||
applied through the centre of mass of the \verb|Rigidbody|.
|
||||
\item \mintinline{csharp}{public void AddRelativeForce(Vector3 force)} (\verb|force| is a vector in local
|
||||
co-ordinates).
|
||||
\item \mintinline{csharp}{public void AddForceAtPosition(Vector3 force, Vector3 position)}
|
||||
|
||||
\end{itemize}
|
||||
|
||||
\subsection{Colliders}
|
||||
Reference: \url{https://docs.unity3d.com/Manual/CollidersOverview.html}
|
||||
\\\\
|
||||
\textbf{Collider} components define the shape of an object for the purposes of physical collisions.
|
||||
Colliders are invisible at runtime, and do not need to be the exact same shape as the object's mesh; a rough
|
||||
approximation is of the shape is often more efficient, and is indistinguishable in gameplay.
|
||||
The simplest (\& least processor-intensive) colliders are the \textbf{primitive} collider types, which all
|
||||
inherit from the superclass \verb|Collider|.
|
||||
In 3D, these are the \verb|BoxCollider|, \verb|SphereCollider|, \& \verb|CapsuleCollider|.
|
||||
In 2D, these are \verb|BoxCollider2D| \& \verb|CircleCollider2D|.
|
||||
Any number of these can be added to a single object to create composite colliders to reasonably approximate a 3D
|
||||
model.
|
||||
\\\\
|
||||
If you need more accuracy (at increased processor cost), use \textbf{\texttt{MeshCollider}} which accurately
|
||||
matches the 3D graphical model (the polygonal mesh).
|
||||
A \verb|MeshCollider| will be unable to collide with another \verb|MeshCollider| unless you mark it as
|
||||
\verb|Convex| in the inspector.
|
||||
This will generate the collider shape as a ``convex hull'' which is like the original mesh with concavities
|
||||
filled in.
|
||||
The general rule is to use mesh colliders for static scene geometry (walls, ground, etc.) and to approximate the
|
||||
shape of moving objects using composite primitive colliders.
|
||||
\begin{figure}[H]
|
||||
\centering
|
||||
\includegraphics[width=0.7\textwidth]{./images/MeshCollider.png}
|
||||
\caption{\texttt{MeshCollider}: Convex Hull vs Non-Convex}
|
||||
\end{figure}
|
||||
|
||||
\begin{figure}[H]
|
||||
\centering
|
||||
\includegraphics[width=0.7\textwidth]{./images/CompositeCollider.png}
|
||||
\caption{Composite Collider}
|
||||
\end{figure}
|
||||
|
||||
\subsubsection{Collisions}
|
||||
Reference: \url{https://docs.unity3d.com/ScriptReference/Collision.html}
|
||||
\\\\
|
||||
Any object with a Collider receives messages from the physics engine when it collides with other Colliders.
|
||||
Any script on the object may choose to respond by implementing the following methods:
|
||||
\begin{itemize}
|
||||
\item \mintinline{csharp}{void OnCollisionEnter(Collision collision)} (the \verb|Collision| object contains
|
||||
information about contact points, impact velocity, etc.)
|
||||
\item \mintinline{csharp}{void OnCollisionExit(Collision collision)}
|
||||
\item \mintinline{csharp}{void OnCollisionStay(Collision collision)}
|
||||
\end{itemize}
|
||||
|
||||
The \verb|OnCollision| methods receive objects of type \verb|Collision|, which contain useful information such as:
|
||||
\begin{itemize}
|
||||
\item \verb|collider|: The \verb|Collider| object that was hit.
|
||||
\item \verb|contacts|: The contact point(s) generated by the physics engine as an array of
|
||||
\verb|ContactPoint| structs.
|
||||
\item \verb|gameObject|: The \verb|GameObject| whose collider was collided with.
|
||||
\item \verb|relativeVelocity|: The relative linear velocity of the two colliding objects as a \verb|Vector3|.
|
||||
\item \verb|rigidbody|: The \verb|Rigidbody| that was hit; this is \verb|null| if the object had a collider
|
||||
but no \verb|Rigidbody|.
|
||||
\end{itemize}
|
||||
|
||||
\subsubsection{\texttt{ContactPoint} Struct}
|
||||
Reference: \url{https://docs.unity3d.com/ScriptReference/ContactPoint.html}
|
||||
\\\\
|
||||
\verb|Collision| objects contain arrays of \verb|ContactPoint| structs in their \verb|.contacts| member variable.
|
||||
The member data of the \verb|ContactPoint| struct is as follows:
|
||||
\begin{itemize}
|
||||
\item \verb|point|: The point of contact in \verb|Vector3| world co-ordinates.
|
||||
\item \verb|normal|: The surface normal at the contact point in \verb|Vector3|.
|
||||
\item \verb|otherCollider|: The other \verb|Collider| in contact at the point.
|
||||
\item \verb|thisCollider|: The first collider in contact at the point (useful if a \verb|GameObject| has
|
||||
more than one \verb|Collider| and we need to know which one).
|
||||
\end{itemize}
|
||||
|
||||
These fields allow us to operate on the object that we hit and to create accurate special effects etc. at the
|
||||
point of contact, rotated according to the surface normal at that point.
|
||||
|
||||
\subsubsection{\texttt{PhysicMaterial}}
|
||||
When Colliders interact, their surfaces need to simulate the properties of the material that they are supposed to
|
||||
represent.
|
||||
For example, a sheet of ice will be slippery while a rubber ball will offer a lot of friction and be very bouncy.
|
||||
Although the shape of colliders is not deformed during Collisions (hence the term ``rigid body physics''), their
|
||||
friction \& bounce can be configured using \verb|PhysicMaterial|s.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
\end{document}
|
@ -0,0 +1,3 @@
|
||||
\begin{Verbatim}[commandchars=\\\{\}]
|
||||
\PYG{k}{public}\PYG{+w}{ }\PYG{k}{void}\PYG{+w}{ }\PYG{n+nf}{AddForceAtPosition}\PYG{p}{(}\PYG{n}{Vector3}\PYG{+w}{ }\PYG{n}{force}\PYG{p}{,}\PYG{+w}{ }\PYG{n}{Vector3}\PYG{+w}{ }\PYG{n}{position}\PYG{p}{)}
|
||||
\end{Verbatim}
|
@ -0,0 +1,5 @@
|
||||
\begin{Verbatim}[commandchars=\\\{\},codes={\catcode`\$=3\catcode`\^=7\catcode`\_=8\relax}]
|
||||
\PYG{c+c1}{// note that Input.mousePosition gives a Vector4 where the $z$ component is 0}
|
||||
\PYG{c+c1}{// the screen is 2D of course; the $z$ component of the Vector3 supplied to ScreenToWorldPoint is a world-coordinate distance into the world.}
|
||||
\PYG{n}{Vector3}\PYG{+w}{ }\PYG{n}{mousePosInWorld}\PYG{+w}{ }\PYG{o}{=}\PYG{+w}{ }\PYG{n}{Camera}\PYG{p}{.}\PYG{n}{main}\PYG{p}{.}\PYG{n}{ScreenToWorldPoint}\PYG{p}{(}\PYG{n}{Input}\PYG{p}{.}\PYG{n}{mousePosition}\PYG{p}{);}
|
||||
\end{Verbatim}
|
@ -0,0 +1,3 @@
|
||||
\begin{Verbatim}[commandchars=\\\{\}]
|
||||
\PYG{k}{public}\PYG{+w}{ }\PYG{n}{Vector3}\PYG{+w}{ }\PYG{n}{angularVelocity}
|
||||
\end{Verbatim}
|
@ -0,0 +1,10 @@
|
||||
\begin{Verbatim}[commandchars=\\\{\},codes={\catcode`\$=3\catcode`\^=7\catcode`\_=8\relax}]
|
||||
\PYG{c+c1}{// local space to global}
|
||||
\PYG{k}{public}\PYG{+w}{ }\PYG{n}{Vector3}\PYG{+w}{ }\PYG{n+nf}{TransformPoint}\PYG{p}{(}\PYG{n}{Vector3}\PYG{+w}{ }\PYG{n}{position}\PYG{p}{);}
|
||||
\PYG{k}{public}\PYG{+w}{ }\PYG{n}{Vector3}\PYG{+w}{ }\PYG{n+nf}{TransformDirection}\PYG{p}{(}\PYG{n}{Vector3}\PYG{+w}{ }\PYG{n}{direction}\PYG{p}{);}
|
||||
\PYG{k}{public}\PYG{+w}{ }\PYG{n}{Vector3}\PYG{+w}{ }\PYG{n+nf}{TransformVector}\PYG{p}{(}\PYG{n}{Vector3}\PYG{+w}{ }\PYG{n}{vector}\PYG{p}{);}
|
||||
\PYG{c+c1}{// global to local}
|
||||
\PYG{k}{public}\PYG{+w}{ }\PYG{n}{Vector3}\PYG{+w}{ }\PYG{n+nf}{InverseTransformPoint}\PYG{p}{(}\PYG{n}{Vector3}\PYG{+w}{ }\PYG{n}{position}\PYG{p}{);}
|
||||
\PYG{k}{public}\PYG{+w}{ }\PYG{n}{Vector3}\PYG{+w}{ }\PYG{n+nf}{InverseTransformDirection}\PYG{p}{(}\PYG{n}{Vector3}\PYG{+w}{ }\PYG{n}{direction}\PYG{p}{);}
|
||||
\PYG{k}{public}\PYG{+w}{ }\PYG{n}{Vector3}\PYG{+w}{ }\PYG{n+nf}{InverseTransformVector}\PYG{p}{(}\PYG{n}{Vector3}\PYG{+w}{ }\PYG{n}{vector}\PYG{p}{);}
|
||||
\end{Verbatim}
|
@ -0,0 +1,5 @@
|
||||
\begin{Verbatim}[commandchars=\\\{\},codes={\catcode`\$=3\catcode`\^=7\catcode`\_=8\relax}]
|
||||
\PYG{k}{if}\PYG{+w}{ }\PYG{p}{(}\PYG{n}{Input}\PYG{p}{.}\PYG{n}{GetKey}\PYG{p}{(}\PYG{n}{KeyCode}\PYG{p}{.}\PYG{n}{LeftArrow}\PYG{p}{))}\PYG{+w}{ }\PYG{p}{\PYGZob{}}
|
||||
\PYG{+w}{ }\PYG{n}{RotateCameraAroundMarsSomehow}\PYG{p}{();}
|
||||
\PYG{p}{\PYGZcb{}}
|
||||
\end{Verbatim}
|
@ -0,0 +1,3 @@
|
||||
\begin{Verbatim}[commandchars=\\\{\},codes={\catcode`\$=3\catcode`\^=7\catcode`\_=8\relax}]
|
||||
\PYG{n}{GameObject}\PYG{+w}{ }\PYG{n}{otherMarsObject}\PYG{+w}{ }\PYG{o}{=}\PYG{+w}{ }\PYG{n}{Instantiate}\PYG{p}{(}\PYG{n}{marsObject}\PYG{p}{);}
|
||||
\end{Verbatim}
|
@ -0,0 +1,15 @@
|
||||
\begin{Verbatim}[commandchars=\\\{\},codes={\catcode`\$=3\catcode`\^=7\catcode`\_=8\relax}]
|
||||
\PYG{k}{public}\PYG{+w}{ }\PYG{k}{class}\PYG{+w}{ }\PYG{n+nc}{GameManager}\PYG{+w}{ }\PYG{p}{:}\PYG{+w}{ }\PYG{n}{MonoBehaviour}\PYG{+w}{ }\PYG{p}{\PYGZob{}}
|
||||
\PYG{+w}{ }\PYG{c+c1}{// inspector settings}
|
||||
\PYG{+w}{ }\PYG{k}{public}\PYG{+w}{ }\PYG{n}{GameObject}\PYG{+w}{ }\PYG{n}{marsObject}\PYG{p}{;}
|
||||
\PYG{+w}{ }\PYG{k}{void}\PYG{+w}{ }\PYG{n+nf}{Start}\PYG{p}{()}\PYG{+w}{ }\PYG{p}{\PYGZob{}}
|
||||
\PYG{+w}{ }\PYG{n}{marsObject}\PYG{p}{.}\PYG{n}{transform}\PYG{p}{.}\PYG{n}{position}\PYG{+w}{ }\PYG{o}{=}\PYG{+w}{ }\PYG{k}{new}\PYG{+w}{ }\PYG{n}{Vector3}\PYG{p}{(}\PYG{l+m}{0}\PYG{p}{,}\PYG{l+m}{0}\PYG{p}{,}\PYG{l+m}{0}\PYG{p}{);}
|
||||
\PYG{+w}{ }\PYG{n}{Camera}\PYG{p}{.}\PYG{n}{main}\PYG{p}{.}\PYG{n}{transform}\PYG{p}{.}\PYG{n}{position}\PYG{+w}{ }\PYG{o}{=}\PYG{+w}{ }\PYG{k}{new}\PYG{+w}{ }\PYG{n}{Vector3}\PYG{p}{(}\PYG{l+m}{0}\PYG{p}{,}\PYG{l+m}{0}\PYG{p}{,}\PYG{l+m}{100}\PYG{p}{);}
|
||||
\PYG{+w}{ }\PYG{n}{Camera}\PYG{p}{.}\PYG{n}{main}\PYG{p}{.}\PYG{n}{transform}\PYG{p}{.}\PYG{n}{LookAt}\PYG{p}{(}\PYG{n}{marsObject}\PYG{p}{.}\PYG{n}{transform}\PYG{p}{);}
|
||||
\PYG{+w}{ }\PYG{p}{\PYGZcb{}}
|
||||
\PYG{+w}{ }\PYG{k}{void}\PYG{+w}{ }\PYG{n+nf}{Update}\PYG{p}{()}\PYG{+w}{ }\PYG{p}{\PYGZob{}}
|
||||
\PYG{+w}{ }\PYG{c+c1}{// programmatically rotate Mars each frame:}
|
||||
\PYG{+w}{ }\PYG{n}{marsObject}\PYG{p}{.}\PYG{n}{transform}\PYG{p}{.}\PYG{n}{Rotate}\PYG{p}{(}\PYG{k}{new}\PYG{+w}{ }\PYG{n}{Vector3}\PYG{p}{(}\PYG{l+m}{0}\PYG{p}{,}\PYG{l+m}{10}\PYG{o}{*}\PYG{n}{Time}\PYG{p}{.}\PYG{n}{deltaTime}\PYG{p}{,}\PYG{l+m}{0}\PYG{p}{));}
|
||||
\PYG{+w}{ }\PYG{p}{\PYGZcb{}}
|
||||
\PYG{p}{\PYGZcb{}}
|
||||
\end{Verbatim}
|
@ -0,0 +1,3 @@
|
||||
\begin{Verbatim}[commandchars=\\\{\}]
|
||||
\PYG{k}{public}\PYG{+w}{ }\PYG{k}{void}\PYG{+w}{ }\PYG{n+nf}{AddRelativeForce}\PYG{p}{(}\PYG{n}{Vector3}\PYG{+w}{ }\PYG{n}{force}\PYG{p}{)}
|
||||
\end{Verbatim}
|
@ -0,0 +1,3 @@
|
||||
\begin{Verbatim}[commandchars=\\\{\},codes={\catcode`\$=3\catcode`\^=7\catcode`\_=8\relax}]
|
||||
\PYG{n}{camera}\PYG{p}{.}\PYG{n}{transform}\PYG{p}{.}\PYG{n}{RotateAroudn}\PYG{p}{(}\PYG{n}{Vector3}\PYG{p}{.}\PYG{n}{zero}\PYG{p}{,}\PYG{+w}{ }\PYG{n}{Vector3}\PYG{p}{.}\PYG{n}{up}\PYG{p}{,}\PYG{+w}{ }\PYG{l+m}{50f}\PYG{+w}{ }\PYG{o}{*}\PYG{+w}{ }\PYG{n}{Time}\PYG{p}{.}\PYG{n}{deltaTime}\PYG{p}{);}
|
||||
\end{Verbatim}
|
@ -0,0 +1,3 @@
|
||||
\begin{Verbatim}[commandchars=\\\{\}]
|
||||
\PYG{k}{public}\PYG{+w}{ }\PYG{k+kt}{float}\PYG{+w}{ }\PYG{n}{angularDrag}
|
||||
\end{Verbatim}
|
@ -0,0 +1,18 @@
|
||||
\begin{Verbatim}[commandchars=\\\{\},codes={\catcode`\$=3\catcode`\^=7\catcode`\_=8\relax}]
|
||||
\PYG{k}{public}\PYG{+w}{ }\PYG{k}{class}\PYG{+w}{ }\PYG{n+nc}{ExampleScript}\PYG{+w}{ }\PYG{p}{:}\PYG{+w}{ }\PYG{n}{MonoBehaviour}
|
||||
\PYG{p}{\PYGZob{}}
|
||||
\PYG{+w}{ }\PYG{c+c1}{// Launches a projectile after 2 seconds}
|
||||
|
||||
\PYG{+w}{ }\PYG{n}{Rigidbody}\PYG{+w}{ }\PYG{n}{projectile}\PYG{p}{;}
|
||||
|
||||
\PYG{+w}{ }\PYG{k}{void}\PYG{+w}{ }\PYG{n+nf}{Start}\PYG{p}{()}\PYG{+w}{ }\PYG{p}{\PYGZob{}}
|
||||
\PYG{+w}{ }\PYG{n}{Invoke}\PYG{p}{(}\PYG{l+s}{\PYGZdq{}LaunchProjectile\PYGZdq{}}\PYG{p}{,}\PYG{+w}{ }\PYG{l+m}{2f}\PYG{p}{);}
|
||||
\PYG{+w}{ }\PYG{p}{\PYGZcb{}}
|
||||
|
||||
\PYG{+w}{ }\PYG{k}{void}\PYG{+w}{ }\PYG{n+nf}{LaunchProjectile}\PYG{p}{()}
|
||||
\PYG{+w}{ }\PYG{p}{\PYGZob{}}
|
||||
\PYG{+w}{ }\PYG{n}{Rigidbody}\PYG{+w}{ }\PYG{n}{instance}\PYG{+w}{ }\PYG{o}{=}\PYG{+w}{ }\PYG{n}{Instantiate}\PYG{p}{(}\PYG{n}{projectile}\PYG{p}{);}
|
||||
\PYG{+w}{ }\PYG{n}{instance}\PYG{p}{.}\PYG{n}{velocity}\PYG{+w}{ }\PYG{o}{=}\PYG{+w}{ }\PYG{n}{Random}\PYG{p}{.}\PYG{n}{insideUnitSphere}\PYG{+w}{ }\PYG{o}{*}\PYG{+w}{ }\PYG{l+m}{5f}\PYG{p}{;}
|
||||
\PYG{+w}{ }\PYG{p}{\PYGZcb{}}
|
||||
\PYG{p}{\PYGZcb{}}
|
||||
\end{Verbatim}
|
@ -0,0 +1,8 @@
|
||||
\begin{Verbatim}[commandchars=\\\{\},codes={\catcode`\$=3\catcode`\^=7\catcode`\_=8\relax}]
|
||||
\PYG{n}{GameObject}\PYG{+w}{ }\PYG{n}{go1}\PYG{p}{,}\PYG{+w}{ }\PYG{n}{go2}\PYG{p}{;}\PYG{+w}{ }\PYG{c+c1}{// it's assumed that these are not nulls!}
|
||||
|
||||
\PYG{n}{Vector3}\PYG{+w}{ }\PYG{n}{difference}\PYG{p}{,}\PYG{+w}{ }\PYG{n}{direction}\PYG{p}{;}
|
||||
\PYG{n}{difference}\PYG{+w}{ }\PYG{o}{=}\PYG{+w}{ }\PYG{n}{go2}\PYG{p}{.}\PYG{n}{transform}\PYG{p}{.}\PYG{n}{position}\PYG{+w}{ }\PYG{o}{\PYGZhy{}}\PYG{+w}{ }\PYG{n}{go1}\PYG{p}{.}\PYG{n}{transform}\PYG{p}{.}\PYG{n}{position}\PYG{p}{;}
|
||||
\PYG{n}{direction}\PYG{+w}{ }\PYG{o}{=}\PYG{+w}{ }\PYG{n}{difference}\PYG{p}{.}\PYG{n}{normalized}\PYG{p}{;}
|
||||
\PYG{k+kt}{float}\PYG{+w}{ }\PYG{n}{distance}\PYG{+w}{ }\PYG{o}{=}\PYG{+w}{ }\PYG{n}{difference}\PYG{p}{.}\PYG{n}{magnitude}\PYG{p}{;}
|
||||
\end{Verbatim}
|
@ -0,0 +1,11 @@
|
||||
\begin{Verbatim}[commandchars=\\\{\},codes={\catcode`\$=3\catcode`\^=7\catcode`\_=8\relax}]
|
||||
\PYG{c+c1}{// these happen for Collider-to-Collider collisions}
|
||||
\PYG{n}{OnCollisionEnter}\PYG{p}{(}\PYG{n}{Collision}\PYG{+w}{ }\PYG{n}{coll}\PYG{p}{);}
|
||||
\PYG{n}{OnCollisionExit}\PYG{p}{(}\PYG{n}{Collision}\PYG{+w}{ }\PYG{n}{coll}\PYG{p}{);}
|
||||
\PYG{n}{OnCollisionStay}\PYG{p}{(}\PYG{n}{Collision}\PYG{+w}{ }\PYG{n}{coll}\PYG{p}{);}
|
||||
|
||||
\PYG{c+c1}{// these happen for Trigger-to-Trigger collisions}
|
||||
\PYG{n}{OnTriggerEnter}\PYG{p}{(}\PYG{n}{Collider}\PYG{+w}{ }\PYG{n}{coll}\PYG{p}{);}
|
||||
\PYG{n}{OnTriggerExit}\PYG{p}{(}\PYG{n}{Collider}\PYG{+w}{ }\PYG{n}{coll}\PYG{p}{);}
|
||||
\PYG{n}{OnTriggerStay}\PYG{p}{(}\PYG{n}{Collider}\PYG{+w}{ }\PYG{n}{coll}\PYG{p}{);}
|
||||
\end{Verbatim}
|
@ -0,0 +1,3 @@
|
||||
\begin{Verbatim}[commandchars=\\\{\},codes={\catcode`\$=3\catcode`\^=7\catcode`\_=8\relax}]
|
||||
\PYG{n}{camera}\PYG{p}{.}\PYG{n}{transform}\PYG{p}{.}\PYG{n}{RotateAround}\PYG{p}{(}\PYG{n}{Vector3}\PYG{p}{.}\PYG{n}{zero}\PYG{p}{,}\PYG{+w}{ }\PYG{n}{camera}\PYG{p}{.}\PYG{n}{transform}\PYG{p}{.}\PYG{n}{up}\PYG{p}{,}\PYG{+w}{ }\PYG{l+m}{50f}\PYG{+w}{ }\PYG{o}{*}\PYG{+w}{ }\PYG{n}{Time}\PYG{p}{.}\PYG{n}{deltaTime}\PYG{p}{);}
|
||||
\end{Verbatim}
|
@ -0,0 +1,3 @@
|
||||
\begin{Verbatim}[commandchars=\\\{\}]
|
||||
\PYG{k}{public}\PYG{+w}{ }\PYG{k+kt}{float}\PYG{+w}{ }\PYG{n}{drag}
|
||||
\end{Verbatim}
|
@ -0,0 +1,3 @@
|
||||
\begin{Verbatim}[commandchars=\\\{\}]
|
||||
\PYG{k}{public}\PYG{+w}{ }\PYG{k}{void}\PYG{+w}{ }\PYG{n+nf}{AddForce}\PYG{p}{(}\PYG{n}{Vector3}\PYG{+w}{ }\PYG{n}{force}\PYG{p}{)}
|
||||
\end{Verbatim}
|
@ -0,0 +1,24 @@
|
||||
\begin{Verbatim}[commandchars=\\\{\},codes={\catcode`\$=3\catcode`\^=7\catcode`\_=8\relax}]
|
||||
\PYG{k}{public}\PYG{+w}{ }\PYG{k}{class}\PYG{+w}{ }\PYG{n+nc}{Area}\PYG{+w}{ }\PYG{p}{:}\PYG{+w}{ }\PYG{n}{MonoBehaviour}\PYG{+w}{ }\PYG{p}{\PYGZob{}}
|
||||
\PYG{+w}{ }\PYG{c+c1}{// inspector settings}
|
||||
\PYG{+w}{ }\PYG{k}{public}\PYG{+w}{ }\PYG{n}{Transform}\PYG{+w}{ }\PYG{n}{innerWallsGroup}\PYG{p}{;}
|
||||
\PYG{+w}{ }\PYG{k}{public}\PYG{+w}{ }\PYG{n}{Vector3}\PYG{+w}{ }\PYG{n}{wallsPos}\PYG{p}{;}
|
||||
|
||||
\PYG{+w}{ }\PYG{k}{private}\PYG{+w}{ }\PYG{n}{List}\PYG{o}{\PYGZlt{}}\PYG{n}{GameObject}\PYG{o}{\PYGZgt{}}\PYG{+w}{ }\PYG{n}{innerWalls}\PYG{+w}{ }\PYG{o}{=}\PYG{+w}{ }\PYG{k}{new}\PYG{+w}{ }\PYG{n}{List}\PYG{o}{\PYGZlt{}}\PYG{n}{GameObject}\PYG{o}{\PYGZgt{}}\PYG{p}{();}
|
||||
\PYG{+w}{ }\PYG{k}{private}\PYG{+w}{ }\PYG{k+kt}{bool}\PYG{p}{[]}\PYG{+w}{ }\PYG{n}{wallIsRaised}\PYG{+w}{ }\PYG{o}{=}\PYG{+w}{ }\PYG{k}{null}\PYG{p}{;}
|
||||
|
||||
\PYG{+w}{ }\PYG{k}{void}\PYG{+w}{ }\PYG{n+nf}{Start}\PYG{p}{()}\PYG{+w}{ }\PYG{p}{\PYGZob{}}
|
||||
\PYG{+w}{ }\PYG{k}{foreach}\PYG{+w}{ }\PYG{p}{(}\PYG{n}{Transform}\PYG{+w}{ }\PYG{n}{t}\PYG{+w}{ }\PYG{k}{in}\PYG{+w}{ }\PYG{n}{innerWallsGroup}\PYG{p}{)}\PYG{+w}{ }\PYG{p}{\PYGZob{}}
|
||||
\PYG{+w}{ }\PYG{n}{innerWalls}\PYG{p}{.}\PYG{n}{Add}\PYG{p}{(}\PYG{n}{t}\PYG{p}{.}\PYG{n}{gameObject}\PYG{p}{);}
|
||||
\PYG{+w}{ }\PYG{p}{\PYGZcb{}}
|
||||
|
||||
\PYG{+w}{ }\PYG{n}{wallIsRaised}\PYG{+w}{ }\PYG{o}{=}\PYG{+w}{ }\PYG{k}{new}\PYG{+w}{ }\PYG{k+kt}{bool}\PYG{p}{[}\PYG{n}{innerWalls}\PYG{p}{.}\PYG{n}{Count}\PYG{p}{];}
|
||||
|
||||
\PYG{+w}{ }\PYG{k}{for}\PYG{+w}{ }\PYG{p}{(}\PYG{k+kt}{int}\PYG{+w}{ }\PYG{n}{i}\PYG{+w}{ }\PYG{o}{=}\PYG{+w}{ }\PYG{l+m}{0}\PYG{p}{;}\PYG{+w}{ }\PYG{n}{i}\PYG{+w}{ }\PYG{o}{\PYGZlt{}}\PYG{+w}{ }\PYG{n}{innerWalls}\PYG{p}{.}\PYG{n}{Coutn}\PYG{p}{;}\PYG{+w}{ }\PYG{n}{i}\PYG{o}{++}\PYG{p}{)}\PYG{+w}{ }\PYG{p}{\PYGZob{}}
|
||||
\PYG{+w}{ }\PYG{n}{innerWalls}\PYG{p}{[}\PYG{n}{i}\PYG{p}{].}\PYG{n}{transform}\PYG{p}{.}\PYG{n}{position}\PYG{+w}{ }\PYG{o}{=}\PYG{+w}{ }\PYG{n}{wallsPos}\PYG{p}{;}
|
||||
\PYG{+w}{ }\PYG{n}{innerWalls}\PYG{p}{[}\PYG{n}{i}\PYG{p}{].}\PYG{n}{SetActive}\PYG{p}{(}\PYG{k}{false}\PYG{p}{);}
|
||||
\PYG{+w}{ }\PYG{n}{wallIsRaised}\PYG{p}{[}\PYG{n}{i}\PYG{p}{]}\PYG{+w}{ }\PYG{o}{=}\PYG{+w}{ }\PYG{k}{false}\PYG{p}{;}
|
||||
\PYG{+w}{ }\PYG{p}{\PYGZcb{}}
|
||||
\PYG{+w}{ }\PYG{p}{\PYGZcb{}}
|
||||
\PYG{p}{\PYGZcb{}}
|
||||
\end{Verbatim}
|
@ -0,0 +1,9 @@
|
||||
\begin{Verbatim}[commandchars=\\\{\},codes={\catcode`\$=3\catcode`\^=7\catcode`\_=8\relax}]
|
||||
\PYG{k}{public}\PYG{+w}{ }\PYG{k}{class}\PYG{+w}{ }\PYG{n+nc}{GameManager}\PYG{+w}{ }\PYG{p}{:}\PYG{+w}{ }\PYG{n}{MonoBehaviour}\PYG{+w}{ }\PYG{p}{\PYGZob{}}
|
||||
\PYG{+w}{ }\PYG{k}{public}\PYG{+w}{ }\PYG{k}{static}\PYG{+w}{ }\PYG{n}{GameManager}\PYG{+w}{ }\PYG{n}{instance}\PYG{p}{;}
|
||||
|
||||
\PYG{+w}{ }\PYG{k}{void}\PYG{+w}{ }\PYG{n+nf}{Start}\PYG{+w}{ }\PYG{p}{()}\PYG{+w}{ }\PYG{p}{\PYGZob{}}
|
||||
\PYG{+w}{ }\PYG{n}{instance}\PYG{+w}{ }\PYG{o}{=}\PYG{+w}{ }\PYG{k}{this}\PYG{p}{;}
|
||||
\PYG{+w}{ }\PYG{p}{\PYGZcb{}}
|
||||
\PYG{p}{\PYGZcb{}}
|
||||
\end{Verbatim}
|
@ -0,0 +1,17 @@
|
||||
\begin{Verbatim}[commandchars=\\\{\},codes={\catcode`\$=3\catcode`\^=7\catcode`\_=8\relax}]
|
||||
\PYG{k}{using}\PYG{+w}{ }\PYG{n+nn}{System.Collections}\PYG{p}{;}
|
||||
\PYG{k}{using}\PYG{+w}{ }\PYG{n+nn}{System.Collections.Generic}\PYG{p}{;}
|
||||
\PYG{k}{using}\PYG{+w}{ }\PYG{n+nn}{UnityEngine}\PYG{p}{;}
|
||||
|
||||
\PYG{k}{public}\PYG{+w}{ }\PYG{k}{class}\PYG{+w}{ }\PYG{n+nc}{GameManagerScript}\PYG{+w}{ }\PYG{p}{:}\PYG{+w}{ }\PYG{n}{MonoBehaviour}\PYG{+w}{ }\PYG{p}{\PYGZob{}}
|
||||
\PYG{+w}{ }\PYG{k}{public}\PYG{+w}{ }\PYG{n}{GameObject}\PYG{+w}{ }\PYG{n}{marsObject}\PYG{p}{;}
|
||||
\PYG{+w}{ }\PYG{c+c1}{// Use this for initialization}
|
||||
\PYG{+w}{ }\PYG{k}{void}\PYG{+w}{ }\PYG{n+nf}{Start}\PYG{+w}{ }\PYG{p}{()}\PYG{+w}{ }\PYG{p}{\PYGZob{}}
|
||||
\PYG{+w}{ }\PYG{n}{Camera}\PYG{p}{.}\PYG{n}{main}\PYG{p}{.}\PYG{n}{transform}\PYG{p}{.}\PYG{n}{position}\PYG{+w}{ }\PYG{o}{=}\PYG{+w}{ }\PYG{k}{new}\PYG{+w}{ }\PYG{n}{Vector3}\PYG{+w}{ }\PYG{p}{(}\PYG{l+m}{0f}\PYG{p}{,}\PYG{+w}{ }\PYG{l+m}{0f}\PYG{p}{,}\PYG{+w}{ }\PYG{o}{\PYGZhy{}}\PYG{l+m}{100f}\PYG{p}{);}
|
||||
\PYG{+w}{ }\PYG{n}{Camera}\PYG{p}{.}\PYG{n}{main}\PYG{p}{.}\PYG{n}{transform}\PYG{p}{.}\PYG{n}{LookAt}\PYG{+w}{ }\PYG{p}{(}\PYG{n}{marsObject}\PYG{p}{.}\PYG{n}{transform}\PYG{p}{);}
|
||||
\PYG{+w}{ }\PYG{c+c1}{// use the physics engine to rotate Mars}
|
||||
\PYG{+w}{ }\PYG{c+c1}{// before this can run, you need to manually add a rigid body with 0 angular velocity and no gravity in the UI}
|
||||
\PYG{+w}{ }\PYG{n}{marsObject}\PYG{p}{.}\PYG{n}{GetComponent}\PYG{o}{\PYGZlt{}}\PYG{n}{Rigidbody}\PYG{o}{\PYGZgt{}}\PYG{p}{().}\PYG{n}{AddTorque}\PYG{+w}{ }\PYG{p}{(}\PYG{k}{new}\PYG{+w}{ }\PYG{n}{Vector3}\PYG{p}{(}\PYG{l+m}{0f}\PYG{p}{,}\PYG{l+m}{20f}\PYG{p}{,}\PYG{l+m}{0f}\PYG{p}{));}
|
||||
\PYG{+w}{ }\PYG{p}{\PYGZcb{}}
|
||||
\PYG{p}{\PYGZcb{}}
|
||||
\end{Verbatim}
|
@ -0,0 +1,3 @@
|
||||
\begin{Verbatim}[commandchars=\\\{\}]
|
||||
\PYG{k}{void}\PYG{+w}{ }\PYG{n+nf}{OnCollisionEnter}\PYG{p}{(}\PYG{n}{Collision}\PYG{+w}{ }\PYG{n}{collision}\PYG{p}{)}
|
||||
\end{Verbatim}
|
@ -0,0 +1,4 @@
|
||||
\begin{Verbatim}[commandchars=\\\{\},codes={\catcode`\$=3\catcode`\^=7\catcode`\_=8\relax}]
|
||||
\PYG{n}{GameObject}\PYG{+w}{ }\PYG{n}{targ}\PYG{p}{;}\PYG{+w}{ }\PYG{c+c1}{// assumed not to be null}
|
||||
\PYG{n}{Vector3}\PYG{+w}{ }\PYG{n}{screenPos}\PYG{+w}{ }\PYG{o}{=}\PYG{+w}{ }\PYG{n}{Camera}\PYG{p}{.}\PYG{n}{main}\PYG{p}{.}\PYG{n}{WorldToScreenPoint}\PYG{p}{(}\PYG{n}{targ}\PYG{p}{.}\PYG{n}{transform}\PYG{p}{.}\PYG{n}{position}\PYG{p}{);}
|
||||
\end{Verbatim}
|
@ -0,0 +1,5 @@
|
||||
\begin{Verbatim}[commandchars=\\\{\},codes={\catcode`\$=3\catcode`\^=7\catcode`\_=8\relax}]
|
||||
\PYG{n}{Vector3}\PYG{+w}{ }\PYG{n}{pt}\PYG{+w}{ }\PYG{o}{=}\PYG{+w}{ }\PYG{n}{transform}\PYG{p}{.}\PYG{n}{TransformPoint}\PYG{p}{(}\PYG{k}{new}\PYG{+w}{ }\PYG{n}{Vector3}\PYG{p}{(}\PYG{l+m}{0f}\PYG{p}{,}\PYG{+w}{ }\PYG{l+m}{0f}\PYG{p}{,}\PYG{+w}{ }\PYG{l+m}{10f}\PYG{p}{));}
|
||||
\PYG{c+c1}{// another way of doing the same would be:}
|
||||
\PYG{n}{Vector3}\PYG{+w}{ }\PYG{n}{pt}\PYG{+w}{ }\PYG{o}{=}\PYG{+w}{ }\PYG{n}{transform}\PYG{p}{.}\PYG{n}{position}\PYG{+w}{ }\PYG{o}{+}\PYG{+w}{ }\PYG{l+m}{10f}\PYG{+w}{ }\PYG{o}{*}\PYG{+w}{ }\PYG{n}{transform}\PYG{p}{.}\PYG{n}{forward}\PYG{p}{;}
|
||||
\end{Verbatim}
|
@ -0,0 +1,24 @@
|
||||
\begin{Verbatim}[commandchars=\\\{\},codes={\catcode`\$=3\catcode`\^=7\catcode`\_=8\relax}]
|
||||
\PYG{c+c1}{// Here, we find the 3D position that's just above the enemy's head, and convert this to a vieweort position when viewed through the player's camera.}
|
||||
\PYG{c+c1}{// Finally, this viewport position is converted to a pixel position as required by the GUI sprite.}
|
||||
\PYG{k}{public}\PYG{+w}{ }\PYG{k}{class}\PYG{+w}{ }\PYG{n+nc}{MonsterManager}\PYG{+w}{ }\PYG{p}{:}\PYG{+w}{ }\PYG{n}{MonoBehaviour}\PYG{+w}{ }\PYG{p}{\PYGZob{}}
|
||||
\PYG{+w}{ }\PYG{k}{void}\PYG{+w}{ }\PYG{n+nf}{Update}\PYG{+w}{ }\PYG{p}{()}\PYG{+w}{ }\PYG{p}{\PYGZob{}}
|
||||
\PYG{+w}{ }\PYG{k}{if}\PYG{+w}{ }\PYG{p}{(}\PYG{n}{GameManager}\PYG{p}{.}\PYG{n}{gameState}\PYG{o}{==}\PYG{n}{GameStates}\PYG{p}{.}\PYG{n}{Playing}\PYG{p}{)}\PYG{+w}{ }\PYG{p}{\PYGZob{}}
|
||||
\PYG{+w}{ }\PYG{k}{if}\PYG{+w}{ }\PYG{p}{(}\PYG{n}{numMonstersAlive}\PYG{o}{==}\PYG{l+m}{1}\PYG{p}{)}\PYG{+w}{ }\PYG{p}{\PYGZob{}}
|
||||
\PYG{+w}{ }\PYG{c+c1}{// put the final enemy indicator (GUI object) above the final monster}
|
||||
\PYG{+w}{ }\PYG{n}{GameObject}\PYG{+w}{ }\PYG{n}{go}\PYG{+w}{ }\PYG{o}{=}\PYG{+w}{ }\PYG{n}{GUIManager}\PYG{p}{.}\PYG{n}{instance}\PYG{p}{.}\PYG{n}{finalEnemyIndicator}\PYG{p}{;}
|
||||
\PYG{+w}{ }\PYG{n}{Monster}\PYG{+w}{ }\PYG{n}{m}\PYG{+w}{ }\PYG{o}{=}\PYG{+w}{ }\PYG{n}{allActiveMonsters}\PYG{p}{[}\PYG{l+m}{0}\PYG{p}{];}
|
||||
\PYG{+w}{ }\PYG{n}{Bounds}\PYG{+w}{ }\PYG{n}{b}\PYG{+w}{ }\PYG{o}{=}\PYG{+w}{ }\PYG{n}{m}\PYG{p}{.}\PYG{n}{mycollider}\PYG{p}{.}\PYG{n}{bounds}\PYG{p}{;}
|
||||
\PYG{+w}{ }\PYG{n}{Vector3}\PYG{+w}{ }\PYG{n}{pos}\PYG{+w}{ }\PYG{o}{=}\PYG{+w}{ }\PYG{k}{new}\PYG{+w}{ }\PYG{n}{Vector3}\PYG{p}{(}\PYG{n}{b}\PYG{p}{.}\PYG{n}{center}\PYG{p}{.}\PYG{n}{x}\PYG{p}{,}\PYG{+w}{ }\PYG{n}{b}\PYG{p}{.}\PYG{n}{max}\PYG{p}{.}\PYG{n}{y}\PYG{+w}{ }\PYG{o}{+}\PYG{+w}{ }\PYG{l+m}{1f}\PYG{p}{,}\PYG{+w}{ }\PYG{n}{b}\PYG{p}{.}\PYG{n}{center}\PYG{p}{.}\PYG{n}{z}\PYG{p}{);}
|
||||
\PYG{+w}{ }\PYG{n}{Vector3}\PYG{+w}{ }\PYG{n}{viewPos}\PYG{+w}{ }\PYG{o}{=}\PYG{+w}{ }\PYG{n}{Player}\PYG{p}{.}\PYG{n}{myPlayer}\PYG{p}{.}\PYG{n}{fpsCamera}\PYG{p}{.}\PYG{n}{WorldToViewportPoint}\PYG{p}{(}\PYG{n}{pos}\PYG{p}{);}
|
||||
\PYG{+w}{ }\PYG{k}{if}\PYG{+w}{ }\PYG{p}{(}\PYG{n}{viewPos}\PYG{p}{.}\PYG{n}{x}\PYG{o}{\PYGZlt{}}\PYG{l+m}{0f}\PYG{+w}{ }\PYG{o}{||}\PYG{+w}{ }\PYG{n}{viewPos}\PYG{p}{.}\PYG{n}{x}\PYG{o}{\PYGZgt{}}\PYG{l+m}{1f}\PYG{+w}{ }\PYG{o}{||}\PYG{+w}{ }\PYG{n}{viewPos}\PYG{p}{.}\PYG{n}{y}\PYG{o}{\PYGZlt{}}\PYG{l+m}{0f}\PYG{+w}{ }\PYG{o}{||}\PYG{+w}{ }\PYG{n}{viewPos}\PYG{p}{.}\PYG{n}{y}\PYG{o}{\PYGZgt{}}\PYG{l+m}{1f}\PYG{+w}{ }\PYG{o}{||}\PYG{+w}{ }\PYG{n}{viewPos}\PYG{p}{.}\PYG{n}{z}\PYG{o}{\PYGZlt{}}\PYG{l+m}{0f}\PYG{p}{)}
|
||||
\PYG{+w}{ }\PYG{n}{go}\PYG{p}{.}\PYG{n}{SetActive}\PYG{p}{(}\PYG{k}{false}\PYG{p}{);}
|
||||
\PYG{+w}{ }\PYG{k}{else}\PYG{+w}{ }\PYG{p}{\PYGZob{}}
|
||||
\PYG{+w}{ }\PYG{n}{go}\PYG{p}{.}\PYG{n}{SetActive}\PYG{p}{(}\PYG{k}{true}\PYG{p}{);}
|
||||
\PYG{+w}{ }\PYG{n}{go}\PYG{p}{.}\PYG{n}{transform}\PYG{p}{.}\PYG{n}{position}\PYG{+w}{ }\PYG{o}{=}\PYG{+w}{ }\PYG{k}{new}\PYG{+w}{ }\PYG{n}{Vector2}\PYG{p}{(}\PYG{n}{viewPos}\PYG{p}{.}\PYG{n}{x}\PYG{o}{*}\PYG{n}{Screen}\PYG{p}{.}\PYG{n}{width}\PYG{p}{,}\PYG{+w}{ }\PYG{n}{viewPos}\PYG{p}{.}\PYG{n}{y}\PYG{o}{*}\PYG{n}{Screen}\PYG{p}{.}\PYG{n}{height}\PYG{p}{);}
|
||||
\PYG{+w}{ }\PYG{p}{\PYGZcb{}}
|
||||
\PYG{+w}{ }\PYG{p}{\PYGZcb{}}
|
||||
\PYG{+w}{ }\PYG{p}{\PYGZcb{}}
|
||||
\PYG{+w}{ }\PYG{p}{\PYGZcb{}}
|
||||
\PYG{p}{\PYGZcb{}}
|
||||
\end{Verbatim}
|
@ -0,0 +1,16 @@
|
||||
\begin{Verbatim}[commandchars=\\\{\},codes={\catcode`\$=3\catcode`\^=7\catcode`\_=8\relax}]
|
||||
\PYG{k}{public}\PYG{+w}{ }\PYG{k}{class}\PYG{+w}{ }\PYG{n+nc}{GameManager}\PYG{+w}{ }\PYG{p}{:}\PYG{+w}{ }\PYG{n}{MonoBehaviour}\PYG{+w}{ }\PYG{p}{\PYGZob{}}
|
||||
\PYG{+w}{ }\PYG{c+c1}{// inspector settings}
|
||||
\PYG{+w}{ }\PYG{k}{public}\PYG{+w}{ }\PYG{n}{gameObject}\PYG{+w}{ }\PYG{n}{marsObject}\PYG{p}{;}
|
||||
|
||||
\PYG{+w}{ }\PYG{c+c1}{// Start is called before the first frame update}
|
||||
\PYG{+w}{ }\PYG{k}{void}\PYG{+w}{ }\PYG{n+nf}{Start}\PYG{p}{()}\PYG{+w}{ }\PYG{p}{\PYGZob{}}
|
||||
\PYG{+w}{ }\PYG{n}{marsObject}\PYG{p}{.}\PYG{n}{transform}\PYG{p}{.}\PYG{n}{position}\PYG{+w}{ }\PYG{o}{=}\PYG{+w}{ }\PYG{k}{new}\PYG{+w}{ }\PYG{n}{Vector3}\PYG{p}{(}\PYG{l+m}{0}\PYG{p}{,}\PYG{l+m}{0}\PYG{p}{,}\PYG{l+m}{0}\PYG{p}{);}
|
||||
\PYG{+w}{ }\PYG{n}{Camera}\PYG{p}{.}\PYG{n}{main}\PYG{p}{.}\PYG{n}{transform}\PYG{p}{.}\PYG{n}{position}\PYG{+w}{ }\PYG{o}{=}\PYG{+w}{ }\PYG{k}{new}\PYG{+w}{ }\PYG{n}{Vector3}\PYG{p}{(}\PYG{l+m}{0}\PYG{p}{,}\PYG{l+m}{0}\PYG{p}{,}\PYG{l+m}{100}\PYG{p}{);}
|
||||
\PYG{+w}{ }\PYG{n}{Camera}\PYG{p}{.}\PYG{n}{main}\PYG{p}{.}\PYG{n}{transform}\PYG{p}{.}\PYG{n}{LookAt}\PYG{p}{(}\PYG{n}{marsObject}\PYG{p}{.}\PYG{n}{transform}\PYG{p}{);}
|
||||
|
||||
\PYG{+w}{ }\PYG{c+c1}{// before this can run, you need to manually add a rigid body with 0 angular velocity and no gravity in the UI}
|
||||
\PYG{+w}{ }\PYG{n}{marsObject}\PYG{p}{.}\PYG{n}{GetComponent}\PYG{o}{\PYGZlt{}}\PYG{n}{RigidBody}\PYG{o}{\PYGZgt{}}\PYG{p}{().}\PYG{n}{addTorque}\PYG{p}{(}\PYG{k}{new}\PYG{+w}{ }\PYG{n}{Vector3}\PYG{p}{(}\PYG{l+m}{0}\PYG{p}{,}\PYG{l+m}{20}\PYG{p}{,}\PYG{l+m}{0}\PYG{p}{));}
|
||||
\PYG{+w}{ }\PYG{p}{\PYGZcb{}}
|
||||
\PYG{p}{\PYGZcb{}}
|
||||
\end{Verbatim}
|
@ -0,0 +1,36 @@
|
||||
\begin{Verbatim}[commandchars=\\\{\},codes={\catcode`\$=3\catcode`\^=7\catcode`\_=8\relax}]
|
||||
\PYG{k}{private}\PYG{+w}{ }\PYG{k}{void}\PYG{+w}{ }\PYG{n+nf}{Start}\PYG{p}{()}\PYG{+w}{ }\PYG{p}{\PYGZob{}}
|
||||
\PYG{+w}{ }\PYG{n}{Debug}\PYG{p}{.}\PYG{n}{Log}\PYG{p}{(}\PYG{l+s}{\PYGZdq{}Start method\PYGZdq{}}\PYG{p}{);}
|
||||
\PYG{+w}{ }\PYG{n}{StartCoroutine}\PYG{p}{(}\PYG{n}{TestCoroutine}\PYG{p}{());}
|
||||
\PYG{+w}{ }\PYG{n}{Debug}\PYG{p}{.}\PYG{n}{Log}\PYG{p}{(}\PYG{l+s}{\PYGZdq{}Start method ends\PYGZdq{}}\PYG{p}{);}
|
||||
\PYG{p}{\PYGZcb{}}
|
||||
|
||||
\PYG{c+c1}{// this coroutine has a loop that runs as along as the calling object is active}
|
||||
\PYG{k}{private}\PYG{+w}{ }\PYG{n}{IEnumerator}\PYG{+w}{ }\PYG{n+nf}{TestCoroutine}\PYG{p}{()}\PYG{+w}{ }\PYG{p}{\PYGZob{}}
|
||||
\PYG{+w}{ }\PYG{n}{Debug}\PYG{p}{.}\PYG{n}{Log}\PYG{p}{(}\PYG{l+s}{\PYGZdq{}TestCoroutine\PYGZdq{}}\PYG{p}{);}
|
||||
\PYG{+w}{ }\PYG{k}{while}\PYG{p}{(}\PYG{k}{true}\PYG{p}{)}
|
||||
\PYG{+w}{ }\PYG{p}{\PYGZob{}}
|
||||
\PYG{+w}{ }\PYG{n}{Debug}\PYG{p}{.}\PYG{n}{Log}\PYG{p}{(}\PYG{l+s}{\PYGZdq{}Here\PYGZdq{}}\PYG{p}{);}
|
||||
\PYG{+w}{ }\PYG{k}{yield}\PYG{+w}{ }\PYG{k}{return}\PYG{+w}{ }\PYG{k}{null}\PYG{p}{;}
|
||||
\PYG{+w}{ }\PYG{n}{Debug}\PYG{p}{.}\PYG{n}{Log}\PYG{p}{(}\PYG{l+s}{\PYGZdq{}There\PYGZdq{}}\PYG{p}{);}
|
||||
\PYG{+w}{ }\PYG{p}{\PYGZcb{}}
|
||||
\PYG{p}{\PYGZcb{}}
|
||||
|
||||
\PYG{k}{private}\PYG{+w}{ }\PYG{k}{void}\PYG{+w}{ }\PYG{n+nf}{Update}\PYG{p}{()}\PYG{+w}{ }\PYG{p}{\PYGZob{}}
|
||||
\PYG{+w}{ }\PYG{n}{Debug}\PYG{p}{.}\PYG{n}{Log}\PYG{p}{(}\PYG{l+s}{\PYGZdq{}Update\PYGZdq{}}\PYG{p}{);}
|
||||
\PYG{p}{\PYGZcb{}}
|
||||
|
||||
\PYG{c+c1}{// Output should be:}
|
||||
\PYG{c+cm}{/*}
|
||||
\PYG{c+cm}{Start method}
|
||||
\PYG{c+cm}{TestCoroutine}
|
||||
\PYG{c+cm}{Here}
|
||||
\PYG{c+cm}{Start method ends}
|
||||
\PYG{c+cm}{Update}
|
||||
\PYG{c+cm}{There}
|
||||
\PYG{c+cm}{Here}
|
||||
\PYG{c+cm}{Update}
|
||||
\PYG{c+cm}{There}
|
||||
\PYG{c+cm}{Here}
|
||||
\PYG{c+cm}{*/}
|
||||
\end{Verbatim}
|
@ -0,0 +1,3 @@
|
||||
\begin{Verbatim}[commandchars=\\\{\}]
|
||||
\PYG{k}{public}\PYG{+w}{ }\PYG{k+kt}{float}\PYG{+w}{ }\PYG{n}{mass}
|
||||
\end{Verbatim}
|
@ -0,0 +1,3 @@
|
||||
\begin{Verbatim}[commandchars=\\\{\}]
|
||||
\PYG{k}{void}\PYG{+w}{ }\PYG{n+nf}{OnCollisionExit}\PYG{p}{(}\PYG{n}{Collision}\PYG{+w}{ }\PYG{n}{collision}\PYG{p}{)}
|
||||
\end{Verbatim}
|
@ -0,0 +1,3 @@
|
||||
\begin{Verbatim}[commandchars=\\\{\}]
|
||||
\PYG{k}{public}\PYG{+w}{ }\PYG{n}{Vector3}\PYG{+w}{ }\PYG{n}{centerOfMass}
|
||||
\end{Verbatim}
|
@ -0,0 +1,4 @@
|
||||
\begin{Verbatim}[commandchars=\\\{\},codes={\catcode`\$=3\catcode`\^=7\catcode`\_=8\relax}]
|
||||
\PYG{n}{Rigidbody}\PYG{+w}{ }\PYG{n}{rigid}\PYG{+w}{ }\PYG{o}{=}\PYG{+w}{ }\PYG{n}{GetComponent}\PYG{o}{\PYGZlt{}}\PYG{n}{Rigidbody}\PYG{o}{\PYGZgt{}}\PYG{p}{();}
|
||||
\PYG{n}{rigid}\PYG{p}{.}\PYG{n}{AddForce}\PYG{p}{(}\PYG{n}{transform}\PYG{p}{.}\PYG{n}{forward}\PYG{+w}{ }\PYG{o}{*}\PYG{+w}{ }\PYG{l+m}{200f}\PYG{+w}{ }\PYG{o}{*}\PYG{+w}{ }\PYG{n}{Time}\PYG{p}{.}\PYG{n}{fixedDeltaTime}\PYG{p}{);}
|
||||
\end{Verbatim}
|
@ -0,0 +1,8 @@
|
||||
\begin{Verbatim}[commandchars=\\\{\},codes={\catcode`\$=3\catcode`\^=7\catcode`\_=8\relax}]
|
||||
\PYG{n}{GameObject}\PYG{+w}{ }\PYG{n}{go}\PYG{+w}{ }\PYG{o}{=}\PYG{+w}{ }\PYG{n}{Instantiate}\PYG{p}{(}\PYG{n}{Resources}\PYG{p}{.}\PYG{n}{Load}\PYG{p}{(}\PYG{n}{prefabName}\PYG{p}{));}
|
||||
|
||||
\PYG{c+c1}{// later on, assuming we still have a reference to the object:}
|
||||
\PYG{n}{GameObject}\PYG{p}{.}\PYG{n}{Destroy}\PYG{p}{(}\PYG{n}{go}\PYG{p}{);}
|
||||
\PYG{c+c1}{// or}
|
||||
\PYG{n}{GameObject}\PYG{p}{.}\PYG{n}{DestroyImmediate}\PYG{p}{(}\PYG{n}{go}\PYG{p}{);}
|
||||
\end{Verbatim}
|
@ -0,0 +1,3 @@
|
||||
\begin{Verbatim}[commandchars=\\\{\}]
|
||||
\PYG{k}{void}\PYG{+w}{ }\PYG{n+nf}{OnCollisionStay}\PYG{p}{(}\PYG{n}{Collision}\PYG{+w}{ }\PYG{n}{collision}\PYG{p}{)}
|
||||
\end{Verbatim}
|
@ -0,0 +1,3 @@
|
||||
\begin{Verbatim}[commandchars=\\\{\},codes={\catcode`\$=3\catcode`\^=7\catcode`\_=8\relax}]
|
||||
\PYG{n}{InvokeRepeating}\PYG{p}{(}\PYG{l+s}{\PYGZdq{}LaunchProjectile\PYGZdq{}}\PYG{p}{,}\PYG{+w}{ }\PYG{l+m}{2.0f}\PYG{p}{,}\PYG{+w}{ }\PYG{l+m}{0.3f}\PYG{p}{);}
|
||||
\end{Verbatim}
|
@ -0,0 +1,3 @@
|
||||
\begin{Verbatim}[commandchars=\\\{\}]
|
||||
\PYG{k}{public}\PYG{+w}{ }\PYG{n}{Vector3}\PYG{+w}{ }\PYG{n}{velocity}
|
||||
\end{Verbatim}
|
@ -0,0 +1,76 @@
|
||||
|
||||
\makeatletter
|
||||
\def\PYG@reset{\let\PYG@it=\relax \let\PYG@bf=\relax%
|
||||
\let\PYG@ul=\relax \let\PYG@tc=\relax%
|
||||
\let\PYG@bc=\relax \let\PYG@ff=\relax}
|
||||
\def\PYG@tok#1{\csname PYG@tok@#1\endcsname}
|
||||
\def\PYG@toks#1+{\ifx\relax#1\empty\else%
|
||||
\PYG@tok{#1}\expandafter\PYG@toks\fi}
|
||||
\def\PYG@do#1{\PYG@bc{\PYG@tc{\PYG@ul{%
|
||||
\PYG@it{\PYG@bf{\PYG@ff{#1}}}}}}}
|
||||
\def\PYG#1#2{\PYG@reset\PYG@toks#1+\relax+\PYG@do{#2}}
|
||||
|
||||
\@namedef{PYG@tok@c}{\let\PYG@it=\textit\def\PYG@tc##1{\textcolor[rgb]{0.53,0.53,0.53}{##1}}}
|
||||
\@namedef{PYG@tok@cp}{\let\PYG@bf=\textbf\def\PYG@tc##1{\textcolor[rgb]{0.53,0.53,0.53}{##1}}}
|
||||
\@namedef{PYG@tok@cs}{\let\PYG@bf=\textbf\def\PYG@tc##1{\textcolor[rgb]{0.53,0.53,0.53}{##1}}}
|
||||
\@namedef{PYG@tok@k}{\let\PYG@bf=\textbf}
|
||||
\@namedef{PYG@tok@kd}{\let\PYG@bf=\textbf\let\PYG@it=\textit}
|
||||
\@namedef{PYG@tok@nb}{\let\PYG@bf=\textbf\let\PYG@it=\textit}
|
||||
\@namedef{PYG@tok@bp}{\let\PYG@bf=\textbf\let\PYG@it=\textit}
|
||||
\@namedef{PYG@tok@nn}{\let\PYG@bf=\textbf\let\PYG@it=\textit\def\PYG@tc##1{\textcolor[rgb]{0.40,0.40,0.40}{##1}}}
|
||||
\@namedef{PYG@tok@nc}{\let\PYG@bf=\textbf\let\PYG@it=\textit\def\PYG@tc##1{\textcolor[rgb]{0.40,0.40,0.40}{##1}}}
|
||||
\@namedef{PYG@tok@nf}{\let\PYG@bf=\textbf\let\PYG@it=\textit\def\PYG@tc##1{\textcolor[rgb]{0.40,0.40,0.40}{##1}}}
|
||||
\@namedef{PYG@tok@nv}{\let\PYG@bf=\textbf\let\PYG@it=\textit\def\PYG@tc##1{\textcolor[rgb]{0.40,0.40,0.40}{##1}}}
|
||||
\@namedef{PYG@tok@no}{\let\PYG@bf=\textbf\let\PYG@it=\textit\def\PYG@tc##1{\textcolor[rgb]{0.40,0.40,0.40}{##1}}}
|
||||
\@namedef{PYG@tok@ow}{\let\PYG@bf=\textbf}
|
||||
\@namedef{PYG@tok@s}{\let\PYG@it=\textit\def\PYG@tc##1{\textcolor[rgb]{0.40,0.40,0.40}{##1}}}
|
||||
\@namedef{PYG@tok@err}{\def\PYG@bc##1{{\setlength{\fboxsep}{\string -\fboxrule}\fcolorbox[rgb]{1.00,0.00,0.00}{1,1,1}{\strut ##1}}}}
|
||||
\@namedef{PYG@tok@kc}{\let\PYG@bf=\textbf}
|
||||
\@namedef{PYG@tok@kn}{\let\PYG@bf=\textbf}
|
||||
\@namedef{PYG@tok@kp}{\let\PYG@bf=\textbf}
|
||||
\@namedef{PYG@tok@kr}{\let\PYG@bf=\textbf}
|
||||
\@namedef{PYG@tok@kt}{\let\PYG@bf=\textbf}
|
||||
\@namedef{PYG@tok@fm}{\let\PYG@bf=\textbf\let\PYG@it=\textit\def\PYG@tc##1{\textcolor[rgb]{0.40,0.40,0.40}{##1}}}
|
||||
\@namedef{PYG@tok@vc}{\let\PYG@bf=\textbf\let\PYG@it=\textit\def\PYG@tc##1{\textcolor[rgb]{0.40,0.40,0.40}{##1}}}
|
||||
\@namedef{PYG@tok@vg}{\let\PYG@bf=\textbf\let\PYG@it=\textit\def\PYG@tc##1{\textcolor[rgb]{0.40,0.40,0.40}{##1}}}
|
||||
\@namedef{PYG@tok@vi}{\let\PYG@bf=\textbf\let\PYG@it=\textit\def\PYG@tc##1{\textcolor[rgb]{0.40,0.40,0.40}{##1}}}
|
||||
\@namedef{PYG@tok@vm}{\let\PYG@bf=\textbf\let\PYG@it=\textit\def\PYG@tc##1{\textcolor[rgb]{0.40,0.40,0.40}{##1}}}
|
||||
\@namedef{PYG@tok@sa}{\let\PYG@it=\textit\def\PYG@tc##1{\textcolor[rgb]{0.40,0.40,0.40}{##1}}}
|
||||
\@namedef{PYG@tok@sb}{\let\PYG@it=\textit\def\PYG@tc##1{\textcolor[rgb]{0.40,0.40,0.40}{##1}}}
|
||||
\@namedef{PYG@tok@sc}{\let\PYG@it=\textit\def\PYG@tc##1{\textcolor[rgb]{0.40,0.40,0.40}{##1}}}
|
||||
\@namedef{PYG@tok@dl}{\let\PYG@it=\textit\def\PYG@tc##1{\textcolor[rgb]{0.40,0.40,0.40}{##1}}}
|
||||
\@namedef{PYG@tok@sd}{\let\PYG@it=\textit\def\PYG@tc##1{\textcolor[rgb]{0.40,0.40,0.40}{##1}}}
|
||||
\@namedef{PYG@tok@s2}{\let\PYG@it=\textit\def\PYG@tc##1{\textcolor[rgb]{0.40,0.40,0.40}{##1}}}
|
||||
\@namedef{PYG@tok@se}{\let\PYG@it=\textit\def\PYG@tc##1{\textcolor[rgb]{0.40,0.40,0.40}{##1}}}
|
||||
\@namedef{PYG@tok@sh}{\let\PYG@it=\textit\def\PYG@tc##1{\textcolor[rgb]{0.40,0.40,0.40}{##1}}}
|
||||
\@namedef{PYG@tok@si}{\let\PYG@it=\textit\def\PYG@tc##1{\textcolor[rgb]{0.40,0.40,0.40}{##1}}}
|
||||
\@namedef{PYG@tok@sx}{\let\PYG@it=\textit\def\PYG@tc##1{\textcolor[rgb]{0.40,0.40,0.40}{##1}}}
|
||||
\@namedef{PYG@tok@sr}{\let\PYG@it=\textit\def\PYG@tc##1{\textcolor[rgb]{0.40,0.40,0.40}{##1}}}
|
||||
\@namedef{PYG@tok@s1}{\let\PYG@it=\textit\def\PYG@tc##1{\textcolor[rgb]{0.40,0.40,0.40}{##1}}}
|
||||
\@namedef{PYG@tok@ss}{\let\PYG@it=\textit\def\PYG@tc##1{\textcolor[rgb]{0.40,0.40,0.40}{##1}}}
|
||||
\@namedef{PYG@tok@ch}{\let\PYG@it=\textit\def\PYG@tc##1{\textcolor[rgb]{0.53,0.53,0.53}{##1}}}
|
||||
\@namedef{PYG@tok@cm}{\let\PYG@it=\textit\def\PYG@tc##1{\textcolor[rgb]{0.53,0.53,0.53}{##1}}}
|
||||
\@namedef{PYG@tok@cpf}{\let\PYG@it=\textit\def\PYG@tc##1{\textcolor[rgb]{0.53,0.53,0.53}{##1}}}
|
||||
\@namedef{PYG@tok@c1}{\let\PYG@it=\textit\def\PYG@tc##1{\textcolor[rgb]{0.53,0.53,0.53}{##1}}}
|
||||
|
||||
\def\PYGZbs{\char`\\}
|
||||
\def\PYGZus{\char`\_}
|
||||
\def\PYGZob{\char`\{}
|
||||
\def\PYGZcb{\char`\}}
|
||||
\def\PYGZca{\char`\^}
|
||||
\def\PYGZam{\char`\&}
|
||||
\def\PYGZlt{\char`\<}
|
||||
\def\PYGZgt{\char`\>}
|
||||
\def\PYGZsh{\char`\#}
|
||||
\def\PYGZpc{\char`\%}
|
||||
\def\PYGZdl{\char`\$}
|
||||
\def\PYGZhy{\char`\-}
|
||||
\def\PYGZsq{\char`\'}
|
||||
\def\PYGZdq{\char`\"}
|
||||
\def\PYGZti{\char`\~}
|
||||
% for compatibility with earlier versions
|
||||
\def\PYGZat{@}
|
||||
\def\PYGZlb{[}
|
||||
\def\PYGZrb{]}
|
||||
\makeatother
|
||||
|
@ -0,0 +1,36 @@
|
||||
- same format as every other year
|
||||
- final page is the same as the past few years
|
||||
- useful methods and stuff
|
||||
- don't expect precise arguments and names of methods
|
||||
- answer 3 of 5
|
||||
|
||||
- question 1:
|
||||
- in four parts
|
||||
- asking about monobehaviours
|
||||
- coroutines
|
||||
- partial game, do things write code
|
||||
- one of the partial games was done as a demo over the course
|
||||
|
||||
- question 2:
|
||||
- write short technical notes approx 150 words on each of the four parts
|
||||
- in past papers
|
||||
- lots of overlaps with past papers
|
||||
- can give some code, if appropriate
|
||||
|
||||
- question 3:
|
||||
- 3 parts
|
||||
- first two about colliders and stuff like that (related things)
|
||||
- third part about low level moving objects around
|
||||
- both a lot in past papers
|
||||
|
||||
- question 4:
|
||||
- write a complete monobehaviour over a number of steps to do a simple behaviour that's useful in unity
|
||||
- has public variables for setting up a prefab
|
||||
- involves using vectors and time
|
||||
|
||||
- question 5:
|
||||
- raycasting
|
||||
- write code for fictional game involving raycasting
|
||||
|
||||
|
||||
- very similar style to the past papers
|
After Width: | Height: | Size: 583 KiB |
After Width: | Height: | Size: 456 KiB |
After Width: | Height: | Size: 434 KiB |
After Width: | Height: | Size: 468 KiB |
After Width: | Height: | Size: 215 KiB |
After Width: | Height: | Size: 643 KiB |
After Width: | Height: | Size: 154 KiB |
BIN
third/semester1/CT3536: Games Programming/notes/images/uniog.jpg
Normal file
After Width: | Height: | Size: 107 KiB |
After Width: | Height: | Size: 144 KiB |
After Width: | Height: | Size: 542 KiB |