# Unity snabbreferens

Detta är en hemsida med förenklade förklaringar och exempel relaterade till att arbeta med spelmotorn Unity. Tanken är att den ska kunna användas som referensverk för gymnasieelever som läser kurserna Programmering 1 och Programmering 2.

**Se även:**

* [Csharp ](https://csharp.progdocs.se/)– en sida med förenklade förklaringar och exempel för C#
* [Unity AR/VR-referens](https://sites.google.com/view/unityarvr) – en något föråldrad sida med förklaringar och exempel kring hur man kan jobba med VR och AR i Unity.

## Hittat ett fel?

Hela den här sidan finns [speglad på GitHub](https://github.com/krank/unity-ref) – där kan du skapa en buggrapport (issue) och beskriva problemet.

Eller så kan du forka repositoriet, göra ändringen och sedan göra en pull request!

## Videotips

* [11 Things You (Probably) Didn't Know You Could Do In Unity](https://www.youtube.com/watch?v=mCKeSNdO_S0)


# Installation & setup

* **Ladda ner och installera** [**Unity Hub**](https://unity3d.com/get-unity/download)**.**
  * **Starta Unity Hub** och följ instruktionerna – skapa ett Unity-konto om du inte redan har ett, skaffa en Unity-licens (välj gratislicensen).
  * När Unity Hub startar så får du frågan **om du vill installera Unity**. Du kan **tacka nej** till det, för den installationen inkluderar onödiga moduler som bara tar upp hårddiskutrymme.
  * Via Unity Hub, **installera manuellt en version av Unity (minst 2022)**. Du kan **klicka ur alla valbara extragrejer**, framför allt Visual Studio.
    * Om Visual Studio redan är installerat på datorn kan du inte kryssa ur det. Det är OK, du kan manuellt avinstallera Visual Studio senare.
  * Unity Hub och Unity tar tillsammans upp c:a **5.5 gb**
  * **MacOS:** Scrolla ner till "Download the Unity Hub" och välj "Download for Mac"
  * **MacOS:** Om du har [Brew ](https://brew.sh/)kan du installera via:`brew install --cask unity-hub`
  * **Windows:** Kan installeras via winget: `winget install Unity.UnityHub`
* **Ladda ner och installera** [**Visual Studio Code**](https://code.visualstudio.com/)**.**
  * I Code, installera följande extensions:
    * [C#](https://www.google.com/url?q=https%3A%2F%2Fmarketplace.visualstudio.com%2Fitems%3FitemName%3Dms-vscode.csharp\&sa=D\&sntz=1\&usg=AFQjCNGOzgSFj14Pbd9ut66JAvh0loJsEw) – Ger Visual Studio Code stöd för C#
    * [C# Dev Kit](https://marketplace.visualstudio.com/items?itemName=ms-dotnettools.csdevkit) – Ger utökat stöd för C#
    * [Unity](https://marketplace.visualstudio.com/items?itemName=VisualStudioToolsForUnity.vstuc) – Officiell extension från Microsoft som får Unity och Code att funka ihop
    * [Unity Code Snippets](https://marketplace.visualstudio.com/items?itemName=kleber-swf.unity-code-snippets) – lägger till en del smarta kodkompletteringar för Unity.
    * [gitignore](https://www.google.com/url?q=https%3A%2F%2Fmarketplace.visualstudio.com%2Fitems%3FitemName%3Dcodezombiech.gitignore\&sa=D\&sntz=1\&usg=AFQjCNHu8aUEHuuoWIdAZQcCdvDqnSWhSQ) – Underlättar arbetet med git och Visual Studio Code. Om du söker efter den, se till att ta den av CodeZombie!
  * **Windows:** Kan installeras via winget: `winget install Microsoft.VisualStudioCode`
  * **MacOS:** Om du har [Brew ](https://brew.sh/)kan du installera via:`brew install --cask vscode`
  * Visual Studio Code inkl. extensions tar upp c:a **1gb**
* **Ladda ner och installera** [**Dotnet 8 SDK**](https://dotnet.microsoft.com/en-us/download) **eller nyare**
  * Behövs av för att C# Dev Kit ska kunna bidra med automatkomplettering av kod.
  * **Windows:** Kan installeras via winget: `winget install Microsoft.DotNet.SDK.8`
  * **MacOS:** Om du har [Brew ](https://brew.sh/)kan du installera via:`brew install --cask dotnet-sdk`
  * Tar upp c:a **1.2 gb**
* **Ladda ner och installera** [**Git**](https://git-scm.com/downloads)
  * Används för versionshantering och att dela med sig av kod/projekt (t.ex. för inlämningar)
  * Windows: Kan installeras via winget: `winget install git.git`
  * **MacOS:** Om du har [Brew ](https://brew.sh/)kan du installera via:`brew install --cask git`
  * **MacOS:** Om du inte har Brew och bara testar att köra `git` i terminalen så kommer Apples grundläggande utvecklingsverktyg att installeras – inklusive git.

Att installera allt ovanstående på en helt nyinstallerad dator kräver totalt c:a **8 gb** ledigt utrymme.

## Nytt projekt

* Välj själv den template (2D, 3D etc) som bäst matchar spelet du tänker bygga.
* Gå till **Window → Package Manager** och se till så att paketet **Visual Studio Editor** är uppdaterat (minst version 2.0.20).
  * Du kan behöva **avinstallera** metapaketet **Engineering** och sedan manuellt installera Visual Studio Editor.
* När projektet skapats, gå till **Edit →** **Preferences** och **External Tools**. Välj **Visual Studio Code** som **External Script Editor.**

## Unity och Git

Ett enkelt sätt att använda Git med Unity är Visual Studio Codes inbyggda Git-gränssnitt.

* Högerklicka i Assets och välj **"Open C# project"**.
* Följ instruktionerna för att skapa ett Git-repository [här](https://krank23.gitbook.io/csharp-ref/lathund-skapa-projekt), men lägg till en **gitignore** för **Unity** istället för Visual Studio.


# Kompilera och distribuera

Unityprojekt kan normalt bara öppnas och köras i Unity. Om de ska kunna spelas utan unity behöver de kompileras till körbara filer för önskad plattform. I normala fall, när Unity körs på en Windowsdator, kommer de körbara filerna i första hand att vara vanliga exe-filer som kan köras i 64-bitars windows.

## Kompilera

Gå till **File → Build Settings**.

Lägg till önskade scener till listan – antingen genom knappen **"Add Open Scenes"** eller genom att dra in dem från Assets.

Klicka på **Build**.

**Bläddra till eller skapa en mapp** som resultatet ska läggas i. Välj en mapp som inte används till något annat.

**Dubbelklicka på exe-filen** som skapas i mappen för att köra den kompilerade versionen av spelet.

**Alla filer i mappen behövs för att köra spelet**, så för att distribuera det så behöver du packa ihop och skicka hela mappens innehåll. Det enklaste sättet att göra det är antagligen att **komprimera mappen till en zip-fil**.

## Andra plattformar

Unity har normalt bara stöd för att exportera spelprojekt till Windows-format, det vill säga vanliga klassiska EXE-filer som kan köras i 64-bitars Windowssystem.

Det går att installera moduler för att exportera projekt till andra operativsystem eler ramverk – till exempel Android eller UWP (Universal Windows Platform).

* Öppna **Unity Hub**.
* Gå till **Installs**.
* Klicka på **kugghjulet** bredvid den Unityversion som ska ges nya exportmoduler.
* Klicka på **Add modules**.

Kryssa i de moduler du vill ha och sedan Install. Se till att kryssa ur Visual Studio 2019 om du inte absolut vill ha det programmet, och Documentation om du inte kommer att vilja komma åt Unitys egna dokumentation inuti programmet.

## Android

Installera modulerna **"Android Build Support"**, **"Android SDK & NDK Tools"** och **"OpenJDK"**.

I Unityprojekt som ska exporteras till Android, gå till **File → Build Settings**, markera **Android** och klicka **Switch platform**.

Koppla in en Android-enhet som har USB Debugging aktiverat, och klicka **Refresh** för att få enheten att dyka upp i listan.

När man build:ar till Android får man en **APK-fil**, som sedan förs över till Androidenheten och installeras. APK är ett universellt format för Android-appar och kan användas för att installera appar på alla Androidenheter som tillåter installation från "okända källor".

## WebGL

Installera modulen **"WebGL Build Support"** (kräver c:a 1.6gb).

I Unityprojekt som ska exporteras till Android, gå till **File → Build Settings**, markera **WebGL** och klicka **Switch platform**.

Klicka på Build och välj eller skapa en mapp som vanligt. Det du får i den mappen är en index.html-fil som laddar in och visar spelet.

{% hint style="info" %}
**OBSERVERA:** De flesta webbläsare blockerar lokal inladdning av Unityprojekt, så det går inte bara att dubbelklicka på index.html-filen som genereras och öppna i en webbläsare. För att testa lokalt: Använd "Build and Run" inuti Unity.
{% endhint %}

Innehållet i mappen kan sedan publiceras på valfri webbserver, eller t.ex. laddas upp och publiceras på Github Pages.

## UWP

Installera modulen **"Universal Windows Platform Build Support"** (c:a 2gb). Du kommer också att behöva ha Microsoft Visual Studio installerat, så installera det antingen från dess hemsida eller genom att kryssa i modulen **"Microsoft Visual Studio Community 2019"** (c:a 1.3gb). Om du har någon senare version av Visual Studio installerad så fungerar den också; då behöver du inte installera 2019.

Får du sedan felmeddelanden, dubbelkolla i Visual Studio Installer så att "Desktop Development med C++" är installerat.

I Unityprojekt som ska exporteras till Android, gå till **File → Build Settings**, markera **Universal Windows Platform** och klicka **Switch platform**.

När ett UWP-projekt build:as så skapas ett Visual Studio-projekt som i sin tur måste kompileras. För att testköra projektet, öppna SLN-filen för det genererade projektet i Visual Studio och klicka på **Debug → Start without debugging**.


# Unity och git

Unityprojekt fungerar egentligen precis som vanliga C#projekt. Öppnas de i Visual Studio Code kan man alltså använda [samma steg](https://csharp.progdocs.se/mjukvara/git-and-github).

**En gång:**

* Ha Visual Studio Code installerat.
* Ha [Git installerat](https://csharp.progdocs.se/mjukvara/git-and-github).
* Ställ in [användarnamn och e-mail](https://csharp.progdocs.se/mjukvara/git-and-github#foersta-gangen-efter-ny-git-installation).
* Lägg in tillägget [gitignore ](https://marketplace.visualstudio.com/items?itemName=codezombiech.gitignore)till Visual Studio.

**En gång per projekt:**

* Gå till projektet i Visual Studio Code, öppna kommando-palletten (F1 eller Fn+F1) och sök "add gitignore". Välj "Unity".
* Gå till Source Control och välj Initialize Repository.
* Publicera projektet på Github.

**En gång per arbetstillfälle:**

* Gå till projektet i Visual Studio Code.
* Gå till Source Control.
* Skriv något i rutan för Message.
* Tryck på plusset till höger om "Changes" för att lägga till alla nya ändringar till din commit.
* Tryck på Commit, och sedan Sync.

**För projekt med stora filer (>100mb)**

* Gå till projektet i Visual Studio Code.
* Gå till terminalen
* Skriv in kommandot `git lfs install` för att aktivera Git LFS (Large File System)
* Skriv därefter in `git lfs track '*.fbx'` för att göra så att LFS sköter alla FBX-filer. Gör motsvarande för andra stora filtyper.


# Begrepp

### Projekt

Projektet är själva produkten - alla banor, alla 3d-modeller, alla ljud, alla inställningar, allting.

### Assets

Alla resurser som inte är knutna till en specifik scen. Generellt behöver det mesta som importeras läggas in som en asset först, t.ex. ljudfiler, 3d-modeller, texturer, material. Scener ligger också som assets.

### Scener

En scen kan vara till exempel en bana i spelet, eller en menyskärm. Något som är separat från resten av innehållet. Scener innehåller en eller flera spelobjekt.

### Spelobjekt/GameObject

Alla föremål, textrutor, kameror etc som finns i en scen är game objects, spelobjekt. Varje spelobjekt har minst en komponent, Transformkomponenten, men de flesta innehåller även andra komponenter.

### Komponenter

En komponent ger ett spelobjekt vissa egenskaper - det kan röra sig om utseende, beteende, hur objektet ska låta, hur det ska bete sig rent fysikaliskt (tyngd etc), hur dess hitbox ska se ut etc. Spelobjekt är i princip klumpar av komponenter.

### Collider

En collider-komponent är i princip en hitbox: den delen av objektet som "räknas" när det gäller kollisioner. Ett spelobjekt kan ha flera colliders.

### RigidBody

En rigidbody gör att spelobjektet omfattas av Unitys fysikmotor. Det betyder att objektet kan påverkas av gravitation och olika krafter. För att en kollision mellan två spelobjekt ska kunna hanteras av kod så måste minst ett av objekten i kollisionen ha en RigidBody.

### Taggar

Ett sätt att sätta etikett på spelobjekt. Det gör att flera spelobjekt kan klumpas ihop och underlättar också ifall man t.ex. vill undersöka vilket spelobjekt det är man kolliderat med.

### Prefab

Ett spelobjekt, inklusive transform-komponent och möjligen också andra komponenter, som ligger i Assets. Prefabs är alltså inte en del av någon scen, utan fungerar ofta som "mallar" för nya objekt som skapas i scenen.


# Ett Unityprojekts uppbyggnad

Ett unityprojekt innehåller ett antal **assets**.

Assets kan till exempel vara **scener**, texturer, 3d-modeller, sprites och C#-scripts.

Varje Scene är en separat del av projektet, som innehåller ett eget 3d-space.

I varje scene finns ett antal **GameObjects**, som kan vara nästan vad som helst – kameror, lampor, spelkaraktärer, fiender, powerups och så vidare.

Varje GameObject består av ett antal **Components**.

Varje Component är ett script som ger viss funktionalitet till det GameObject det sitter ihop med. Alla GameObjects har t.ex. en Transform-Component som ger objektet dess position, rotation och skalning.

I en Component kan det sedan finnas **variabler**. Transform-komponenten her till exempel [Vector3](/grundfunktioner/datatyper-och-synlighet#vector3)-variabler för position, rotation och skalning av objektet.


# Prefabs och instanser

En **prefab** är ett spelobjekt (med komponenter) som inte finns i en scen utan istället finns i Assets. Prefabs fungerar som mallar för nya objekt.

En prefab skapas genom att ett spelobjekt i scenen dras ner till Assets. Då skapas en prefab av objektet, och i scenen finns nu istället en **instans** av den.

## Instanser

En instans är ett spelobjekt som bygger på och är kopplat till en prefab. När instansen skapas är den först identisk med prefaben. Därefter kan ändringar göras till instansen, som då blir alltmer olik prefaben.

Med andra ord blir prefaben som en mall eller som en [klass](https://krank23.gitbook.io/csharp-ref/klasser-och-objektorientering/klasser-och-instanser).

![](/files/DEWecEnDd9JXN6umQU8c)

Instanser får en extra rad med knappar högst upp i Inspectorn.

* **Open** gör att prefaben öppnas för redigering.
* **Select** markerar prefaben i Assets.
* Ändringar som görs till en instans kallas **Overrides**. Overrides kan återställas (**revert**) så att de blir lika som prefaben igen, eller så kan prefaben ändras så att samma ändringar görs där (**apply**).


# Komponenter

Alla spelobjekt i Unity består av ett antal **komponenter**. Varje komponent är en instans av en komponentklass, och alla komponentklasser har olika inbyggda variabler och metoder som ger komponenten och spelobjektet funktionalitet.

Några exempel på vanliga komponenter:

* **Transform:** Alla spelobjekt har en Transform-komponent som talar om objektets position, rotation och skalning.
* **Colliders:** Finns i olika varianter (box, sphere etc) och är olika för 2d och 3d-fysik (t.ex. BoxCollider2D). Funkar som hit boxes; ger en enkel volym eller 2d-yta som används för att känna av kollisioner. Colliders kan göras till triggers och påverkar då inte varandra i fysikmotorn; annars används colliders för att göra så saker kan hindra varandras förflyttning som fysiska objekt.
* **RigidBody, RigidBody2D:** Används för att tala om för fysikmotorn att objektet ska omfattas av fysiksimuleringen – man kan t.ex. ange objektets massa och via kod addera kraft i valfri riktning med hjälp av objektets rigidbody-komponent.
* **MeshRenderer, SpriteRenderer:** Används för att ge objektet ett utseende – MeshRenderer använder en 3d-modell som renderas ut på skärmen medan SpriteRenderer använder en 2d-bild.

## Scriptkomponenter

I princip all kod som skrivs i Unityprojekt skrivs i script-komponenter. För att scriptkomponentens kod ska köras behöver normalt sett komponenten sitta på ett spelobjekt som är aktivt i scenen.

För att skapa en scriptkomponent:

* Högerklicka i Assets och välj Create → C# Script eller
* Klicka på Add Component längst ner i Inspectorn på ett spelobjekt.

Normalt sett ärver alla scriptkomponenter från [MonoBehavior](/grundlaggande-koncept/monobehavior).

## GetComponent<>()

Hämtar första bästa komponent av angiven typ. Returnerar `null` om det inte finns någon.

```csharp
void Start()
{
  Transform tForm = this.GetComponent<Transform>();
  Rigidbody2D rigidBody = this.GetComponent<Rigidbody2D>();
}
```

## TryGetComponent<>()

Fungerar dels som GetComponent, men är mer säker – fungerar lite som [TryParse](https://unity.progdocs.se/grundlaggande-koncept/spaces/-MHmNgpRz-b16wpwGwZI-887967055/pages/-MHzQ4eGFcc-4IH2WYJF#int.tryparse). Med andra ord: Går det inte att hitta rätt komponent, så returneras false.

```csharp
void Start()
{
  if (this.GetComponent<Rigidbody2D>(out RigidBody2D rigidBody)
  {
    // Gör något med rigidBody
  }
}
```

## Komponentmenyn

Klicka på ![](/files/h6nxNOaaW2mSKm7vl8lc) till höger om komponentens namn för att ta fram komponentmenyn.

* **Reset** återställer komponenten till dess utgångläge. För en Transform-komponent betyder det till exempel att position och rotationsvärdena blir 0 och skalningsvördena blir 1.
* **Copy Component** kopierar komponenten till minnet.
* **Paste Component As New** lägger in en ny kopia av komponenten i minnet till spelobjektet.
* **Paste Component As Values** fungerar bara om komponenten i minnet är av samma typ som den vars meny klickades på. Då ändras den klickade komponentens värden till att bli samma som komponenten i minnets.

## Presets

Presets är assets som innehåller färdiga uppsättningar värden för en komponent. ![](/files/XYQ7kfif3thJxZBAPcso) öppnar listan med presets, och där finns också en "Save current to…"-knapp för att spara komponentens nuvarande variabelvärden till en preset.

Detta är användbar när man vill kunna återanvända en komponents variabelvärden till andra, framtida objekt som har samma komponent.


# Scener

Varje scen är som ett dokument, som i sin tur innehåller alla objekt som hör ihop. En scen kan vara en skärm ("Game Over", "Settings") eller en level.

Från början finns bara en scen, "SampleScene", som ligger i mappen Scenes. Den kan man byta namn på om man vill.

För att skapa nya scener kan man högerklicka i Assets, välja Create och Scene.

## Scenordning

För att en scen ska komma med när spelet körs så behöver den läggas till i File → Build Settings. Scener som läggs till där kan man växla mellan under spelets gång, antingen via deras namn eller deras nummer. Numret står längst ut till höger i listan; scenen högst upp har nummer 0, nästa scen är nummer 1, och så vidare.

Man lägger till scener i listan genom att dra dem dit från Assets-fönstret eller genom att öppna en scen och klicka på "Add open scenes".

![](/files/-MMuCdaHRi7hjjsQKqsh)

Man kan byta ordning på scenerna genom att klicka och dra.

## SceneManagement

För att man ska kunna byta scen måste man importera SceneManagement-modulen i scriptet. Leta rätt på raden "using UnityEngine;" högst upp i scriptet och lägg till "using UnityEngine.SceneManagement;". Så här:

```csharp
using UnityEngine;
using UnityEngine.SceneManagement;
```

### LoadScene()

Laddar in en scen, definierad av sitt nummer i Build settings eller av sitt namn

```csharp
SceneManager.LoadScene(1);
SceneManager.LoadScene("Level1");
```

### GetActiveScene()

Returnerar den nuvarande scenen, som en instans av klassen Scene. Därifrån kan man läsa av scenens namn och build index, till exempel.

```csharp
Scene currentScene = SceneManager.GetActiveScene();

SceneManager.LoadScene(currentScene.name); // Startar om nuvarande scen
```

## Scene

Klassen Scene kan såklart också användas till variabler som t.ex. kan exponeras i Inspector, och då kan man göra så att de refererar till scener i Assets.

```csharp
[SerializeField]
Scene nextScene;

void OnCollisionEnter2D(Collision2D col)
{
  if (col.gameObject.tag == "finish")
  {
    SceneManager.LoadScene(nextScene.name);
  }
}
```


# MonoBehavior

MonoBehavior är den basklass som alla komponenter bygger på. Den innehåller ett antal variabler som ger tillgång till Unitys olika funktioner, och framför allt till spelobjektet som komponenten är fäst vid. Några exempel:

* gameObject – direkt tillgång till spelobjektet
* transform – direkt tillgång till Transform-komponenten
* tag – spelobjektets tagg
* name – spelobjektets namn
* enabled – huruvida komponenten är aktiv eller ej

## Händelse-metoder

Det finns ett antal metoder som man kan lägga till i klasser som ärver från MonoBehavior, och som – om scriptet lagts till som komponent på ett spelobjekt – körs vid specifika tillfällen. Nedan är några exempel, [men en komplett lista finns här](https://docs.unity3d.com/ScriptReference/MonoBehaviour.html).

### Start()

Körs när objektet skapas.

```csharp
void Start()
{
  Debug.Log("I am alive!");
}
```

### Update()

Körs en gång varje bildruta. Här skrivs ofta en hel del av logiken för spelobjektet.

```csharp
void Update()
{
  Debug.Log("Ny bildruta, yay!");
}
```

### FixedUpdate()

Körs en gång varje gång fysikdelen av Unity kör en av sina loopar. Normalt sker det 30 gånger per sekund. Här skrivs också en del fysik, framför allt kanske sådan som berör fysikmotorn eller som inte behöver köras riktigt lika ofta som Update.

```csharp
void Update()
{
  Debug.Log("Ny bildruta, yay!");
}
```

### OnBecameVisible()

Anropas när en renderer på spelobjektet blir synlig – när någon del av dess bounds hamnar innanför skärmen.

```csharp
private void OnBecameVisible()
{
  print("I'm visible!");
}
```

### OnBecameInvisible()

Anropas när en renderer på spelobjektet blir osynlig – när ingen del av dess bounds hamnar innanför skärmen.

```csharp
private void OnBecameInvisible()
{
  Destroy(this.GameObject)
}
```

## Livscykeln

Metoder som Update och även t.ex. kollisionsmetoder som OnEnterCollision körs i en viss ordning. Kolla gärna på schemat [här](https://docs.unity3d.com/Manual/ExecutionOrder.html). Där kan man till exempel se att innan Start körs en som heter Awake och en som heter OnEnable, och att det efter Update sker en massa saker och sedan LateUpdate.

Man behöver inte kunna det schemat utantill, mend et kan vara bra att veta att det finns, och att det finns en viss ordning saker och ting körs i.


# Lager och taggar

## Lager

## Taggar


# Knappar och axlar

Det finns ett antal fördefinierade axlar (Edit->Project Settings->Input).

En axel kan ha ett positivt och negativt värde, från -1 till +1 där 0 är "neutralt".

Varje axel kan sedan ha knappar som ändrar dess värde. Så för axeln "Horizontal" används vänsterpil och a för att ge den värdet -1, och högerpil eller d används för att ge den värdet +1.

I scripts kan man sedan [läsa av axlarnas nuvarande värde](/grundfunktioner/input#input-getaxisraw).

Det här gör att man som spelskapare inte själv behöver anpassa sitt spel till både handkontroll och tangentbord, utan det sköts på ett centralt ställe av Unity.

Man kan skapa egna axlar och man kan ändra knapparna för de som finns.

Några axlar som finns:

* `Horizontal` (vänster/högerpil eller a/d)
* `Vertical` (upp/nerpil eller w/s)
* `Jump` (mellanslag)
* `Fire1` (vänster Ctrl)


# Debug och gizmos

Både Debug och Gizmos används framför allt av spelutvecklare själva för att få syn på saker under spel. Kanske vill man rita ut något extra tydligt som inte syns för spelarna, kanske vill man bara ta reda på vilket värde en variabel har under körningen och hur det värdet ändras.

## Debug

### Debug.Log()

Används för att skriva ut saker till konsollen; motsvarande Console.WriteLine i vanlig C#-konsollprogrammering.

```csharp
Debug.Log($"Current X: {transform.position.x}");
```

![](/files/GS0tByhQY042FtMcjIZS)

Används ofta för att testa ifall kod överhuvudtaget körs eller för att se vilket värde olika variabler har.

### Debug.DrawLine()

Ritar ut en linje i scenvyn. Tar emot två vektorer som startposition och slutposition för linjen, och en färg. Om man vill kan man också ange ett antal sekunder som man vill att linjen ska dröja sig kvar.

```csharp
Debug.DrawLine(Vector2.right, Vector2.down, Color.green);
```

![](/files/RCy6hjIZrRWXSYlh53c0)

## Gizmos

Gizmos är ett annat, mer flexibelt sätt att rita saker i scenvyn.

### OnDrawGizmos()

Gizmos ritas i en egen metod – OnDrawGizmos. Precis som andra metoder med namn på On… så anropas OnDrawGizmos alltid vid ett förbestämt tillfälle; i det här fallet när Unity-UIt uppdateras. Det gör också att man bör vara försiktig – skriver man kod i OnDrawGizmos som fastnar i en loop så finns risk att hela Unity blockeras.

```csharp
  void OnDrawGizmos()
  {
    Gizmos.color = Color.green;
    Gizmos.DrawLine(Vector3.right, Vector3.down);
  }
```

När man ritar gizmos bestäms färgen inte genom parametrar in i metoderna utan genom att man bestämmer vilken förg som ska användas "från och med nu".

### DrawLine()

Fungerar som Debug.DrawLine; man anger två vektorer.

```csharp
void OnDrawGizmos()
{
  Gizmos.color = Color.green;
  Gizmos.DrawLine(
    new Vector3(1,2), 
    new Vector3(2,1));
  Gizmos.DrawLine(
    new Vector3(2,1),
    new Vector3(2,2)
  );
}
```

![](/files/tGNk6YH6iFTqNTn2pkaQ)

### DrawLineList()

Ritar ut linjer mellan en serie vektorer. Tar emot en lista eller en array av vektorer.

<pre class="language-csharp"><code class="lang-csharp"><strong>Gizmos.color = Color.green;
</strong>Vector3[] points = new Vector3[4]
  {
    new Vector3(-1, 0, 0),
    new Vector3(1, 0, 0),
    new Vector3(-1, 1, 0),
    new Vector3(1, 1, 0)
  };

Gizmos.DrawLineList(points);
</code></pre>

![](/files/byOi0qdRSN8MDP3e1Hfm)

### DrawWireCube()

Ritar ut en kub. Tar emot två vektorer, som bestämmer kubens position och storlek i x, y oxch z-led.

```csharp
void OnDrawGizmos()
{
  Gizmos.DrawWireCube(Vector3.zero, Vector3.one);
}
```

![](/files/hDrsfmoYNfbxaJe1jjjn)

### DrawWireSphere()

Ritar ut ett klot (egentligen tre cirklar längs olika axlar). Tar emot en vektor (mittpunkt) och en float som anger radien.

```csharp
void OnDrawGizmos()
{
  Gizmos.DrawWireSphere(Vector3.zero, 1);
}
```

![](/files/bM7YiyeCdlkieEnXUuvI)


# Datatyper och synlighet

## Synlighet

Synlighet i Unity fungerar som vanligt - privata variabler och metoder kan bara kommas åt av respektive script, publika variabler och metoder kan kommas åt även utifrån.

Om ett script som lagts till ett spelobjekt har publika variabler, så kommer dessa variabler att synas i inspectorn i Unity. Det betyder alltså att deras värden kan redigeras direkt i Unity. OBS: Det betyder också att värden som anges via inspectorn får högre prioritet än värden som anges där variablerna deklareras i koden.

Med andra ord; om man skriver:

```csharp
public int experience = 4;
```

Och sedan ändrar värdet till 9 i inspectorn så kommer det inte att spela någon roll vilket värde man senare ändrar fyran till i koden.

### SerializeField

SerializeField används för att göra så att en privat variabel visas i inspectorn. Med andra ord ger man Unity tillgång till variabeln, men andra scripts kan inte komma åt den.

```csharp
[SerializeField]
int experience = 4;
```

Huruvida man använder SerializeField eller public är lite av en smaksak, men den som vill vara extra noggrann med sin inkapsling använder så få publika variabler som möjligt och då kan SerializeField vara användbart som alternativ.

## Datatyper

### float

Decimaltal. Ingår egentligen i grund-C#, men står med här eftersom det är den decimaltals-datatyp som används av Unity.

```csharp
float speed = 4.5f;
```

### Vector3

Tredimensionella vektorer. En vektor innehåller värden för x, y och z (lagrade som floats).

```csharp
// Skapa en Vector3 som har x-värde 2.3, y-värde 4 och z-värde 0.
Vector3 movement = new Vector3(2.3f, 4f, 0f);
```

Vector3-klassen innehåller också bl.a ett antal färdiga vektorer och metoder för att manipulera vektorer.

```csharp
// Skapa en Vector3 som har x-värde 1 (från Vector3.right), y-värde 1 
// (från Vector3.up) och z-värde 0.
Vector3 diagonal = Vector3.right + Vector3.up
```

När man utför vanliga matematiska operationer som innefattar en Vector3 och ett tal så påverkar talet samtliga värden.

```csharp
// Skapa en Vector3 som har x-värde 4, y-värde 4 och z-värde 0.
Vector3 veryDiagnonal = diagonal * 4
```

### Vector2

Fungerar som Vector3 men saknar z-värde.

```csharp
// Skapa en Vector2 som har x-värde 2.3 och y-värde 4.
Vector2 movement = new Vector2(2.3f, 4f);
```

### Quaternion

Beskriver rotationer. Kluriga att använda; man skapar dem nästan aldrig själv utan använder olika metoder som genererar dem. Den vanligaste användningen är att man bara hämtar den färdiga "noll-roterade" Quaternion.identity och använder den i t.ex. Instantiate().

### GameObject

Beskriver spelobjekt. Innehåller bland annat referens till den obligatoriska transform-komponenten, metoden för att förstöra objektet, samt metoden för att hämta referenser till objektets olika komponenter.


# Input

## Tangentbordet (och handkontroller)

### Input.GetAxisRaw()

En metod som hämtar det nuvarande värdet hos en [axel](/grundlaggande-koncept/knappar-och-axlar). Returnerar resultatet som en float.

```csharp
float moveX = Input.GetAxisRaw("Horizontal");
```

## Musen

### Input.mousePosition

En [Vector3](/grundfunktioner/datatyper-och-synlighet#vector3) som innehåller musens nuvarande position i "screen space", alltså uttryckt i pixlar utifrån origo uppe i vänstra hörnet.

### Camera.main.ScreenToWorldPoint()

En metod som förvandlar en vektor som mäter position i "screen space" till en vektor som mäter position utifrån Unityenheter och unitys grid.

```csharp
Vector3 mousePosOnScreen = Input.mousePosition;
Vector3 mousePosInWorld = Camera.main.ScreenToWorldPoint(mousePosOnScreen);
```

### OnMouseUp()

En händelsemetod som man kan lägga till sitt projekt, lite som OnEnterCollision eller [Start eller Update](/grundlaggande-koncept/monobehavior#haendelse-metoder). Den anropas ifall användaren klickar på objektet. Det kräver att objektet har en collider.

```csharp
private void OnMouseUp()
{
    print("hey");
}
```

### Cursor.lockState

Låter dig begränsa muspelarens rörelser. lockState kan ha tre olika värden:

* `CursorLockMode.Locked` – pekaren är helt fast
* `CursorLockMode.Confined` – pekaren kan inte lämna fönstret
* `CursorLockMode.None` – pekaren begränsas inte.

Exempel:

```csharp
Cursor.lockState = CursorLockMode.Locked;
```

### Cursor.visible

Bestämmer ifall muspekaren ska vara synlig.

```csharp
Cursor.visible = false;
```


# Unity Input System

Unity har ett nytt input-system. För att aktivera det, gå till [Package manager](/andra-funktioner/package-manager) och lägg till **Input System** till projektet.

(Vidare läsning: [Complete guide to the new system](https://gamedevbeginner.com/input-in-unity-made-easy-complete-guide-to-the-new-system))

{% hint style="info" %}
**Det enklaste sättet** att börja arbeta med det här systemet är via en [Player Input](#player-input)-komponent.
{% endhint %}

## Player Input

PlayerInput är en [komponent](/grundlaggande-koncept/komponenter) som får kod att köras när spelaren trycker på knappar eller drar i spakar.

<figure><img src="/files/dWOVjXMqm3YCkh5o4khx" alt=""><figcaption></figcaption></figure>

Komponenten behöver en **Input Action Asset** för att fungera. Om det inte finns en, så kan man skapa den genom att klicka på "Create Actions…".

En Input Action Asset innehåller kopplingar mellan specifika knapptryck (WASD, vänster analog spak) och en Action (t.ex. Move).

{% hint style="info" %}
**OBSERVERA!** När du lagt till en Input Action Asset, se till att välja Default Map! Ofta är det helt enkelt "Player" som ska vara default.
{% endhint %}

**Behavior** är det sätt Player Input-komponenten använder för att kommunicera med andra scripts. Send Messages är antagligen det enklaste.

### Send Messages

Om en scriptkomponent på samma spelobjekt som Player Input har metoder som är döpta på rätt sätt, så kommer de metoderna att anropas när spelaren trycker på knappar eller drar i analoga spakar. I en normal Input Action Asset finns till exempel en Action som heter Move. När spelaren trycker på, eller släpper upp, någon av knapparna eller spakarna som är knuten till denna Action, så körs OnMove-metoden om den finns.

```csharp
public class AvatarController : MonoBehaviour
{
  void OnMove()
  {
    print("Moving!");
  }
}
```

### Läsa av input-värden

För att läsa av exakt vilket värde en knapp eller spak har, till exempel för förflyttning, så kan man lägga till en **InputValue**-parameter till de metoder som anropas av Send Message-systemet.

Från ett InputValue-objekt kan man sedan få ut Vector2 eller float eller bool, beroende på vilken typ av data som skickas av motsvarande Action. Move har ofta en Vector2 som Action Type, till exempel.&#x20;

```csharp
using UnityEngine;
using UnityEngine.InputSystem;

public class AvatarController : MonoBehaviour
{

  [SerializeField]
  float speed = 2;

  Vector2 movement = new Vector2();

  void Update()
  {
    transform.Translate(movement * speed * Time.deltaTime);
  }

  void OnMove(InputValue value)
  {
    movement = value.Get<Vector2>();
  }
}
```

## Sammanfattning av hur det egentligen funkar

**Sammanfattning:**

* **Player Input**-komponenten kopplar ihop en **Input Action Asset** med spelets övriga kod.
* En **Input Action Asset** består av en eller flera **Action Maps**.
* Varje **Action Map** beskriver en uppsättning kontroller för en del av ett spel (t.ex. båtsekvenser, eller plattformshoppande). Och består av ett antal **Input Actions**.
* En **Input Action** kopplar ihop vissa knapptryck (t.ex. mellanslag och A på handkontroll) med ett värde med specifierad datatyp (t.ex. float). "Movement" kan vara en Input Action, medan WASD är ett sätt att mata Movement med data.

Man kan arbeta antingen separat med enskilda Input Actions, eller så kan man jobba mer övergripande med Input Action Assets och låta Unitys system hantera mer av strukturen.

## InputAction

Grunden till det nya systemet är **InputActions**. En InputAction knyter ihop knappar och andra inputs till värden. Detta kallas **bindings**.&#x20;

Exempel: En *Movement-InputAction* som knyter WASD och en handkontrolls vänstra analoga styrspak till en 2D-vektor med X- och Y-värden.

Det går att lägga till en InputAction direkt i ett script, och då knyta knappar etc till denna action via gränssnittet i Unitys inspector.

Glöm inte `using UnityEngine.InputSystem` högst upp!

```csharp
using UnityEngine.InputSystem;

public class PlayerController : MonoBehaviour
{
  public InputAction moveAction;
  
  private void Awake()
  {
    moveAction.Enable(); // OBS!
  }
}
```

Innan en InputAction börjar fungera måste dess Enable()-metod först anropas.

I Inspectorn lägger man sedan till nya **bindings** med plus-knappen. Man bestämmer vilken typ av **värde** InputActionen ska ge ifrån sig genom att klicka på kugghjulet.

![En InputAction med en Up/Down/Left/right composite-binding som döpts till WASD](/files/2oa5mnk8K8H8cv6xm5pi)

### ReadValue<>

Används för att läsa av en InputActions värde. Datatypen anges mellan <>. Om ingen binding har rätt datatyp, returneras ett nollvärde.

```csharp
  void Update()
  {
    Vector2 movement = moveAction.ReadValue<Vector2>();
    
    transform.Translate(movement * speed * Time.deltaTime;
  }
```

### Actions

Varje InputAction har tre [delegatvariabler](broken://spaces/-MHmNgpRz-b16wpwGwZI-887967055/pages/-MHzpdfgJmvzXgoB8QQf) av typen [`Action`](https://krank23.gitbook.io/csharp-ref/grundlaeggande/delegates#h.p_qt3arehin8yt)`<InputAction.CallbackContext>`. Delegaterna heter **started**, **canceled** och **performed**.

**Started** anropas normalt sett när input påbörjas och **canceled** när input avslutas, så de är lätta att använda för att koppla kod till när en knapp till exempel trycks ner (started) eller släpps upp (canceled). **Performed** är mer komplicerad och när den anropas beror på vilken sorts InputAction det rör sig om (Value eler Button t.ex).

InputAction.CallbackContext-parametern innehåller information om den InputAction-händelse som anropade metoden, så man kan koppla samma metod till flera Actions och ändå göra skillnad i vad som händer.

```csharp
  void Awake()
  {
    fireAction.Enable();
    fireAction.started += OnFireStart;
    fireAction.canceled += OnFireEnd;
  }
  
  void OnFireStart(InputAction.CallbackContext context)
  {
    // Börja ladda upp skottet
  }
  
  void OnFireEnd(InputAction.CallbackContext context)
  {
    // Avfyra skottet
  }
```

## Input Action assets

En InputAction asset samlar ett flertal ActionAssets på ett och samma ställe. Man skapar en sådan genom att högerklicka i Assets och välja Create -> Input Actions.

En InputAction asset är tänkt att samla en spelares inputs. Har man flera spelare, så skapar man en asset per spelare för att hålla isär deras kontroller.

![](/files/h8qNG5lP2pElwaWvZTUm)

### Action Maps

Används för att separera kontrollerna för olika delar av spelet. Man kan till exempel ha en Action Map för **menyer** och en för själva **spelet**. I spel där man ibland kör fordon och ibland springer omkring som ensam person kan Action Maps separera styrningen för de olika sekvenserna.

Varje Action Map innehåller ett antal InputActions. De har samma tillval som andra InputActions.

### Control Schemes

Control Schemes är sätt att gruppera och filtrera bindings i en InputAction asset. Till exempel kan projektet ha Control Schemes för **tangentbord+mus**, **handkontroll** och **touchscreen**.

### InputAction assets i kod

Lägg till en InputActionAsset-variabel och gör så att den [syns i inspectorn](/grundfunktioner/datatyper-och-synlighet#synlighet). Använd Unitys gränssnitt för att välja vilken asset som ska användas av scriptet.

Genom att anropa assetens Enable-metod så aktiveras den som helhet. Enskilda InputActions behöver inte aktiveras manuellt.

```csharp
using UnityEngine.InputSystem;

public class PlayerController : MonoBehaviour
{
  public InputActionAsset actionAsset;
  
  private void Awake()
  {
    actionAsset.Enable();
  }
}
```

### FindAction()

Metoden FindAction tar emot namnet på en InputAction som parameter och returnerar denna InputAction om den hittas i InputAction asseten som den anropas i.

```csharp
  private void Awake()
  {
    actionAsset.Enable();
    InputAction fireAction = actionAsset.FindAction("Fire");
    
    fireAction.started += OnFireStart;
    fireAction.canceled += OnFireEnd;
  }
```

##


# Flytta och rotera

## Time.deltaTime

Eftersom alla datorer är olika snabba så blir det lite konstigt om man har t.ex. en fast förflyttning eller fast rotation per bildruta.

Time.deltaTime är en float som innehåller tiden som gått sedan föregående bildruta i sekunder.

Det gör att om man multiplicerar en hastighet med Time.deltaTime så kommer det att bli en stor förflyttning om man har få fps och en mindre förflyttning om man har hög fps.

Om hastigheten ska vara 2 rutor per sekund så kommer objektet alltså att röra sig 2 \* 1/30 per bildruta på en dator som har 30fps och 2 \* 1/60 per bildruta på en dator som har 60fps.

```csharp
float speed = 2;
Vektor3 movement = Vektor3.right * speed * Time.deltaTime;
```

## Position

### transform.Translate()

En metod som tar emot en [Vector3 ](/grundfunktioner/datatyper-och-synlighet#vector3)och adderar den till den nuvarande positionen - samma sak som att addera själv alltså, men via en metod.

```csharp
Vektor3 movement = Vektor3.right * Time.deltaTime;
transform.Translate(movement);
```

### transform.position

En [Vektor3](/grundfunktioner/datatyper-och-synlighet#vector3) som motsvarar objektets nuvarande x, y- och z-position i världen.

```csharp
Vector3 newPosition = new Vector3(2f, 3.2f, 0f);
transform.position = newPosition;
```

Ovanstående exempel skapar en ny vektor med x-värde 2, y-värde 3.2 och z-värde 0. Därefter byts objektets nuvarande position ut mot den nya vektorn.

```csharp
Vector3 movement = Vector3.right * Time.deltaTime;
transform.position += movement
```

Ovanstående exempel skapar först en ny vektor som beskriver hur mycket objektet ska förflyttas, och sedan adderar den vektorn till transform.position så att det nya värdet som transform.position har är den nya positionen den ska ha.

### Vector3.Lerp()

Lerp står för "Linear interpolation". Förenklat kan man stoppa en "källvektor" och en "målvektor" och få ut en vektor som ligger mellan källan och målet. Man anger också en float som mäter hur långt längsmed rutten från källan till målet som den mellanliggande vektorn rört sig.

Detta brukar användas för att skapa "mjuka" rörelser och storleksförändringar.

```csharp
Vector3 newPosition = Vector3.Lerp(transform.position, target.transform.position, 0.5f);
// newPosition ligger precis mellan transform.Position och target.transform.Position.

transform.position = newPosition;
```

Kör man ovanstående kod i Update() så kommer objektet att flytta sig halva vägen varje bildruta. Det kommer alltså egentligen aldrig att komma fram…

Float-värdet behöver vara mellan 0 och 1, för 1 innebär "hela vägen".

## Rotation

Man jobbar sällan direkt med Quaternions i Unity; man skapar åtminstone sällan egna. Istället använder man olika metoder för att generera eller förändra quaternions.

### transform.Rotate()

Roterar objektet ett givet antal grader i x, y och z-led.

```csharp
transform.Rotate(90, 0, 0);
transform.Rotate(new Vector3(90, 0, 0));
```

Eller ett visst antal grader runt en given axel

```csharp
transform.Rotate(Vector3.up, 45);
```

### transform.RotateAround()

Snurrar objektet ett givet antal grader runt en punkt och en axel som skär denna punkt.

```csharp
Vector3 sunPosition = new Vector3(0, 10, 60);
transform.RotateAround(sunPosition, Vector3.up, 30);
```

### transform.rotation

Om man fått fram en quaternion eller vill använda en färdig – t.ex. nollrotationen Quaternion.identity – så an man ändra på transform.rotation direkt.

```csharp
transform.rotation = Quaternion.identity;
```

### transform.LookAt()

Används främst i 3D – roterar objektet så att dess interna "forward"-axel pekar mot en specifik position.

```csharp
// roterar objektet så dess forward pekar mot världens nollpunkt
transform.LookAt(Vector3.zero);
```

### Motsvarigheten till LookAt() i 2d

Det finns ett lite "fuskigt" sätt att rotera ett objekt i 2d så att det pekar mot ett annat objekt i scenen.

```csharp
transform.right = target.position - transform.position;
```


# Kollisioner

Unity kan känna av en kollision mellan två objekt, men bara om:

* Båda objekten har en **collider**.
* Båda dessa colliders är av samma "familj"; en 2d-collider kan inte kollidera med en 3d-collider.
* Minst ett av objekten har en **RigidBody** av samma familj.

Med andra ord: För ett 2d-spel, se till så att minst ett av två objekt som ska kunna kollidera har en rigidbody2d och att båda har en 2d-collider.

Om man inte behöver gravitation i sitt spel så kan man ändra Gravity Scale till 0.

För mer exakt kollisionshantering kan man ändra Collision Detection till Continuous, Sleeping Mode till Never Sleep och Interpolate till antingen Interpolate eller Extrapolate.

![](/files/-ML7qMsAf1rh58AclJj8)

## Triggers

Trigger-colliders är colliders som inte har någon fysisk närvaro; de hindrar inte förflyttning och saker studsar inte från dem. Man förvandlar en vanlig collider till en trigger genom att kryssa i "Is Trigger".

## OnCollisionEnter2D()

Metoden OnCollisionEnter2D anropas när två objekt kolliderar och båda har vanliga 2d-colliders - och minst en av dem har en RigidBody. Om ett objekt har flera scripts med en OnCollisionEnter2D-metod så anropas samtliga.

Dess första parameter innehåller en referens till kollisionen, som bland annat innehåller information om det andra objektet.

```csharp
void OnCollisionEnter2D(Collision2D col)
{
  Debug.Log("OnCollisionEnter2D");
  if (col.gameObject.tag == "bullet")
  {
    Debug.Log("Bullet collision!");
  }
}
```

I ovanstående exempel används variabeln col som namn på kollisionen, och man kan därmed komma åt det andra spelobjektet genom att använda col.gameObject.

## OnTriggerEnter2D()

Om två objekt kolliderar och båda har 2d-colliders, men **den ena collidern är en trigger**, så anropas OnTriggerEnter2D istället för OnCollisionEnter2D. Metoderna fungerar i övrigt nästan likadant.

Skillnaden är att den första parametern innehåller en referens till det andra objektets collider, snarare än information om kollisionen i sig.

```csharp
void OnTriggerEnter2D(Collider2D other)
{
  Debug.Log("OnTriggerEnter2D");
  if (other.gameObject.tag == "trap")
  {
    Debug.Log("Trap triggered!!");
  }
}
```

I praktiken används de dock oftast likadant.

## OnCollisionEnter()

Fungerar likadant som 2D-versionen, förutom att den använder sig av RigidBody och vanliga Colliders snarare än 2D-versionerna.

```csharp
void OnCollisionEnter(Collision collision)
{
  Debug.Log("OnCollisionEnter");
  if (col.gameObject.tag == "bullet")
  {
    Debug.Log("Bullet collision!");
  }
}
```

## OnTriggerEnter()

Fungerar likadant som 2D-versionen, förutom att den använder sig av RigidBody och vanliga Colliders snarare än 2D-versionerna.

```csharp
void OnTriggerEnter(Collider other)
{
  Debug.Log("OnTriggerEnter");
  if (other.gameObject.tag == "trap")
  {
    Debug.Log("Trap triggered!!");
  }
}
```


# Skapa och förstör

## Instantiate

För att skapa en kopia av ett GameObject används Instantiate.

```csharp
Instantiate(somePrefab);
```

Ofta används denna för att skapa kopior av prefabs. Då deklarerar man en GameObject-variabel som public eller använder [SerializeField](/grundfunktioner/datatyper-och-synlighet#serializefield). Sedan använder man Unitys editor, och inspectorn, för att göra så att variabeln länkar till prefaben i Assets.

```csharp
[SerializeField]
GameObject somePrefab;
```

### Bestämma position och rotation

Det finns flera [överlagrade](https://krank23.gitbook.io/csharp-ref/grundlaeggande/egna-metoder#oeverlagring) varianter av metoden Instantiate. Vilken version som används beror på vilka parametervärden som anges.

En av de vanligaste är den som anropas när man anger en Vector3 och en Quaternion. Då används vektorn som position för det nya objektet och quaternionen som rotation.

```csharp
Instantiate(somePrefab, new Vector3(1, 3, 0), Quaternion.identity);
```

I exemplet ovan placeras det nya objektet på x=1, y=3, z=0.

För att placera det skapade objektet på samma plats som det objekt som skapar det, till exempel om man vill skapa en projektil som avfyras från spelarens rymdskepp, så kan man givetvis använda trandsform.position, som ju är en vektor som beskriver objektets egen position.

```csharp
Instantiate(somePrefab, transform.position, Quaternion.identity);
```

I exemplen ovan används Quaternion.identity för rotation. Identity är en färdig Quaternion som är neutral - motsvarigheten till Vector3.zero.

### Att använda objektet efter att det skapats

Ofta vill man göra saker med det nya objektet efter att det skapats. Ett vanligt exempel är att man vill ändra dess parent, dvs lägga in det som child-objekt till det nuvarande. På så vis får man ju en snygg hierarkisk struktur.

Turligt nog returnerar Instantiate-metoden en referens till det nyskapade objektet.

```csharp
GameObject newThing = Instantiate(somePrefab, 
  transform.position, Quaternion.identity);

newThing.transform.SetParent(this.transform);
```

## Destroy

För att förstöra ett spelobjekt används Destroy.

```csharp
Destroy(this.gameObject);
```

Denna kod förstör det spelobjekt som det här scriptet sitter fast vid.

Man kan också påverka andra spelobjekt.

```csharp
GameObject g = GameObject.Find("Door");
if (g != null)
{
  Destroy(g);
}
```

Letar rätt på spelobjektet med namnet "Door" och förstör det, om det finns.

```csharp
private void OnTriggerEnter2D(Collider other)
{
  if (other.gameObject.tag == "Door")
  {
    Destroy(other.gameObject);
  }
}
```

När det här objektet kolliderar med ett objekt som har en trigger-collider, kolla om det objektet har taggen "Door", och förstör det i så fall.


# Hitta spelobjekt

{% hint style="info" %}
**OBSERVERA:** Detta bör inte göras mer än nödvändigt – alltså helst inte av många objekt samtidigt och helst inte varje frame. Det är systemmässigt kostsamt!
{% endhint %}

## Find

Find tar emot ett namn som parameter och returnerar det objekt som matchar. Om inget matchar, returneras null.

```
GameObject player = GameObject.Find("Player");
```

## FindWithTag

FindWithTag tar emot namnet på en tag som parameter och returnerar ett objekt som har taggen. Om inget matchar, returneras null.

```
GameObject player = GameObject.FindWithTag("StartPosition");
```

## FindGameObjectsWithTag

FindGameObjectsWithTag är en metod inbyggd i GameObject-klassen, som tar emot namnet på en tag som parameter och returnerar en array med de objekt som har taggen.

```
GameObject[] enemies = GameObject.FindWithTag("Enemy");
```


# Beständig data

## Spara data mellan scener

### Static

Ett väldigt enkelt sätt att spara data så att den inte förstörs vid scenbyte är att lagra datan i en [statisk](https://csharp.progdocs.se/klasser-och-objektorientering/static) variabel.

```csharp
public class AvatarController : MonoBehaviour
{
  public static int score = 100;
}
```

Eftersom statiska variabler inte är knutna till någon specifik instans av klassen så finns de kvar även när alla instanser som finns i scenen förstörts. Därför kan de användas för att lagra data som ska föras över från en scen till en annan.

### DontDestroyOnLoad()

Objektet som anges som parameter kommer inte att förstöras när en ny scen laddas, utan ligga kvar i minnet. Det betyder att alla objektets variabler också behåller sina värden. Objektet kan sedan hittas i den nya scenen genom t.ex. [Find](/grundfunktioner/hitta-spelobjekt#find), och dess värden läsas av.

```csharp
public class ScoreHandler : MonoBehaviour
{
  public int score = 0;

  void Start()
  {
    DontDestroyOnLoad(this.gameObject);
  }
}
```

## Spara data mellan körningar av spelet

### PlayerPrefs

Kan användas för att spara strings, ints och floats för spelet.

#### Save()

Sparar alla värden till hårddisk.

#### HasKey()

Tar emot en string som parameter, returnerar true ifall det finns ett värde med det namnet.

```csharp
if (PlayerPrefs.HasKey("score"))
{
  score = PlayerPrefs.GetInt("score");
}
```

#### DeleteKey()

Tar emot en string som parameter, tar bort värdet med det namnet (om det finns).

#### DeleteAll()

Tar bort alla värden.

#### GetInt(), SetInt()

Läser av respektive ändrar på ett int-värde med det namn som anges som parameter.

```csharp
PlayerPrefs.SetInt("Score", 300);

score = PlayerPrefs.GetInt("score");
```

#### GetFloat, SetFloat

Läser av respektive ändrar på ett int-värde med det namn som anges som parameter.

```csharp
PlayerPrefs.SetFloat("modifier", 3.4f);

modifier = PlayerPrefs.GetFloat("modifier");
```

#### GetString, SetString

Läser av respektive ändrar på ett string-värde med det namn som anges som parameter.

```
PlayerPrefs.SetString("name", "Mira");

name = PlayerPrefs.GetString("name");
```

### WriteAllText, WriteAllLines

[Samma metoder som används i vanliga C#](https://csharp.progdocs.se/filhantering/laesa-och-skriva) för att läsa och skriva data fungerar precis likadant i Unity. Däremot bör man använda **Application.persistentDataPath** som första del av alla filnamn för att se till så filerna sparas i rätt mapp (spelets data-mapp).

```csharp
string name = "Mira";
string filename = Application.persistentDataPath + "/name.txt";

File.WriteAllText(filename, name);
```

I Windows är Application.persistentDataPath lika med:

```
%userprofile%\AppData\LocalLow<companyname><productname>
```

Där %userprofile% är din användares mapp (t.ex. C:\Users\Krank) och \<companyname> och \<productname> är de som angetts under Player Settings (Edit → Project Settings → Player).

### JsonUtility

Även om senare versioner av Dotnet har [inbyggda bibliotek](https://csharp.progdocs.se/filhantering/serialisering/json-serialisering) för att serialisera och deserialisera [JSON ](https://csharp.progdocs.se/filhantering/filformat/json)så saknas dessa i den version av Dotnet som ingår i Unity. Istället har Unity **JsonUtility**.

För att förbereda en klass för serialisering med JsonUtility, markera den som \[System.Serializable].

{% code title="GameData.cs" lineNumbers="true" %}

```csharp
[System.Serializable]
public class GameData
{
  public int score;
  public string name;
}
```

{% endcode %}

Sedan kan instanser av klassen serialiseras / deserialiseras.

{% code title="ScoreHandler.cs" lineNumbers="true" %}

```csharp
public class ScoreHandler : MonoBehaviour
{
  public GameData data = new GameData();

  public void SaveData()
  {
    string jsonString = JsonUtility.ToJson(data);
    string filename = Application.persistentDataPath + "/data.txt";
    File.WriteAllText(filename, jsonString);
  }

  public void LoadData()
  {
    string filename = Application.persistentDataPath + "/data.txt";
    string jsonString = File.ReadAllText(filename);
    data = JsonUtility.FromJson<GameData>(jsonString);
  }
}
```

{% endcode %}

#### JsonUtility.ToJson()

Tar emot ett objekt som parameter, returnerar JSON-kod. Lägger man med både ett objekt och ett boolskt värde så avgör det boolska värdet huruvida JSON-koden är snyggt formaterad med indrag etc.

```csharp
string jsonString = JsonUtility.ToJson(data);
string jsonStringPretty = JsonUtility.ToJson(data, true);
```

#### JsonUtility.FromJson<>()

Tar emot en klass mellan <> och en string som parameter. Returnerar en instans av klassen, baserad på den deserialiserade JSON-koden i stringen.

```csharp
data = JsonUtility.FromJson<GameData>(jsonString);
```


# Slump

Slump i Unity fungerar lite annorlunda än i vanlig C#.

### Random.Range <a href="#h.p_9y2btum-ch5y" id="h.p_9y2btum-ch5y"></a>

```csharp
float slumptal = Random.Range(0f, 5f) // Slumpar ett decimaltal mellan 0 och 5
int slumptal2 = Random.Range(0, 5) // Slumpar ett heltal mellan 0 och 5
```


# Fysik (2D och 3D)

I Unity är det fysikmotorn som sköter gravitation och andra fysikaliska krafter, och hindrar objekt från att clippa in i varandra. Den sköter dessutom andra kollisioner – sådana som inte har med fysikaliska krafter att göra alls, utan där det bara finns anledning att avgöra ifall två objekt överlappar varandra.

Det finns två helt separata fysikmotorer – 2D och 3D. Båda kan finnas med i samma projekt, men de kan inte påverka eller känna av samma objekt.

## Fysikuppdatering

Fysikmotorn uppdaterar normalt inte objektens position varje bildruta, utan har en egen frekvens. Som standard är denna 50 ggr/sekund. Det går att ställa in under **Edit → Project Settings**, och sedan **Time**. Där finns **"Fixed Timestep"**, som normalt är 0.02.

Metoden **FixedUpdate** körs varje fysik-timestep.

```csharp
void FixedUpdate()
{
  Debug.Log("Doing all the physics!");
}
```

## Rigidbody/Rigidbody2D

RigidBody-komponenterna är kärnan i fysikmotorn. Bara objekt med en RigidBody omfattas av fysikmotorns simuleringar. Undantaget är objekt som kolliderar med dem – de påverkas också, om de har rätt sorts collider.

TL,DR: för att ett objekt ska ges **gravitation** etc behöver det en RigidBody. För att en **kollision** ska kunna avläsas med kod (eller märkas av i fysikmotorn) behöver minst ett av de inblandade objekten ha en RigidBody.

### Velocity

Velocity är en property som beskriver objektets nuvarande hastighet – hur mycket dess position förändras över tid. Man bör vara försiktig med att modifiera den direkt.

```csharp
void Update()
{
  RigidBody rigidbody = GetComponent<RigidBody>();
  
  float xMovement = rigidbody.Velocity.x;
}
```

### AddForce()

Används för att applicera ny kraft till en RigidBody, och därmed påverka dess Velocity. Hur mycket velocityn påverkas beror på vilken ForceMode som används och eventuellt på objektets massa.

Unity-enheter fungerar här som meter, och Force-värdet anges i newtons eller newtonsekunder.

```csharp
// Applicera 700 newtons i riktning framåt.
rigidBody.AddForce(Vector3.forward * 700);

// Applicera en impuls av 900 newtonsekunder åt höger
rigidBody.AddForce(Vector3.right * 900, ForceMode.Impulse);
```

* **ForceMode.Impulse:** applicerar en omedelbar mängd kraft (kraften som adderas är per timestep), och tar massan med i beräkningen.
* **ForceMode.Force:** applicerar en mängd kraft per sekund, och tar massan med i beräkningen.
* **ForceMode.VelocityChange:** applicerar en omedelbar mängd kraft (kraften som adderas är per timestep), men struntar i massan.
* **ForceMode.Acceleration:** applicerar en mängd kraft per sekund, men struntar i massan.

[Här är en tråd på Unitys forum](https://answers.unity.com/questions/696068/difference-between-forcemodeforceaccelerationimpul.html) som går igenom den exakta matten, för den som vill läsa mer.

{% hint style="info" %}
**OBS:** För Rigidbody2D-komponenter används ForceMode2D istället för ForceMode.
{% endhint %}

## Colliders

En collider är en "hit box" som används istället för ett spelobjekts faktiska geometri för att se om det kolliderar med något. För att en kollision mellan två objekt ska registreras av fysikmotorn behöver båda ha en collider.

* **BoxCollider** är en collider som är format som ett rektangulärt block.
* **SphereCollider** är en collider formad som ett klot.
* **CapsuleCollider** är en collider formad som en cylinder som är rundad med halvklot i ändarna.
* **BoxCollider2D** är en 2D-collider formad som en rektangel.
* **CircleCollider2D** är en 2D-collider formad som en cirkel.
* **CapsuleCollider2D** är en 2D-collider formad som en rektangel med halvcirklar i ändarna.

### Triggers

En collider som är markerad som "Is Trigger" agerar inte som ett hinder för kollisioner, men kan användas för att genom kod känna av ifall ett annat objekts collider överlappar den.

**Exempel:** När avataren kliver över tröskeln så går larmet och monster instansieras i rummet.

## Kollisionsmetoder

Skrivs dessa metoder in i script som är knutna till ett objekt med en RididBody/RigidBody2D så anropas de automatiskt när en kollision inträffar.

### OnTriggerEnter()

En metod som anropas ifall en collider kolliderar med någon av det här objektets trigger colliders.

```csharp
void OnTriggerEnter(Collider other)
{
  // other är det andra objektets collider
  // Den innehåller i sin tur en referens till det andra objektet,
  // och därifrån kan man nå dess transform, tag och komponenter.
  
  if (other.gameObject.tag == "trap")
  {
    print("It's a trap!");
  }
}
```

### OnCollisionEnter()

En metod som anropas ifall en collider kolliderar med någon av det här objektets vanliga colliders.

```csharp
void OnCollisionEnter(Collision col)
{
  // col är ett objekt som innehåller information om själva kollisionen,
  // däribland en referens till objektet man kolliderade med,
  // och därifrån kan man nå dess transform, tag och komponenter.
  
  if (other.gameObject.tag == "bullet")
  {
    print("Ouch!");
  }
}
```

### OnTriggerEnter2D()

För objekt med RigidBody2D. En metod som anropas ifall en 2D-collider kolliderar med någon av det här objektets 2D trigger colliders.&#x20;

```csharp
void OnTriggerEnter(Collider2Dc other)
{
  // other är det andra objektets collider
  // Den innehåller i sin tur en referens till det andra objektet,
  // och därifrån kan man nå dess transform, tag och komponenter.
  
  if (other.gameObject.tag == "trap")
  {
    print("It's a trap!");
  }
}
```

### OnCollisionEnter2D()

För objekt med RigidBody2D. En metod som anropas ifall en 2D collider kolliderar med någon av det här objektets vanliga 2D-colliders.

```csharp
void OnCollisionEnter2D(Collision2D col)
{
  // col är ett objekt som innehåller information om själva kollisionen,
  // däribland en referens till objektet man kolliderade med,
  // och därifrån kan man nå dess transform, tag och komponenter.
  
  if (other.gameObject.tag == "bullet")
  {
    print("Ouch!");
  }
}
```

###


# Raycasting\*

## (Camera) ScreenPointToRay()

Skapar en ray som utgår från kamerans position och går "igenom" en viss punkt på skärmen.

```csharp
Ray mouseRay = Camera.main.ScreenPointToRay(Input.mousePosition);
```

## Physics.Raycast()

```csharp
RaycastHit hit;
Physics.Raycast(
  cameraObject.transform.position, 
  cameraObject.transform.forward, 
  out hit, 
  maxInteractionDistance);
```

```csharp
Physics.Raycast(mouseRay, out RaycastHit hit)
```


# UI och Canvas\*

## Canvas

Canvas betyder målarduk, och det är Canvas-objektet som samlar alla UI-element när man använder Unitys vanliga system för att skapa gränssnitt. Genom att lägga in bilder, knappar och andra element i Canvasen så blir de spelets gränssnitt.

### Canvas screen space

Canvas-objektet har samma proportioner som spelfönstret, och oavsett objektets storlek så projiceras objektet som helhet ovanpå spelkamerans vy när man spelar spelet. Canvasen skalas alltså så att dess kanter läggs precis på kamerans kanter.

När man normalt skapar en Canvas så är denna *jättestor* i scenvyn. Det beror på att den har Render Mode **Screen Space: Overlay**. Då är canvasobjektets storlek frikopplad från kamerans storlek i scene view, vilket fungerar ganska bra för 3D-spel.

För 2D-spel, framför allt sådana som bara har en kamera, passar det ofta bättre att använda **Screen Space: Camera** som Render Mode. Det ställs in i Canvas-komponenten. Då behöver man också ange vilken kamera canvasen ska anpassa sig efter.

<figure><img src="/files/7Hjlt3yf5cnDce2M8vTd" alt=""><figcaption></figcaption></figure>

## Rect transform

En rect transform har fler delar än en vanlig transform.

* **Anchor** avgör hur ett UI-objekt ska positioneras. Anchor har Min X/Y och Max X/Y. Alla får från 0 till 1, där 0 är längst ner till vänster och 1 är högst upp till höger. Detta är relativt objektet som rect transformens objekt befinner sig i, så ett objekt som ligger i canvasen använder canvasen som utgångspunkt.
  * *Min Y och Max Y är likadana:* använd Pos Y och Height på Y-led.
    * Pos Y bestämmer hur långt från Min/Max Y som objektet befinner sig.
    * Height bestämmer höjden på objektet.
  * *Min Y och Max Y är olika:* använd Top och Bottom på Y-led.
    * Top bestämmer hur långt från Min Y som objektets övre del är.
    * Bottom bestämmer hur långt från Max Y som objektets nedre del är.
  * Min X och Max X fungerar på samma sätt.
    * De är olika: använd Pos X och Width.
    * De är lika: använd Left och Right.
* **Pivot** avgör var på objektet dess koordinater ska räknas från. Det gäller framför allt om Pos X eller Pos Y ska användas. Pivot X 0 och Y 0 innebär att det är objektets nedre vänstra hörn man bestämmer position för. X 1 och Y 1 innebär att det är objektets övre högra hörn man bestämmer position för.

Några exempel på hur man uppnår olika saker med ovanstående system:

* Objektet är lika stort som skärmen
  * Anchor Min X/Y 0, Max X/Y 1
  * Left/Right/Top/Bottom 0
* Objektet upptar hela vänsterkanten och är 300 pixlar brett
  * Anchor Min Y 0, Max Y 1
  * Anchor Min/Max X 0
  * Top/Bottom/Pos X 0
  * Width 300
* Objektet ligger i mitten längst ner på skärmen och är 500 pixlar brett och 100 högt
  * Anchor Min/Max X 0.5
  * Anchor Min/Max Y 0
  * Width 300, Height 100

### Genvägar

Längst upp till vänster i Rect Transform finns en grafisk ruta. Klickar på den fr man fram ett rutnät med 4x4 rutor och tillhörande rad- och kolumnrubriker.&#x20;

## Knappar

(Kommer…)

## Events

(Kommer…)


# Importera grafik\*

Att få in grafik till Unity är ganska lätt. Det finns två sätt:

* Spara bilder och 3d-modeller direkt i Unity-projektets **Assets-mapp**. Då importas de automatiskt av Unity.
* Importera dem genom att dra in dem till Assets-delen av gränssnittet eller använda **Asset → Import new asset**.

Beroende på originalens filformat så skapar Unity någon form av "Asset" kring det, till exempel en Texture2D för bilder.

## Texture2D

En texture2D är helt enkelt en bild. Hur bilden ska användas bestäms genom att man väljer "texture type" i inspectorn.

<figure><img src="/files/fcY0qwlCWx6kgrK3e5RZ" alt=""><figcaption></figcaption></figure>

De vanligaste texturtyperna är:

* **Default** – Texturen agerar som en vanlig 3D-textur, som används för att ge ett 3D-objekt en grafisk yta. Kräver sällan några speciella inställningar.
* **Sprite (2D and UI)** – Texturen agerar som en "sprite"; en egen, fristående, tvådimensionell bild som visas i spelet utan att behöva någon 3d-modell.

### Sprite

{% hint style="info" %}
**OBSERVERA:** I nyare versioner av Unity, eller i 3D-projekt, kan du behöva installera paketet "2D Sprite" via [Package manager](/andra-funktioner/package-manager) för att ha tillgång till Sprite editor-fönstret.
{% endhint %}

För sprites finns tre "Sprite modes":

* **Single** – Bilden innehåller en sprite.
* **Multiple** – Bilden innehåller en eller flera sprites, och de ska delas in genom rektanglar.
* **Polygon** – Bilden innehåller en eller flera sprite, och de ska delas in genom mer komplexa former (polygoner)

För att redigera rektanglarna eller polygonerna används **Sprite editor**-fönstret.

Klicka på den här knappen för att öppna det fönstret: ![](/files/xZYCKPJINZSmPvEYhkKc)

\[BILD HÄR: Single/Multiple/Polygon]

#### Pixels per unit

En sprite består alltid av ett antal pixlar i bredd och höjd. Pixels per unit bestämmer hur många pixlar som ska motsvara en unity-enhet när objektets Scale är 1.0. Skriver man 32 i den rutan så kommer alltså en sprite på 32×32 pixlar att uppta en hel unity-enhet i bredd och höjd.

Högre siffror här ger alltså lägre storlek.

\[BILD HÄR: 32×32 @ 32, 64, 16]

### Sprite sheets

På ett sprite sheet finns flera olika bilder till spelet på samma bild, Ofta brukar man ha ett sprite sheet per karaktär, eller till och med ett sprite sheet per animation

\[BILD HÄR: Ett enkelt sprite sheet]

För sprite sheets i Unity används normalt sett Sprite mode: Multiple. I Sprite editorn kan man då använda Slice-funktionen för att automatiskt dela in bilden i mindre delar. Man väljer att dela in den efter hur stor varje bild ska vara eller hur många bilder det ska vara i bredd respektive höjd.

\[BILD HÄR: Slice]

(Mer kommer…)

### Pixelart och texturer

Importen för bilder är anpassad för högupplösta texturer, vilket betyder att de fokuserar på komprimering och snabbhet snarare än precision. När man jobbar med pixelart funkar inte det – då måste man ändra lite inställningar

(Mer kommer…)

## 3D-modeller

* fbx
* obj
* blend


# Sprite editor\*

Sprite Editor-fönstret används för att bestämma saker om en sprite. Förutom vilken textur som ska ligga till grund för spriten behöver Unity nämligen veta till exempel hur den ska delas upp (för spritesheets och tilesets), hur dess kollisions-form ska vara och var dess pivot ska befinna sig.

## Slicing

Spritesheets och tilesets är båda exempel på när man packat in flera bilder i en bildfil. I ett spritesheet samlas alla bildrutor för en eller flera animationer på samma bild. I ett tileset samlas istället alla unika rutor som används för att rita upp en [tilemap](/andra-funktioner/tilemaps).

Se till att "Sprite Mode" är Multiple i texturens import settings innan du börjar arbeta i sprite editorn.

<figure><img src="/files/id6wVSOLfkSNgYY1kSwA" alt=""><figcaption></figcaption></figure>

För att börja dela upp bilden klickar man på Slice. Därefter kan man välja slice type – vilken princip som ska användas för uppdelningen.

* **Automatic:** Låt Unity gissa
* **Grid by Cell Size:** välj hur många pixlar stor varje ruta ska vara.
* **Grid by Cell Count:** välj hur många kolumner resp. rader bilden ska delas upp i.

De två senare är oftast väldigt bra för tilesets och spritesheets, framför allt när det gäller pixel art.

Klicka på **Slice** för att göra uppdelningen och skapa rutorna.

## Sprite

Klickar man på en av rutorna så kan man redigera den.

<figure><img src="/files/Ity04cgXd5r4CKLihtCu" alt=""><figcaption></figcaption></figure>

Här kan man manuellt justera koordinater och bredd och höjd. Man kan också välja **pivot**.

## Pivot

En sprites pivot är den punkt som den roteras kring, när man snurrar på den eller flippar den. Oftast funkar det bra att bara låta den ligga i mitten (Center), men det kan vara bra att flytta på den. Den bör ligga på karaktärens "mittpunkt" när det gäller spritesheets – eller möjligen karaktärens fötter, beroende på vad man vill uppnå.

## Physics shape\*


# Unity Events

Unity Events är en variation på samma designmönster som C# [delegater](https://krank23.gitbook.io/csharp-ref/grundlaeggande/delegates#multicasting-delegat-variabler-med-flera-metoder). En händelse – en "event" – knyts till en eller flera metoder. Så när händelsen aktiveras, så körs alla metoder som kopplats till den.

Skillnaden mellan Events och delegater är att med Events sker anknytningen mellan händelse och metoder i första hand via Unity-editorns gränssnitt snarare än med kod.

Många system i Unity använder Events som ett sätt att bygga logik direkt i editorn. UI-systemet använder till exempel Events för att knyta knapptryck till metodanrop, utan att den som designar gränssnittet behöver skriva någon kod.

## I editorn

![](/files/FjEGrZZ5T5H2FDg3LC1J)

Bilden ovan visar tre exempel på UnityEvents som visas i Unity-editorn. Det första eventet har ännu inga metoder kopplade till sig – listan är tom. Listan utökas genom knappen +.

För att koppla en metod till ett Event behövs tre eller fyra bitar information:

* **När** eventet ska vara aktivt – normalt "Runtime only", alltså att eventet bara kan aktiveras när spelet körs.
* **Objektet** som innehåller den komponent vars metod ska anropas.
* **Komponenten** och **metoden** som ska anropas.
* Eventuellt: en **parameter** som skickas in i metoden när den anropas.

Eventet **"Normal Event"** i exemplet anropar metoden **SayHello** på komponenten **Hello**, som i sin tur befinner sig i objektet **TestObject**.

Eventet **"String Event"** anropar istället metoden **SaySomething**, med parametern **"What is Love?"**, på samma komponent (**Hello**) och samma objekt (**TestObject**).

Objektet behöver väljas först, därefter komponenten, metoden och det eventuella parametervärdet.

## UnityEvent

UnityEvent är datatypen för unity events. För att använda den behöver man också inkludera UnityEngine.Events.

{% code title="UnityEventTest.cs" lineNumbers="true" %}

```csharp
using UnityEngine;
using UnityEngine.Events;

public class UnityEventTest : MonoBehaviour
{
  [SerializeField]
  UnityEvent jumpEvent;
}
```

{% endcode %}

### Invoke()

Aktiverar eventet – det vill säga, kör alla metoder som knutits till det.

```csharp
private void Update() {
  if (Input.GetAxisRaw("Jump") > 0)
  {
    jumpEvent.Invoke();
  }
}
```

### AddListener()

Normalt används Unity-gränssnittet för att lägga till metoder som ska anropas när eventet aktiveras, men man kan också göra det i kod via AddListener().

```csharp
private void Start() {
  jumpEvent.AddListener(Jump);
}

private void Jump()
{
  GetComponent<Rigidbody2D>().AddForce(Vector2.up * 1000);
}
```

### UnityEvent<>

För att skapa events som skickar parametervärden till sina metoder, och vars metoder tar emot parametervärden, läggs parametrarnas datatyp till mellan < och >.

{% code title="" lineNumbers="true" %}

```csharp
using UnityEngine;
using UnityEngine.Events;

public class UnityEventTest : MonoBehaviour
{
  [SerializeField]
  UnityEvent<int> powerUpEvent; // Man kan bara lägga till metoder som tar emot integers

  private void Start()
  {
    powerUpEvent.AddListener(PowerUp);
  }

  private void Update()
  {
    if (Input.GetAxisRaw("PowerUp") > 0)
    {
      powerUpEvent.Invoke(9001); // Kör alla metoder, skicka in 9001 som parametervärde
    }
  }

  private void PowerUp(int amount)
  {
    print("Powering up " + amount + "!");
  }
}
```

{% endcode %}


# Invoke, Couroutines

## Invoke

Invoke för att man kan köra en metod efter en viss tid. Passar bra när man vill att något ska göras exakt en gång.

Tar emot en string och en float – namnet på metoden som ska köras och hur långt in i framtiden den ska köras.

```csharp
void Start()
{
  Invoke("EndGame", 60);
}

void EndGame()
{
  SceneManager.LoadScene(0);
}
```

## Coroutines

Coroutines är metoder som körs *vid sidan av* resten av koden. De kan till exempel användas ifall man att något ska ske med jämna mellanrum.

En coroutine-metod behöver ha IEnumerator som returtyp och för att "pausa" körningen av den används "yield return".

Om man yield-returnar null fortsätter metoden köras nästa frame. Annars brukar man ofta yield-returna en new WaitForSeconds() med ett antal sekunder angivna som en float mellan parenteserna.

```csharp
[SerializeField] GameObject enemyPrefab;
[SerializeField] PlayerController player;

void Start()
{
  StartCoroutine(SpawnEnemy());
}

IEnumerator SpawnEnemy()
{
  while(player.IsAlive())
  {
    Instantiate(enemyPrefab);
    yield return new WaitForSeconds(2.5f);
  }
}
```


# Animationer\*

* Animator: hanterar vilken animation som ska spelas
* Animator controller: state machine som styr en animator
* Animation clip: en specifik animation

## Skapa animationer

* Window->Animation->Animation
* Skapa clip & addera Animator-komponent
* Animera properties med keyframes

## Kod

### Animator

#### Play()

Spela upp en specifik namngiven animation.

```
GetComponent<Animator>().Play("WalkLeft");
```

#### SetTrigger(), SetBool(), SetFloat(), SetInteger()

#### runtimeAnimatorController

GetCurrentAnimatorClipInfo()

* Get en array

### AnimationClip

* name
* length

### RuntimeAnimatorController

* Klass som beskriver en AnimatorController
* animationClips: read-only array.
  * Kan göras till List och sedan Find:as för att hitta specifikt clip


# AnimationClip\*

* Window->Animation->Animation
* Timeline
* Keyframes
* Properties
* Sub-objects


# Animator Controller\*

* State machine
* Transitions

## Animator Override Controller


# Tilemaps\*


# Asset Store

[Unity Asset Store](https://assetstore.unity.com/) är en onlinebutik där man kan köpa och ladda ner olika assets, till exempel 3D-modeller, animationer, bibliotek av färdigskriven kod och mycket annat.

I nyare versioner av Unity ser flödet för Asset Store oftast ut såhär:

* Logga in på Asset Store
* Leta rätt på den asset du vill köpa. En del är gratis!
* Klicka på "Add to my assets". Nu finns denna asset kopplad till ditt konto, och tillgänglig att läggas till i alla dina projekt.

![](/files/St5jytx2IKtf982wf9ox)

* Starta Unity och gå till projektet där du vill använda det du valt.
* Öppna [Package manager](/andra-funktioner/package-manager) och gå till My assets.

![](/files/WFpqzhiizf8xBjoBpk1h)

* Markera den asset du vill använda i listan till vänster.
* Klicka på "Download" i nedre högra hörnet.
* När paketet är nedladdat, tryck på "Import".

När du nästa gång vill använda samma paket behöver du varken gå till Asset store eller ladda ner – då går du bara till Package manager och importerar paketet.


# Användbara Assets

* [**Export Project to Zip**](https://assetstore.unity.com/packages/tools/utilities/export-project-to-zip-243983): Gör det enkelt att packa ihop hela projektet till en zipfil, utan att t.ex. den onödiga Library-mappen kommer med.


# Package manager

Varje Unityprojekt består av ett antal olika moduler. En del av dem är frivilliga, och det finns väldigt många som kan läggas till i efterhand till exempel via [Asset Store](/andra-funktioner/asset-store). Modulerna är packeterade som "paket" som kan läggas till eller tas bort från projekt.

Det finns fyra listor med paket: Unity Registry, In Project, My Assets och Built-in.

![](/files/m3Lj4dVFVHdRDF5Il3DQ)

* **Unity Registry** är paket som Unity skapat och gjort tillgängliga.
* **In Project** är en lista med paket som just nu är tillagda i projektet.
* **My Assets** listar paket du lagt till bland dina assets på Asset Store.
* **Built-In** är paket som automatiskt finns inbyggda i varje Unityprojekt. De kan du inte ta bort helt, men du kan aktivera eller avaktivera dem.

## Preview packages

Unity utvecklar nya paket hela tiden, och en del av dem är experimentella – ännu inte riktigt redo för att användas i spel som ska säljas och behöver vara riktigt stabila.

För att komma åt dem, tryck på kugghjuls-ikonen (![](/files/VI5tCsUpjjm0hsdi8Lz2)) till vänster om sökrutan i Package Manager och välj "Advanceed Project Settings". Kryssa i "Enable Preview Packages".

![](/files/HeumE2dwGfoxROEzLcIB)

Nu kommer du att se fler paket i Unity Registry-listan. De som är experimentella är tydligt utmarkerade.

![](/files/sUMXQhMz8mDMghsHqdiQ)


# Meddelanden

Att "skicka ett meddelande" betyder att alla komponenter på objektet kör en namngiven metod *om den finns*.

Båda dessa har en prestandakostnad – de bör inte användas om andra alternativ finns.

### SendMessage()

Kör en namngiven metod i alla komponenter på samma objekt som scriptet.

```csharp
// Kör metoden "DoSomething()" på alla scriptkomponenter som har den
SendMessage("DoSomething");
```

### BroadcastMessage()

Kör en namngiven metod i alla komponenter på samma objekt som scriptet – eller dess barnobjekt.

```csharp
// Kör metoden "DoSomething()" på alla scriptkomponenter som har den
BroadcastMessage("DoSomething");
```


# CharacterController

CharacterController är en komponent för att hantera spelkaraktärer i 3D-spel. Med en CharacterController behöver karaktären ingen RigidBody eller Collider – istället sköter CharacterControllern kollisioner med hjälp av vad som i princip är en Capsule Collider.

CharacterControllers har ingen automatisk gravitation och påverkas normalt inte heller av andra fysik-krafter.

## Move()

Flytta objektet, ungefär som transform.Translate men arbetar normalt sett i den **globala** rymden, dvs förflyttningen är *inte* relativt objektets rotation.

```csharp
Vector3 movement = inputVector.x * movementSpeed * transform.right
                     + inputVector.y * movementSpeed * transform.forward;

GetComponent<CharacterController>().Move(movement * Time.deltaTime);
```

## isGrounded

Kolla ifall karaktären står på marken.

{% hint style="info" %}
**OBSERVERA:** Fungerar bara om karaktären flyttade sig, eller försökte flytta sig, föregående frame! Därför är det bra att t.ex. inte nollställa eventuell vertikal hastighet helt…
{% endhint %}

```csharp
if (characterController.isGrounded)
{
  verticalVelocity = -1;
  if (jumpPressed)
  {
    verticalVelocity = jumpForce;
  }
}
```

## velocity

En [Vector3](/grundfunktioner/datatyper-och-synlighet#vector3) som är den hastighet karaktären har – eller snarare, *hade* föregående frame. Kan inte ändras på; är bara ett passivt uträknat värde.

```csharp
if (characterController.velocity.y > 0)
{
  // Hoppar
}
else if (characterController.isGrounded)
{
  // Står på marken
}
else
{
  // Ramlar nedåt
}
```


# Scriptable objects\*

* Fristående objekt som lever i assets
* Kommunikation mellan andra objekt, så de inte behöver känna till varandra

## Enkla värden

## SO-baserat Event-system


# AI-Navmesh\*

* com.unity.ai.navigation
*
* using UnityEngine.AI
* NavMeshSurface -> Bake (1 per agent type)
* Agent types (storlek etc)
* Nav Mesh Agent
* agent.destination
* Navmesh modifier volume


# Mirror (nätverk)

Mirror är ett bibliotek av komponenter för att bygga multiplayerspel. Det finns gratis via Unitys [Asset Store](/andra-funktioner/asset-store).

### Den korta versionen

* Lägg till Mirror i projektet.
* Skapa ett nytt tomt GameObject, döp det till NetworkManager.
  * Lägg till komponenten NetworkManagerHUD.
  * Lägg till Kcp Transport.
* Ge alla spelobjekt som ska synkas över nätverket en NetworkIdentity-komponent. Även de som ska instantieras senare (t.ex. projektiler).
* Ge alla spelobjekt vars position/rotation ska synkas över nätverket en NetworkTransform-komponent.
  * Ställ in så att objekt som ska styras *direkt* av spelare har Client Authority.
* Gör en prefab av objektet som ska spawnas när en spelare ansluter.
* Förbered för spawning:
  * Lägg till denna prefab i NetworkManager-objektets Player Prefab-variabel.
  * Lägg till de prefabs som ska kunna spawnas över nätverket (projektiler etc) till listan Registered Spawnable Prefabs.
* Gör så att scriptkomponenter som ska köra nätverkskod ärver från NetworkBehavior istället för MonoBehavior
  * Lägg till "using Mirror" högst upp
  * Använd boolen "isLocalPlayer" för att avgöra ifall det nuvarande objektet styrs av den lokala spelaren.
  * Skapa en override för metoden OnStartLocalPlayer för att få ett alternativ till Start() som bara körs för den lokale spelaren
  * Markera metoder som ska köras på servern med \[Command]
  * För objekt som ska spawnas på allas datorer, kör NetworkServer.Spawn().

## NetworkManager

En komponent som samlar in all data som ska synkroniseras över nätverket och använder en Transport-komponent för att skicka/ta emot den. Denna, Kcp Transport och NetworkManagerHUD kan med fördel läggas på samma objekt.

* Ställ in så **Network Transport** blir det objekt som har en Kcp Transport.
* Lägg till den prefab som ska instansieras för varje spelare som registrerar sig och bli den spelarens avatar i **Player Prefab**.
* Lägg till alla prefabs som ska kunna instansieras över nätverket i **Registered Spawnable Prefabs**-listan.

![](/files/MxYJ9le9DeQc0Ue2mtbb)

## NetworkManagerHUD

En komponent som ger spelaren ett gränssnitt för att starta en server eller ansluta till en existerande server.

![](/files/lc74ZPbWrisQJVvYjsxT)

## Kcp Transport

En komponent som används för själva kommunikationen mellan klienter och server. Kan ligga på ett annat objekt än NetworkManager och NetworkManagerHUD.

## Network Identity

En komponent som alla objekt som ska vara unika (ha en egen unik identitet) på nätverket behöver ha. Till exempel alla spelaravatarer, powerups och projektiler

## Network Transform

En komponent som signalerar till NetworkManagern att objektets Transform ska synkroniseras över nätverket – position, rotation och storlek. Bör ges till spelar-avataren, projektiler och annat som flyttar på sig.

## NetworkBehavior

NetworkBehavior är en klass som ingår i Mirror-biblioteket och som i sin tur ärver från MonoBehavior. När man har scriptkomponenter som ska nyttja sig av nätverkskommandon och liknande så behöver deras klasser ärva från NetworkBehavior istället för från MonoBehavior.

```csharp
using UnityEngine;
using Mirror;

public class PlayerController : NetworkBehaviour
{
  // Kod
}
```

### IsLocalPlayer

En bool-variabel som är true ifall objektet tillhör och är styrt av den lokala spelaren.

```csharp
void Update()
{
  if (!IsLocalPlayer)
  {
    return;
  }
  
  // Kod som bara ska köras för den lokala spelaren
}
```

### OnStartLocalPlayer

En variant av Start() som bara körs för den lokala spelaren

```csharp
public override void OnStartLocalPlayer()
{
  // Färgar den lokala spelaren grön
  GetComponent<Renderer>().material.color = Color.green;
}
```

### Nätverkskommandon \[Command]

Metoder som markeras med \[Command] kommer att köras på servern istället för på klienten.

```csharp
[Command]
void CmdFire()
{
  GameObject bullet = Instantiate(bulletPrefab, bulletSpawnPoint.position, bulletSpawnPoint.rotation);
  NetworkServer.Spawn(bullet);
}
```

### NetworkServer.Spawn()

Ett kommando som tar emot ett GameObject, och ser till att instanser av denna skapas och synkroniseras över hela nätverket. Används ofta för att till exempel se till så att projektiler och powerups skapas likadant för alla spelare.

Observera att objektet som ska spawnas måste vara en instans av en prefab som lagts till som Registered Spawnable Prefab i scenens NetworkManager.

```csharp
GameObject bullet = Instantiate(bulletPrefab, bulletSpawnPoint.position, bulletSpawnPoint.rotation);
NetworkServer.Spawn(bullet);
```


# XR Toolkit

*Uppdaterat för XR Toolkit 2.6.3*

XR Toolkit är Unitys officiella sätt att arbeta med VR och liknande. Förhoppningsvis är det lite mer stabilt och långsiktigt än att köra med något fristående ramverk eller bibliotek, till exempel VRTK.

*De här instruktionerna har testats i Unity 2022.3 men bör fungera även med lite tidigare versioner.*

**Termer**

* **VR-headset:** Den "hjälm" man sätter på huvudet för att se VR-världen.
* **VR-handkontroll:** De fysiska apparater man håller i respektive hand för att styra saker i VR-världen.

## Setup

Utgå från ett vanligt 3D-projekt.

Gå till [Package manager](/andra-funktioner/package-manager) och installera paketen "XR Plugin Management" och "XR Interaction Toolkit" (version 2.6.3 eller nyare) från Unity Registry. Tacka ja ifall Unity frågar om du vill byta till det nya input-systemet.

{% hint style="info" %}
Om XR Interaction Toolkit 2.6.3 inte finns i Unity Registry-listan, klicka på plustecknet uppe till höger, "Add package by name" och skriv in **com.unity.xr.interaction.toolkit** som name och **2.6.3** som version.
{% endhint %}

När du lägger till paketet kommer Unity att fråga om du vill aktivera det nya input-systemet. Tacka ja. Det kommer att innebära att Unity-editorn startas om.

{% hint style="danger" %}
**Om du får ett felmeddelande** om att "InputSystem" inte innehåller något som heter "actions" så behöver du manuellt uppgradera inputsystem-paketet. Gå till Package Manager, Unity Registry. Tryck på plusset, och "Add package by name". Skriv in "com.unity.inputsystem" som namn och "1.8.2" som version och tryck på "Add".
{% endhint %}

Du kan nu också få en varning om att "XR InteractionLayerMask Update Required". Den uppdateringen behöver du bara göra om du uppgraderar ett äldre VR-projekt, så du kan med gott samvete klicka "No Thanks".

Under "XR Interaction Toolkit" finns flera "Samples". Lägg till (importera) **Starter Assets**. **XR Device Simulator** lägger du till [om du tänker utveckla utan tillgång till ett VR-headset](/tillaeggspaket/xr-toolkit/device-simulator).

### Enkel scen-setup

Ta bort din Main Camera från scenen.

Sök i Assets efter "xr origin" och dra ut en instans av **XR Origin (XR Rig)** till scenen. Den prefaben finns annars i mappen Samples→XR Interaction Toolkit→\[version]→Starter Assets→Prefabs. Fördelen med att använda denna prefab är att man får med nästan allt man behöver direkt från början. Nackdelen är att man kanske inte gillar hur det fungerar…

Den kommer att fungera som mittpunkten som VR-trackingen utgår från. Placera den där du vill att spelaren ska börja, och tänk att den ligger på golvet mellan spelarens ben.

Lägg till en **Input Action Manager**-komponent till XR Origin-objektet i scenen. Lägg till **XRI Default Input Actions** till dess lista.

Lägg in en **XR Interaction Manager** i scenen (Högerklicka i hierarkin, XR → Interaction Manager).

{% hint style="info" %}
**OBSERVERA:** I prefab-versionen av XR Origin (XR Rig) används interaction layers för att skilja områden man ska kunna teleportera till från sådana man inte ska kunna teleportera till.

För att det ska fungera **måste interaction layer nummer 31 finnas och vara namngivet**. Eller så får man manuellt gå in och ändra vilket lager som ska användas.

Gå till valfri XR Interactor, till exempel den i XR Origin (XR Rig)→Camera Offset→Left Controller→Teleport Interactor. Leta rätt på "Interactor Layer Mask". Klicka på den och välj "Add layer…". I listan, ge lager 31 ett namn.
{% endhint %}

## Rekommenderade justeringar

XR Origin-riggen har ett par standardgrejer som kan upplevas som jobbiga eller opassande för många vana VR-användare – t.ex. har den inte bara teleportation inbyggd utan också åksjukekontroller (möjligheten att flytta sig i VR-världen genom att dra i vänster handkontrolls styrspak). Den har också strålar som utgår från båda handkontrollerna kontinuerligt och som kan användas för att interagera med saker i spelvärlden, där standard snarare är att man bara kan interagera med saker man kan röra vid.

* För att stänga av åksjuke-kontrollerna: Gå in under **XR Origin (XR Rig) → Locomotion Systems** och ta bort eller stäng av child-objektet **Move**.
* För att stänga av fjärrmanipulering: Gå in under **XR Origin (XR Rig) → Camera Offset → Left Controller** och plocka bort child-objektet **Ray Interactor.**

## Manuell scen-setup

De här instruktionerna ger dig en mer avskalad setup – du måste själv lägga in locomotion och annat.

Ta bort scenens Main Camera.

Lägg in en **XR Interaction Manager** i scenen (GameObject → XR → Interaction Manager).

Lägg in en **XR Origin** i scenen (GameObject → XR → XR Origin (VR)).

Expandera XR Origin och dess Camera Offset och markera LeftHand Controller. Klicka på "Select Preset" (<img src="/files/knJYUiZNAPdifP1e6LOT" alt="" data-size="line">) och välj **XRI Default Left Controller**. Gör samma sak för RightHand Controller, men där väljer du **XRI Default Right Controller**.


# Controllers

## Prefab (utseende)

Om du använder XR Origin-prefaben så syns dina kontroller som ett par generiska vita 3d-modeller i VR-rymden. Oavsett vilket kan du välja egna 3d-modeller att använda.

Expandera XR Origin och Camera Offset, och markera LeftHand Controller (eller RightHand Controller). Scrolla ner till "Model prefab". Lägg in den modell du vill använda.

De generiska vita 3d-modellerna finns under Assets → Samples → XR Interaction Toolkit → 2.4.3 → Starter Assets → Prefabs → Controllers.

## Kod

Nedanstående är den kod som du kan använda för att få saker att hända när spelaren gör olika saker med VR-handkontrollerna.

### ActionBasedController

Komponenten ActionBasedController innehåller referenser till alla actions för VR-handkontrollerna.

```csharp
using UnityEngine.XR.Interaction.Toolkit

public class InteractionController : MonoBehavior
{
  [SerializeField]
  private ActionBasedController controller;
}
```

#### Tips: Hämta referensen automatiskt

Genom att lägga scriptet på den VR-handkontroll vars inputs ska läsas av kan man slippa manuellt ange vilken komponent som ska läsas i Unity, och istället göra det enkelt med kod:

```csharp
using UnityEngine.XR.Interaction.Toolkit

public class InteractionController : MonoBehavior
{
  private ActionBasedController controller;
  
  private void Awake()
  {
    controller = GetComponent<ActionBasedController>();
  }
}
```

### Actions

ActionBasedControllern ger tillgång till de **actions** som en VR-handkontroll normalt avfyrar. Lägg till egna metoder till dessa actions för att köra egen kod som reaktion på dem.

För att det ska fungera måste metoderna ta emot en parameter med datatypen InputAction.CallbackContext, som finns i UnityEngine.InputSystem-biblioteket.

Kolla listan under **Action Based Controller (XR)**-komponenten i Unitys Inspector för att se vilka actions som finns.

```csharp
using UnityEngine.InputSystem;

// --- //

  private void Awake()
  {
    // --- //
    
    controller.activateAction.action.started += OnTriggerPress;
  }
  
  void OnTriggerPress(InputAction.CallbackContext context)
  {
    print("Trigger pressed");
  }
```

#### Värden

Många actions har tillhörande **värden** – till exempel kan man läsa av hur mycket avtryckaren är nedtryckt eller exakt var handkontrollen är just nu.

```csharp
  void OnTriggerPress(InputAction.CallbackContext context)
  {
    print("Trigger pressed");
    
    // Läser värdet från kontexten - dvs en trigger-tryckning
    float triggerValue = context.action.ReadValue<float>()
    
    // Läser ett värde direkt från controllern
    Vector3 controllerPosition = controller.positionAction.action.ReadValue<Vector3>();    

  }
```


# Interaktion\*

I VR-sammanhang är "interaktion" specifikt när VR-utrustningen interagerar med den virtuella miljön. Till exempel är en VR-handkontroll används för att plocka upp något eller trycka på en knapp.

(Om man vill köra kod själv när spelaren trycker på en knapp – se [controllers](/tillaeggspaket/xr-toolkit/controllers))

## XR Interaction Manager

Om du tänkt ha någon form av interaktion i din scen så behöver också något objekt ha en **XR Interaction Manager**-komponent. Lägg till den i XR Origin eller skapa ett helt nytt objekt som bara innehåller komponenten genom att högerklicka i Hierarchy och välja XR och Interaction Manager.

## Interactors och interactibles

Interaktion i XR Toolkit sker mellan **interactors** och **interactibles**.

Objekt som har en interactible-komponent kan man göra något med – plocka upp, kasta, trycka på, dra i, öppna.

Objekt som har en interactor-komponent kan sedan påverka dessa interactible-objekt.

*Exempel: Man vill kunna trycka på en knapp med sin VR-handkontroll. Knappen behöver då en interactible-komponent och VR-handkontrollen behöver en interactor-komponent.*

### Interaction layer mask

Oavsett om det gäller ray interaction eller direct interaction kan **interaction layers** användas för att bestämma vilka objekt som ska kunna interageras med. Interaction layers fungrar ungefär som vanliga [lager](/grundlaggande-koncept/lager-och-taggar).&#x20;

Både XR Ray Interactor och XR Direct Interactor-komponenterna har en **Layer Interaction Mask**-variabel.

![](/files/dkRmHTinHWYKHu5ekslo)

Precis som med vanliga lager används Add Layer för att skapa nya lager. Se till så att bara de lager just denna interactor ska kunna interagera med är förkryssade. Detta blir extra viktigt om du vill ha olika sorters interactors för [teleportation ](/tillaeggspaket/xr-toolkit/teleportation)och att plocka upp föremål. Om du använder prefab-versionen av XR-riggen så utgår den från att lager 31 är "teleportationslagret".

## Interactors\*

Det finns tre huvudsakliga interactors:

* **XR Ray Interactor** – En stråle som normalt utgår från VR-handkontrollen och gör att man kan interagera med det strålen träffar.
* **XR Direct Interactor** – Använder en collider och gör att man kan interagera med det collidern rör vid.
* **XR Poke Interactor** – Gör att man kan interagera med objekt, och med UI-element, genom att "peta" på dem.

Man kan bara ha en av dem på varje XR-controller, så om man vill använda flera – se [teleportation](/tillaeggspaket/xr-toolkit/teleportation) till exempel – får man hitta en workaround av något slag. Oftast sker det genom att man har flera under-objekt som var och ett har en egen interactor. Så är det t.ex. löst i **XR Origin (XR Rig)**-prefaben.

Objekten som motsvarar dina VR-handkontroller finns i din XR Origin, under Camera Offset.

![](/files/lwh6Pd8wtQH1dZVhlq9C)

### Ray interaction

Vid ray interaction så skjuter långa "strålar" ut från VR-handkontrollerna och föremål som träffas av strålarna kan handkontrollerna interagera med. Till exempel kan man då plocka upp föremål på distans genom att sikta på dem med strålarna och trycka på en knapp på controllern.

Som minst behöver VR-handkontrolls-objektet som ska använda ray interaction en **XR Ray Interactor**-komponent. Normalt lägger man också till en **XR Interactor Line Visual**-komponent som för att strålen som skjuter ut syns. Då läggs också en Line Renderer-komponent till automatiskt.

När XR Origin-objektet skapas så ges båda VR-handkontrollerna de komponenter som behövs för ray interaction.

### Direct interaction

Vid direct interaction måste VR-handkontrollen (eller den collider som är på samma objekt som Direct Interactor-scriptet) fysiskt röra vid målobjektet för att interaktion ska kunna se. Då kan man inte interagera med saker på distans utan måste vara nära dem.

Lägg till en **XR Direct Interactor**-komponent till det VR-handkontroll-objektet som ska använda direct interaction. Lägg också till en Sphere Collider (Trigger); den kommer att användas för att känna av kollisionen mellan interactorn och objekten.

### Poke interaction\*

## Interactors och kod

För att komma åt XR Toolkits klasser etc, lägg till detta bland dina using statements:

```csharp
using UnityEngine.XR.Interaction.Toolkit;
```

### Komponentdatatyper

Basklassen för alla interactors är **XRBaseInteractor**. De andra heter liknande saker – **XRDirectInteractor**, **XRRayInteractor** och **XRPokeInteractor**.

```csharp
XRBaseInteractor interactor = GetComponentInChildren<XRRayInteractor>();
```

### interactablesHovered

En lista med de "hoverable" interactables som interactorn just nu hovrar över. Normalt brukar den listan bara innehålla noll eller en saker, men använd en foreach för säkerhets skull! Datatypen för de saker den innehåller är [interfacet ](https://csharp.progdocs.se/klasser-och-objektorientering/interface)IXRHoverInteractable.

```csharp
foreach (IXRHoverInteractable interactable in interactor.interactablesHovered)
{
  // skriver ut namnet på objektet som hovras över
  Debug.Log(interactable.transform.name);
}
```

## Interactables – föremål som kan interageras med

För att göra så att ett objekt kan interageras med, behöver det en Interactable-komponent. Det finns flera olika.

<table><thead><tr><th width="194">Komponent</th><th>Beskrivning</th></tr></thead><tbody><tr><td>XR Grab Interactable</td><td>Objekt som kan plockas upp genom att man trycker på Grab-knappen</td></tr><tr><td>XR Simple Interactable</td><td>Enklast möjliga: objektet kan interageras med men saknar inbyggd funktionalitet.</td></tr><tr><td>XR Socket Interactable</td><td>Objekt som andra objekt kan sättas fast på. En mer detaljerad genomgång finns t.ex. <a href="https://www.youtube.com/watch?v=rRNvq09Itdw">här</a>.</td></tr></tbody></table>

Objektet behöver också en collider av något slag, och antagligen en RigidBody. Fysik-systemet används för att avgöra om objektet kolliderar med en VR-handkontroll eller med en stråle från ray interaction.

### Reagera visuellt

En **XR Tint Interactable Visual**-komponent gör att objektet får en tydlig visuell indikation på att det är det nuvarande målet för interaktionen.

### Reagera med kod via Events

Objekt som har någon form av Interactable-komponent kommer att ha ett antal Interactable Events som kan knytas till specifika metoder i kod – precis som events i [det vanliga UI-systemet](/grundfunktioner/ui-och-canvas#events).

I listan är det mesta ganska självförklarande, men det finns tre viktiga begrepp:

* **Hover** betyder att spelaren markerat objektet med en stråle (ray interactor) eller en VR-handkontroll (direct interactor).
* **Select** betyder att spelaren tryckt på **grepp-knappen** på sin VR-handkontroll. Man kan ändra vilken knapp som gör "select" om man vill.
* **Activate** betyder att spelaren tryckt på **trigger-knappen** på sin VR-handkontroll. Man kan ändra vilken knapp som gör "activate" om man vill. OBS: För att Activate ska ske måste Grab ha skett först.

I exemplet nedan aktiveras metoden **DoSomething** i **CapsuleController**-scriptet som finns i objektet **Capsule** när spelaren **markerat** objektet med antingen sin stråle (ray interactor) eller sin VR-handkontroll (direct interactor)

![](/files/YcSSJa3IHpXegnJmsvG9)

### Reagera med kod – bara kod

I scripts som ligger på det interagerbara objektet kan man skriva kod för att lägga till metoder direkt – utan att gå via den visuella Events-listan. Man gör då detta genom att använda AddListener-metoden på Interactable-komponenten.

Exemplet nedan gäller XR Grab Interactables, men motsvarande gäller också övriga.

{% code title="CubeController.cs" %}

```csharp
using UnityEngine.XR;
using UnityEngine.XR.Interaction.Toolkit;

public class CubeController : MonoBehaviour
{
  XRBaseInteractable interactable;

  void Awake()
  {
    interactable = GetComponent<XRGrabInteractable>();
    interactable.activated.AddListener(ActivateEvent);
  }

  void ActivateEvent(ActivateEventArgs args)
  {
    // Det som ska hända
  }
}
```

{% endcode %}

## Exempel: Köra kod på objekt man pekar på, när man trycker på avtryckaren

Om man vill att något ska hända direkt när spelaren pekar sin controller, med [ray interactor](/tillaeggspaket/xr-toolkit/interaktion#ray-interaction), mot ett föremål och trycker på avtryckaren så kan man kombinera tekniker så här:

{% code title="EnemyController" %}

```csharp
public class EnemyController : MonoBehaviour
{
  public void Damage()
  {
    Debug.Log("Damaged!");
  }
}
```

{% endcode %}

EnemyController läggs på objektet som ska kunna påverkas – skadas, i det här fallet.

GunController, nedan, läggs på Left Controller och Right Controller.

Det GunController gör är att först hitta referenser till ActionBasedController (som sköter input-delen) och XRRayInteractor (som sköter kollen av vilka objekt man pekar på).

När spelaren sedan trycker på Activate-knappen (avtryckaren) så körs metoden Fire, som går igenom alla objekt som XRRayInteractorn känner av, och ifall de har en EnemyController-komponent så körs dess Damage-metod.

{% code title="GunController.cs" %}

```csharp
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.XR.Interaction.Toolkit;

public class GunController : MonoBehaviour
{
  ActionBasedController controller;
  XRBaseInteractor interactor;

  void Awake()
  {
    controller = GetComponent<ActionBasedController>();
    interactor = GetComponentInChildren<XRRayInteractor>();

    controller.activateAction.action.started += Fire;
  }

  void Fire(InputAction.CallbackContext ctx)
  {
    foreach (IXRHoverInteractable interactable in interactor.interactablesHovered)
    {
      if (interactable.transform.TryGetComponent<EnemyController>(out EnemyController controller))
      {
        controller.Damage();
      }
    }
  }
}
```

{% endcode %}


# Device Simulator

När man inte har tillgång till ett VR-headset medan man arbetar med ett VR-projekt behövs något sätt att åtminstone göra enkel testning. Den lösning som just nu finns till Unitys XR Interaction Toolkit heter XR Device Simulator. Den är inte perfekt, men den medger enklare testning.

## Setup

1. Om du inte gjort det redan, gå till [Package Manager](/andra-funktioner/package-manager) och **XR Interaction Toolkit**-paketet. Klicka in under Samples och importera **XR Device Simulator**.
2. Gå till din Assets och till mappen Samples > XR Interaction Toolkit > 2.0.1 > XR Device Simulator. Dra in **XR Device Simulator**-prefaben till din scen.
3. **ELLER:** Gå till Edit → Project Settings och XR Interaction Toolkit. Kryssa i "Use XR Device Simulator in Scenes".

### I Unity 2021.3, med InputSystem 1.4.0+

Det finns en bug som gör att WASD-styrning av simulatorn inte fungerar. Som en workaround, lägg följande script på ett GameObject någonstans i scenen.

{% code title="ShortcutDisabler.cs" lineNumbers="true" %}

```csharp
using UnityEngine;
using UnityEngine.InputSystem;

[DefaultExecutionOrder(-30000)]
public class ShortcutDisabler : MonoBehaviour
{
  private void Awake() {
    InputSystem.settings.SetInternalFeatureFlag("DISABLE_SHORTCUT_SUPPORT", true);
  }
}
```

{% endcode %}

## Kontroller

Styr det simulerade VR-headsetet med vanliga WASD-kontroller och mouselook (inklusive E och Q för att åka uppåt/nedåt). Håll nere **vänster shift** för att styra vänster handkontroll och **mellanslag** för att styra den högra. Vänster musknapp simulerar avtryckaren och G-knappen simulerar greppknappen.

<table><thead><tr><th width="268.7124701157594">Välja enhet att styra</th><th width="150">Toggle</th><th>Simulator</th></tr></thead><tbody><tr><td>Hålla nere vänster shift</td><td></td><td>Vänster VR-handkontroll (tillfälligt)</td></tr><tr><td>Hålla nere mellanslag</td><td></td><td>Höger VR-handkontroll (tillfälligt)</td></tr><tr><td>T</td><td>Ja</td><td>Vänster VR-handkontroll</td></tr><tr><td>Y</td><td>Ja</td><td>Höger VR-handkontroll</td></tr></tbody></table>

<table><thead><tr><th width="267.4204400031097">Styrning/rotation</th><th width="154.933434630245">Toggle</th><th>Simulator</th></tr></thead><tbody><tr><td>WASD</td><td></td><td>Flytta headset framåt / bakåt / vänster / höger</td></tr><tr><td>Flytta musen</td><td></td><td>Lookaround</td></tr><tr><td>Scrollhjulet</td><td></td><td>Rotera enhet</td></tr><tr><td>Mittenknappen</td><td></td><td>Flytta vald handkontroll</td></tr></tbody></table>

| Knappar          | Simulator                                           |
| ---------------- | --------------------------------------------------- |
| Vänster musknapp | Trigger                                             |
| G                | Grip                                                |
| B                | Primary button (Oculus: X/A)                        |
| N                | Secondary button (Oculus: Y/B)                      |
| M                | Menu button (Oculus: Start)                         |
| 4                | Primary 2D axis click (Oculus: Klicka analogspak)   |
| 6                | Primary 2D axis touch (Oculus: röra vid analogspak) |
| 8                | Primary button touch (Oculus: röra vid X/A)         |
| 9                | Secondary button touch (Oculus: röra vid Y/B)       |
|                  |                                                     |


# Teleportation

## Enkel setup

Det behöver finnas en **Locomotion System**-komponent och en **Teleportation Provider**-komponent någonstans i scenen. Enklast är att bara lägga till dem i XR Origin-objektet.

Så länge VR-handkontrollerna har [Ray Interactors](/tillaeggspaket/xr-toolkit/interaktion#ray-interaction) är detta den enda setup som behövs.

* Videotips: <https://www.youtube.com/watch?v=eI1cgiz2JSw>

## Giltiga mål för teleportationen

Det finns två sorters objekt som kan teleporteras till: Area och Anchor. I båda fallen genomförs teleportationen genom att spelaren markerar målobjektet och trycker på en knapp för att genomföra teleportationen.

Objekt med en **Teleport Area**-komponent låter spelaren teleporteras till den exakta punkt på objektet som hen pekade på. Oftast är detta ett objekt med ett Plane-mesh.

Objekt med en **Teleport Anchor**-komponent låter spelaren teleporteras till objektet mittpunkt.

De har ett antal viktiga inställningar gemensamma:

* **Interaction Layer Mask:** För att skilja teleportation från andra typer av interaktion kan det vara praktiskt att ge teleportations-mål ett eget Interaction Layer och se till så att de enbart finns på detta lager. **Om du använder den färdiga prefaben för din XR Rig så utgår dess XR controllers från att lager 31 är teleportationslagret.**
* **Custom Reticle:** Ett objekt som skapas när spelaren markerar objektet och placeras där hen planeras dyka upp efter teleportationen.
* **Teleportation Configuration** är en liten undermeny – den viktigaste här är nog Teleport Trigger, som är den händelse som får teleportationen att utföras. Här kan man bara välja mellan Select (greppknapp) och Activate (avtryckare).


# Meta Quest 2/3

Material:

* Dator med Unity
  * För att testköra via kabel: c:a 4gb för att installera Oculus-appen
  * För att kompilera och installera i headset: c:a 2–3 gb för att installera Android-utvecklingsverktygen
* Meta Quest 2/3
* USB-C-kabel

## Testköra på Meta Quest med kabel

Oculus Link kan användas för att testköra VR-grejer direkt i headsetet utan att de behöver exporteras eller installeras. Link kan köras både trådat (med USB 3-kabel) och trådlöst (vilket kräver bra nätverk).

### Förberedelser

* Ladda ner och installera [Meta Quest Link](https://www.oculus.com/download_app/?id=1582076955407037)-appen. (kräver c:a 400mb)
  * Starta appen, gå igenom dess start-procedur.
  * Inklusive att skapa eller logga in på ett Meta-konto.
* Unity
  * Se till så att du lagt till XR Plugin Management-paketet i [Package Manager](/andra-funktioner/package-manager).
  * I Project Settings, gå till XR Plugin Management, kryssa i Oculus under PC-fliken.

### Kör

* Skapa ett VR-projekt.
* Ta bort XR Device Simulator ur scenen, eller stäng av den tillfälligt.
* Koppla in headsetet med USB-kabel.&#x20;
  * Du får nu troligen frågan om du vill aktivera Oculus Link. Svara ja.
  * Om du inte får frågan, gå in i Oculus' snabbmeny (klicka där klockan och ikoner för nätverk etc är) och välj Oculus Link
* Gå till Unity, testkör spelet med playknapen som vanligt.

## Bygga/exportera till Oculus Quest

### Förberedelser

{% hint style="danger" %}
**VIKTIGT:** Om scenen innehåller en [Device Simulator](/tillaeggspaket/xr-toolkit/device-simulator) – ta bort den eller deaktivera den! Om den är aktiv i scenen kommer ingenting att fungera när projektet körs i Oculusen.
{% endhint %}

#### Oculus Quest 2

* Starta headsetet.
* Gå till Settings->System->Developer. Aktivera USB Debugging.
* Koppla in headsetet via USB. Du bör få en dialogruta i headsetet som ber dig bekräfta att du vill ansluta via USB. Klicka "Allow".

#### Unity build tools

{% hint style="danger" %}
**VIKTIGT:** Använd **Unity 2022** (eller senare) för detta!
{% endhint %}

Starta Unity Hub och gå till **Installs**.

Klicka på kugghjulet bredvid din Unity-installation och välj **Add modules**.

Kryssa i **Android Build Support**, och både **Android SDK & NDK Tools** samt **OpenJDK**. Tryck Continue och vänta tills modulerna laddats ner och installerats. Det här behöver du bara göra en gång – Android-utvecklingsverktygen installeras på datorn, inte i något specifikt projekt.

![](/files/SrvHzty0a1MIvpaxZNsb)

Öppna ett projekt och gå till Edit -> Preferences och klicka på External Tools. Dubbelkolla så att alla rutor under Android är ifyllda och att Unity därmed hittat alla verktyg.

#### Unity build settings

Gå till File -> Build Settings. Välj Android som Platform. Glöm inte att trycka på Switch Platform.

Välj Quest 2-headsetet som "Run device". Om du inte ser headsetet i listan – testa koppla ur det och sedan koppla i det igen, och se till så att det är påslagen och att det inte visar någon dialogruta som väntar på input. Tryck "Refresh".

### Unity project settings

Se till så att du lagt till XR Plugin Management-paketet i [Package Manager](/andra-funktioner/package-manager).

Gå till Edit -> Project Settings. Klicka på **XR Plugin Management**. Klicka på Android-fliken (den till höger) och kryssa i Oculus.

![](/files/8FNPjoSDeM0MkQAV9QlW)

Gå till **Player**, även här Android-fliken, och gå ner till och expandera rubriken **Other Settings**.

![](/files/mp8Ytn7Wnr0pN3qIgFh3)

Gå ner till underrubriken **Identification** och dubbelkolla så att **Minimum API Level** är API Level 23 (Android 6.0).

![](/files/7f45TMhVWlkGpTNKkeab)

Nu är projektet redo att deployas och köras på en Quest 2.

## Build and run

Gå till File -> Build settings och dubbelkolla så att Quest 2-headsetet är valt som Run Device.

Tryck på "Build And Run".

Välj en mapp att lägga den kompilerade versionen av projektet i. Skapa gärna en ny mapp; lägg den inte direkt i projektmappen.

Den kompilerade versionen av projektet kommer att vara en APK-fil, vilket är Androids standardformat för program som kan installeras. Unity använder sedan automatiskt Android-utvecklingsverktygen för att föra över APK-filen till headsetet och installera den. Därefter körs den också automatiskt.

Därefter finns programmet installerat under "Unknown sources" i Questens app-meny.


# 3D-modeller\*

* Controllers/händer
* Teleportation
  * Anchor reticle
  * Area reticle


# MRTK3 (HoloLens 2)

## Färdigt grundprojekt

Här finns färdiga projekt att utgå från, med all setup redan fixad. Välj projektet som matchar din Unity- och Hololensversion:

**Hololens 2:**

* [MRTK3\_BASE\_HL2\_2021](https://github.com/mikael-bergstrom-ntisthlm/MRTK3_BASE_HL2_2021) (MRTK 3, Unity 2021.3.26)

## Manuell setup

Skapa ett nytt 3D-projekt i Unity.

{% hint style="warning" %}
**OBS:** det finns en bugg i Unity 2020.3.32 som krånglar till det med MRTK och Hololens2. Använd en tidigare eller senare version.
{% endhint %}

Ladda ner och packa upp [Mixed Reality Feature Tool](https://aka.ms/MRFeatureTool).

Kör filen **MixedRealityFeatureTool.exe** för att starta verktyget. Tryck på **Start** och välj mappen ditt Unityprojekt ligger i. Klicka på **Discover Features**.

Kryssa i följande:

* Platform Support
  * Mixed Reality OpenXR Plugin
* Spatial Audio
  * Microsoft Spatializer
* MRTK3
  * MRTK Input
  * MRTK UX Components
  * MRTK Windows Speech

Gå till Unity, och vänta på att de nya paketen ska laddas in. Unity kommer att fråga om editorn ska startas om och det nya input-systemet aktiveras. Tryck **Yes**.

![](/files/g5JWUsfkYEmKwQV4Xguq)

Unity kommer att fråga ifall du vill uppdatera dina XR InteractionLayer Masks. Välj **No thanks**.

<figure><img src="/files/DIjFEQaxSk4DgAFU6Xzm" alt=""><figcaption></figcaption></figure>

### Gitignore

Lägg till följande två rader till din gitignore:

```gitignore
# Hololens WSA test certificate
/[Aa]ssets/WSATestCertificate.pfx
```

WSATestCertificate.pfx är en fil som skapas i samband med att man testar projektet mot en riktig Hololens, men bör inte laddas upp till t.ex. Github.

### Project settings

Gå till Project settings.

Under **MRTK3**, klicka på **Assign MRTK Default.**

<figure><img src="/files/LQHHeqG2g99H72YLzmDN" alt=""><figcaption></figcaption></figure>

Under **XR Plug-in Management** finns flikar för olika plattformar. Under fliken för "Windows, Mac, Linux settings", kryssa i:

* Initialize XR on Startup
* OpenXR
* Windows Mixed Reality feature group

Under fliken för "Universal Windows Platform settings" (om du har den), kryssa i:

* OpenXR
* Microsoft HoloLens feature group

Under **Project Validation**, klicka "Fix all" under både "Windows, Mac, Linux settings" och "Universal Windows Platform settings" (om du har den).

Under **OpenXR**, under "Enabled Interaction Profiles", lägg till "Eye Gaze Interaction Profile", "Microsoft Hand Interaction Profile" och "Microsoft Motion Controller Profile".

<figure><img src="/files/qA4EcKf8OfsEsEBhnl9F" alt=""><figcaption></figcaption></figure>

### Scen-setup

Sök i Assets efter prefaben **MRTK XR Rig**. Om du inte hittar den, se till så att din sökning är i **Packages**, inte i Assets. Lägg till en instans av den i scenen.

<figure><img src="/files/e73jIHiFsR96X3FkjbOz" alt=""><figcaption></figcaption></figure>

Sök också efter **MRTKInputSimulator**. Lägg till en instans av den också.

## Länkar

* <https://docs.microsoft.com/en-us/learn/paths/beginner-hololens-2-tutorials/>

### MRTK2 (gamla)

* <https://docs.microsoft.com/en-us/windows/mixed-reality/mrtk-unity/>
* [https://docs.microsoft.com/en-us/windows/mixed-reality/develop/unity/spatial-mapping-in-unity](https://docs.microsoft.com/en-us/windows/mixed-reality/develop/unity/spatial-mapping-in-unity?tabs=mrtk)
* <https://docs.microsoft.com/en-us/windows/mixed-reality/design/scene-understanding>


# Grundkoncept\*

* Fokus
* Gester
  * Luftklick/tap
  * Hold
  * Navigation
  * Manipulation
* Gaze


# Simulering

För utveckling utan HoloLens är det praktiskt med Unitys inbyggda HoloLens-simulering.

Den är automatiskt tillgänglig i scener som förberetts för HoloLens-utveckling. Den aktiveras tillsammans med Play mode.

![](/files/HPXqtmsepC4KcCbForwc)

## Huvudet

För att styra huvudet/kameran:

* WASD för att gå framåt/bakåt/åt sidorna
* Höger musknapp: Mouselook

## Händer

För att styra händerna:

* Vänster Shift: aktivera vänsterhand
* Mellanslag: aktivera högerhand
* Vänsterklick: Knip/klicka


# Interaktion\*

## Object Manipulator

Ett objekt som ges en **Object Manipulator**-komponent kan flyttas runt av användaren, som bara behöver peka på den med en av sina pekare (strecken som skjuter ut från händerna) och använda Select-gesten (knipa ihop tumme och pekfinger) för att påbörja interaktionen.

Objekt med en Object Manipulator-komponent får också automatiskt en Constraint Manager-komponent.

I Object Manipulator-komponenten finns inställningar för en- och tvåhandsmanipulation och till exempel smoothing (som får objektet att röra sig mjukt när det manipuleras).

För att skapa ett objekt som bara kan interageras med på nära håll – ändra i listan **Allowed Interaction Types**.

Det finns också **Unity Events** för när manipulationen börjar och slutar (On Manipulation Started/Ended) samt för när spelaren börjar/slutar markera objektet med sin pekare (On Hover Started/Exited).

### ~~Near Interaction Grabbable~~

~~Ett manipulerbart objekt som ges en Near Interaction Grabbable-komponent kan inte manipuleras på avstånd, utan användaren måste gå nära objektet och röra vid det med sina händer.~~

## Stateful Interactable

Komponent som ger ett objekt enkel interagerbarhet.

* **Selection mode** \[Button|Toggle|One-way toggle] avgör hur objektet ska fungera.
  * Button: En vanlig knapp. man klickar, något händer.
  * Toggle: En av/på-knapp som minns vilket "läge" den är i.
  * One-way toggle: Som toggle, men bara åt ett håll.

Listan "On Clicked" är händelser som sker (metoder som körs) när man klickar på knappen. "On Toggled" och "On Untoggled" dyker upp om man väljer att det ska vara en toggle-knapp, och gör så att olika metoder kan köras när man klickar, när den hamnar i "på"-läge och när den hamnar i "av"-läge.

## ~~Interactable~~

~~Objekt som inte ska kunna manipuleras utan bara reagera med kod på att vidröras, klickas på etc kan ges en **Interactable**-komponent.~~

~~**Input Actions** är vilken action komponenten ska reagera på.~~

~~**Voice Command** är vilket, om något,~~ [~~röstkommando~~ ](/tillaeggspaket/mrtk-hololens/roststyrning)~~den ska reagera på.~~

~~Under **Events** finns sedan framför allt **OnClick**, som är ett helt vanligt~~ [~~Unity Event~~](/grundfunktioner/unity-events) ~~som kan kopplas till ett eller flera scripts och metoder.~~

~~Under **Receivers** går det att lägga till fler sorters events som interactable-objektet ska ta emot. Till exempel kan en InteractableOnFocusReceiver göra det möjligt att koppla script och metoder till när användaren markerar eller tittar på ett objekt.~~


# Röststyrning

## Manuella projektinställningar

Kolla under Window → Package Manager så att paketet **MRTK Windows Speech** finns i projektet. Använd annars **Mixed Reality Feature Tool** för att lägga till det.

Gå till **Project Settings**.

Under **MRTK3**, se till så **MRTK Windows KeywordRecognition Subsystem** är ikryssat.

Under **Player**, gå till **Universal Windows Platform settings** och scrolla ner till **Publishing Settings**. Se till så att **Microphone** är ikryssad under Capabilities.

## Känna igen ett kommando

Många av MRTKs knappar och interaktionsobjekt har inbyggda stöd för att markera dem eller aktivera dem med rösten. Med nedanstående går det dock att lägga in egna kommandon.

### XRSubsystemHelpers.GetFirstRunningSubsystem<>()

Returnerar första bästa aktiva subsystem av angiven typ.

```csharp
// Hämtar första bästa KeywordRecognitionSubsystem
KeywordRecognitionSubsystem keywordSystem = XRSubsystemHelpers.GetFirstRunningSubsystem<KeywordRecognitionSubsystem>();
```

### CreateOrGetEventForKeyword()

Metod inuti KeywordRecognitionSubsystems som skapar ett nytt [unity event](/grundfunktioner/unity-events) knutet till ett visst keyword om det inte redan finns en, eller hämtar en referens till det existerande om det redan finns.

```csharp
UnityEvent event = keywordRecognitionSubsystem.CreateOrGetEventForKeyword("cowabunga");
```

### Komplett exempel

```csharp
// Hämta första bästa "keyword recognition subsystem"
KeywordRecognitionSubsystem keywordRecognitionSubsystem = XRSubsystemHelpers.GetFirstRunningSubsystem<KeywordRecognitionSubsystem>();

// Om ett sådant system hittas...
if (keywordRecognitionSubsystem != null)
{
    // Använd systemet för att koppla samman ett kommando med en listener (en metod eller ett Lambda-uttryck)
    keywordRecognitionSubsystem.CreateOrGetEventForKeyword("your keyword").AddListener(() => Debug.Log("Keyword recognized"));
}
```


# UI/UX och Canvas\*

* TMPro Import Essentials
* UI→MRTK→Canvas


# Spatial awareness\*

* MRTK XR Rig -> Camera Offset
  * Skapa objekt med "ARMeshManager"-komponent
  * Skapa en prefab med ett MeshFilter och rätt material
    * OBS: Ta bort specifika mesh:et i MeshFilter-delen! Annars kommer det att *redigeras permanent*.
    * MeshCollider
* Simulering (Inte fått detta att funka ännu)
  * Edit->Project Settings
    * XR Plug-in Management->Windows, Mac & Linux
      * Kryssa i XR Simulation
  * Window->XR->AR Foundation->XR Environment
    * Install sample environments
    * Import sample environments

{% embed url="<https://localjoost.github.io/Using-ARMeshManager-for-Spatial-Awareness-with-MRTK3-on-HoloLens-2/>" %}

{% embed url="<https://localjoost.github.io/MRTK3-StatefulInteractable-gaze,-hover-and-select-events-and-how-to-use-them/>" %}

OLD MRTK2:

* MixedRealityToolkit
  * Spatial Awareness
    * Enable Spatial Awareness System (kräver egen övergripande Configuration Profile)
    * Observers
      * Alla ändringar kräver egen MixedRealitySpatialAwarenessSystemProfile
      * För simulering
        * Lägg till
        * Type: Microsoft.MixedReality.Toolkit.SpatialObjectMeshObserver → SpatialObjectMeshObserver
      * Alla ändringar i enskilda observers kräver egna Profiles för varje.
        * Display Settings – Visible / Occlusion
      * Ändra saker i Observers
        * using Microsoft.MixedReality.Toolkit;
        * using Microsoft.MixedReality.Toolkit.SpatialAwareness;&#x20;
        * using Microsoft.MixedReality.Toolkit.SpatialObjectMeshObserver;
        * var observers = (CoreServices.SpatialAwarenessSystem as IMixedRealityDataProviderAccess).GetDataProviders();


# Deployment\*

## Deployment till riktig hårdvara eller emulator

För att kunna kompilera och föra över projekt till en HoloLens 2 eller emulatorn, behövs Visual Studio 2019 eller 2022. De tar en hel del utrymme: räkna med **mellan 18.5 och 20.5 gb**!

* Behövs: C++ Desktop och UWP
* Obs: ta med C++ v143 i UWP-paketet.

Dessutom behövs **Universal Windows Platform support** i Unity – **ytterligare c:a 2 gb**.

Windows måste också vara inställt till Developer Mode (Settings→System→For Developers)

### Unity

* Mixed Reality → Project Validation Settings → Hololens 2 Application (UWP)
* Project Validation (XR Plug-in Management)
  * "Fix all"
  * "At least one interaction prodile must be added"
    * Player Settings -> OpenXR -> UWP -> Interaction Profiles -> Microsoft Hand Interaction Profile
  * "The speech interactor needs to be active and enabled"
    * Aktivera MRTK Speech-komponenten i MRTK-riggen
  * "For controller models to show up…"
    * Ignorera, eller lägg till com.unity.cloud.gltfast via Package Manager
* Build -> till egen mapp (skapa en!)

### Visual Studio

* När processen är klar: Gå till mappen, öppna SLN-filen
* (Om det inte redan är fetmarkerat: Universal Windows-projektet -> Högerklick, Set as Startup Project)
* Release, ARM64, Remote machine
* Project -> Properties -> Debugging -> Machine Name (IP)
  * (Om Hololensen är på och på samma nätverk bör man kunna anvönda Locate istf att skriva in IP-numret)
* Build -> Deploy Solution
* \~2–6min för att kompilera (Snabbare efter första gången)
* PIN
* \~3-5min för att överföra

<https://docs.microsoft.com/en-us/windows/mixed-reality/develop/unity/build-and-deploy-to-hololens>

<https://docs.microsoft.com/en-us/windows/mixed-reality/develop/advanced-concepts/using-visual-studio?tabs=hl2>

### Hololens 2-emulator

Har man inte en riktig HoloLens 2 men vill pröva mer "på riktigt" än i Unitys simulering, finns [Hololens 2-emulatorn](https://docs.microsoft.com/en-us/windows/mixed-reality/develop/advanced-concepts/using-the-hololens-emulator). Den kräver **c:a 12 gb** ledigt utrymme. Observera att Hyper-V måste vara aktiverat i Windows för att den ska fungera.


# MRTK2 (Hololens 1)

Unity

* UWP, IL2CPP

Mixed Reality Feature Tool

## System-setup

* Visual Studio
  * Desktop development with C++
* Windows 10 SDK: <https://developer.microsoft.com/en-us/windows/downloads/windows-sdk/>

## Projekt-setup

*

## Scen-setup

* Mixed Reality -> Toolkit -> Add to Scene and Configure

## Interagerbara objekt

* Object manipulator
* Interactable
* NearInteractionGrabbable

## Deployment

* Unity
  * Platform UWP
  * Target Device Hololens
  * Architecture x86
* Visual Studio
  * Release, x86
  * Remote Machine


# ProBuilder

ProBuilder gör att man kan bygga enkel 3D-geometri snabbt direkt i Unity-editorn istället för att bygga saker i ett 3D-program som Blender och sedan importera därifrån.

## Komma igång

* **Installera:** Använd [Package Manager](/andra-funktioner/package-manager) för att lägga till **ProBuilder** från Unity Registry.
* **Skapa nytt ProBuilder-objekt:**

  * Högerklicka i Hierarchy-fönstret och välj ProBuilder och den typ av objekt du vill ha
  * Använd Create Object-menyn

  <figure><img src="/files/fWDbipY5KcgsHHdEfKhH" alt=""><figcaption></figcaption></figure>
* **Redigera:** Byt till ProBuilder-läget i editorn

<figure><img src="/files/2bTDUCuoQsxVJqAa31QY" alt=""><figcaption></figcaption></figure>

## Grundläggande redigering

ProBuilder har fyra grundläggande redigeringslägen – object, vertex, edge och face.

![](/files/Ce7VcsvTFkrbsGgJxUNZ)

Beroende på vilket läge man är i, så är det olika saker som markeras när man klickar på dem och som sedan kan flyttas, roteras och skalas.

* **Object:** Hela objektet.
* **Face:** En "sida" av objektet.
* **Edge:** En "kant" av objektet.
* **Vertex:** En av objektets "punkter".

Grundtanken här är alltså att ett objekt egentligen består av ett antal punkter i 3d-rymden. Punkterna är ihopkopplade med linjer – "kanter" – och mellan linjerna uppstår ytor – "sidor".

### Extrude/inset

Håll nere Shift när du flyttar eller ändrar storlek på en face.

### Actions

Genom att *högerklicka* när du har något markerat får du se vilka actions som finns tillgängliga för den markeringen – till exempel **bevel**.

## Export

I menyn Tools→ProBuilder→Export finns lite olika sätt att spara geometrin man skapat i ett format som 3d-program som t.ex. Blender kan läsa. Därmed kan man börja med att skapa en enkel version av en level i Unity, och sedan skapa snyggare och mer detaljerad eller stiliserad grafik till den i ett 3d-program med Unitys grundgeometri som bas.


# Påverka andra objekt\*

Om ett komponentscript på ett objekt ska kunna påverka (flytta, ta bort, etc) ett annat objekt så måste det ha en *referens* till det objektet.

**Om båda objekten finns redan från början** kan man använda en enkel variabel:

```csharp
[SerializeField]
GameObject otherObject;
```

Sedan bestäms vilket objekt variabeln ska peka på genom att man gör kopplingen i Unity-editorn.

(Bild: Inspectorn, otherObject)

**Om objektet behöver hittas i realtid** finns ett par olika sätt att skapa referensen. Ett är att gå via kollisioner:

```csharp
void OnCollisionEnter(Collision collision)
{
  GameObject otherObject = collision.gameObject
}
```

Ett mycket ineffektivt sätt att göra det på är via [Find ](/grundfunktioner/hitta-spelobjekt)– det bör man bara göra i undantagsfall och absolut inte varje bildruta.

## Komponenter

När man väl har en referens till ett annat GameObject kan man dels påverka det direkt, dels komma åt dess komponenter via [GetComponent ](/grundlaggande-koncept/komponenter#getcomponent-less-than-greater-than)och påverka dem. Det gäller även andra script-komponenter.

```csharp
void OnCollisionEnter(Collision collision)
{
  HealthScript enemyHealth = collision.gameObject.GetComponent<HealthScript>();
  
  enemyHealth.Injure(6);
}
```


# Rutnät\*


