Jeg kommer til at følge nogle videoer som jeg har linket til ved siden af.
På denne side, vil der være dokumentation, for hvad jeg har lært i de forskellige episoder. Jeg vil også have skrevet ting, som jeg havde svært ved og løsninger jeg fandt.
Man kan zoom ind og ud ved brug af scrollwheel, hvis man trykker på mussehjulet kan man panorere rundt, og med alt+venstre klik kan man dreje rundt.
Components er det som gør at forskellige objekter gør forskellige ting, og bliver vist i inspecteren når man klikker på et object i scene.
For at få realistiske physics skal man bruge rigridbody, en box collider og en mesh renderer for at se objectet.
scenes can be compared to different levels.
Transform: Styrer hvor objectet er i forhold til xyz akserne.
Mesh renderer: Gør at man kan se objectet på skærmen.
Box collider (ændres til hvilken form du har): Gør at objecterne kan kollidere med hindanen.
Mesh filter: Styrer hvilken form objecter har.
Shift+space gør at man kan maximere game view.
Når man programmere i Unity, kaldes det et script. Man skal klikke på objectet og tilføje et nyt kompenent som hedder New script, og så vælge et programerings sprog. Den her tutorial bruger c#
Konsollen bliver brugt til at debug, det er her at der bliver sagt, hvis der er sket en fejl.
Fordi at vi bruger void Update(), som laver en opdatering hver frame, skal vi tilfjøje vores *Time.deltaTime til vores funktion, det gør at det afhænger af, hvor mange gange i sekundet den kører, det er smart fordi at framerates afhænger af computeren, og derfor har forskellige computere forskellige framerates.
Fx, hvis vi vil have at vores object skal flyve en hvis distance hver Update, så vil koden hede.
rb.AddForce(0,0,200); men med vores lille ændring vil den se sådan her ud:
rb.AddForce(0,0,200*Time.deltaTime); nu afhænger den af hvor mange gange den gør på et sekund, istedet for hvert frame i et sekund.
Derudover skal vi ændre Update til FixedUpdate, når vi laver noget med physics, da det gøre mere optimalt.
Alt det kode der bliver skrevet i void Start(), vil køre når, spillet starter.
Man kan referere til et komponent i koden, ved at skrive: public komponentnavn forkortelse;
Man derefter drag komponentet ned i et åbent slot i sin script komponent i unity
fx
Public Rigidbody rb;
Nu når vi skriver rb i koden, ved den at vi referere til komponenten Rigidbody
Man kan i unity tilføje en asset som hedder physic material, hvor man kan tilføje hvor meget friktion et objekt har.I stedet for at hard kode en funktion,
kan man oprette variabler som referere til en specifik funktion. Det smarte ved at gøre det til en variabel er at vi nu kan ændre direkte på den fra selve unity, i stedet for at gå ind i koden hver gang.
If statements kan bruges, når du gerne vil have noget sker når nogle betingelser er opfyldt.
I denne episode fokuserede der primært på at spilleren kan rykke sig til siden. Det gøres sådan her:
Først oprettes der en variabl
public float sidewaysForce = 500f;
og så laver vi et if statement til hvis man trykker a og d, respektivt.
if (Input.GetKey("d"))
{
rb.AddForce(sidewaysForce * Time.deltaTime, 0, 0)
}
Dette gør at, når spilleren presser d, så vil rykke sig på x aksen, vil vi have at den skal gå den anden vej på x-aksen tiføjer vi bare et minus foran.
if(Input.GetKey("a"))
{
rb.AddForce(-sidewaysForce * Time.deltaTime, 0, 0)
}
Denne episode handler om at få kameraet til at følge efter spilleren.
I unity kan man putte game objects inde under hinanden, ved at dragge dem. Problemet med at gøre det i vores spil her, er at den vil være så fikseret på spiller objektet, at når vi kollidere med et andet object vil kameraet også rotere, og det vil vi ikke have.
Vi kan få kameraet til kun at følge positionen på spiller objektet, ved brug af et script.
I scriptet opretter vi to variabler
public Transform player; Denne variabel kalder vi player, og vi bruger Transform komponentet, som gemmer 3 float værdier, inde i unity sætter vi vores player object ind i denne variabel, så koden ved at vi referrer til spilleren position.
public Vector3 offset; Denne variabel kalder vi offset, det er en Vector3 som kan gemme 3 float værdier.
nu hvor vores variabler er sat på plads, kan vi skrive koden inde i en void Update
void Update()
{
transform.position = player.position + offset;
}
Denne kode ændrer altså kameraets transform postion til at være lige med spilleren position + vores variabel offset. Inde i unity kan vi ændre på variablen, så kameret er længere væk og længere oppe.
Fori den er inde i en update, sker det her hvert frame, så kameret vil blive ved med at følge spilleren fra en konsant afstand.
Episode 5 handler om at oprette forhændringer, og få ting til at ske når 2 objekter kollidere.
Vi kan lave en cube objekt, som vi kalder for Obstacle, og give det et tag som også hedder Obstacle. Derefter opretter vi et script ved navn PlayerCollision.
I koden skriver vi:
public PlayerMovement movement;
void OnCollisionEnter(Collision collisionInfo)
{
if(collisionInfo.collider.tag == "Obstacle")
{
movement.enabled = false;
}
}
Vi laver en variabel under scripet, som refere til vores andet script, når der bliver skrevet "movement"
Det koden gør, er at når vores spiller kollidere med et objekt, så skal den tjekke hvilket tag objektet har. Hvis objektets tag er "Obstacle" så skal variablen movement.enabled = false; det gør at vores PlayerMovement script stopper med at kørenår spilleren rammer en obstacle.
Denne episode handler om få lavet gameplay.
Ved at dragge et object ned i sin assets menu, kan man skabe en prefab. Man kan nu Drag and drop objektet ud på levellet, det smarte her er, at du kan ændre egenskaberne for dem alle sammen på en gang.
Det kan være nemmere at skabe overblik, hvis du ændrer din synsvinkel. En nem måde at gøre det på er at klikke på de forskellige akser i scene view.
Når man kigger på spillet oppe fra, kan det være svært at ramme de rigtige objects, man kan tilføje forskellige layers, og så låse dem, Fx tilføje et layer til ground objectet, og låse den. Nu kan man let klikke på Obstacles og rykke på dem uden at ændre jorden.
Ved at trykke på et object og holde fast på den grønne del, nu kan man flytte på objectet uden at den ændrer y værdien. Man kan flytte på den med freehand, men hvis du gerne vil have at den klipper sig til gitteret, kan du holde på control, man kan ændre på, hvor mange units der skal gå før objectet klipper sig inde i edit -> snap settings.
For at få spilleren til at bevæge sig mere flydende, det gør vi med noget som hedder force parameter, fordi at vores spiller får momentom, når vi så gerne vil bevæge os fra side til side, skal der opbygges en vis force for at modvirker momentommet, det kan man gøre ved at tilføje ForceMode.VelocityChange:
rb.AddForce(0, 0, forwardForce * Time.deltaTime);
if (Input.GetKey("d") )
{
rb.AddForce(sidewaysFore * Time.deltaTime, 0, 0, ForceMode.VelocityChange);
}
if (Input.GetKey("a"))
{
rb.AddForce(-sidewaysFore * Time.deltaTime, 0, 0, ForceMode.VelocityChange);
}
Sideways force skal tones lidt ned, da den ændres drastisk.
Man kan også ændre "drag", som er luftmodstand. det gør man inde i objecets Rigidbody
Man kan også tilføje en tåge, det gør at man ikke kan se hele levelet fra starten, og det hjælper spilleren til at blive synket mere ned i spillet.
Gå ind under window -> lighting og klik på fog knappen, her kan du ændre farve, densitet og meget mere. Det er en god ide at vælge en farve som blander sig med sin skybox.
Score og UI
Det er en god ide at lave forskellige mapper til sine assets, fx en scripts mappe til alle sine scripts.
For bedre physics kan man vælge collision detection skal være continuous, det gør man ved at klikke på sit objekt og ændre det under rigridbody
For at lave en UI, går man under hierarchy, og vælge UI og så det du vil vælge, jeg vælger en text. Den bliver tilføjet under en Canvas, for at se sin text på skærmen, gå ind i 2D view og tryk F for at locate text objectet, man kan ændre den i forhold til sit gameplay cam.
Hvis man trykker på selve canvas objektet, kan man ændre texten fra at være constant pixel size til at skalere basseret på hvor stort vinduet er.
For at få scoren til at opdatere skal der laves et script, det gør man ved at tilføje et component til objektet, som hedder "script", i dette tilfælde tilføjer man et script component som hedder "Score" til text objektet.
Inde i scriptet skriver vi den her kode:
using UnityEngine;
using UnityEngine.UI;
public class Score : MonoBehaviour
{
public Transform player;
public Text scoreText;
void Update()
{
scoreText.text = player.position.z.ToString("0");
}
}
"using UnityEngine.UI;" gør at hele koden virker, da vi laver en UI
Vi starter med at lave 2 variabler, den ene er "public Transform player;", den gør at vi kan få vores player objects Transform position senere. Den anden variabel hedder "public Text scoreText;" det er den der gør at den kode vi skriver bliver puttet på vores selve text objektet.
Inde i selve unity skal man dragge player objektet ind på player variablen inde under scripet for texten. Man skal også dragge text objectet på text scriptet.
"scoreText.text = player.position.z.ToString("0");" man skriver .text efter vores variabel da vi gerne vil ændre på selve texten, og ikke fonten eller størelsen, man kan udskifte .text med fx .font eller andet for at ændre andre ting. Vi siger altså at variablens text skal være ligemed spiller variablen "player.position.z", det den gør er tage spillerens postion på z aksen, og fordi vi har skrevet koden under "void Update()" vil den opdatere på hvert frame. Vi blivet nødt til at tilføje .ToString("0"); fordi at "Transform position" bliver givet i datatypen "float", hvor text er i datatypen "string", ToString(); gør så at datatypen ændres vi tilføjer ("0") for at texten ikke displayer dicimal tal.
Denne episode handler om at lave en "Game over" skærm, når du taber (kollidere med en obstacle eller falder ud over kanten.).
Vi starter med at lave et tomt objekt, som vi kalder GameManager, vi laver herefter et script med samme navn, man bruger GameManageren til at ændre tilstanden af dit spil, for eksempel, en game over screen.
Vi kommer til at bruge den til at genstarte spillet, hvis vi kollidere med et obstacle eller falder ud over kanten.
Inde i vores GameManager script, skal vi fjerne de 2 void funktioner og tilføje vores egen. Vi kalde den void EndGame (), for at gøre det nemmere for os senere tilføjer vi et public foran, det gør at vi kan referere til den i andre scripts. Så starten på vores kode i GameManager scriptet ser sådan ud:
public void Endgame ()
{
"selve kode her"
}
Inde i vores PlayerCollision script vil vi gerne referere til vores GameManager, og det har vi gjort førhen ved at skrive public "reference" navn, men der er en anden måde at gøre det. Man kan skrive FindObjectOfType<"reference">(); Man kan derefter tilføje et punktum for at få adgang til mere specifike til i referencen.
Så i vores tilfælde skal man tilføje: FindObjectOfType<GameManager>().EndGame();
Inde i vores PlayerMovement script, vil vi gerne gøre at, når vores spiller falder ned i -y-aksen, så skal vi restart spillet, fordi så er spilleren faldet ud over kanten. Det gør vi ved denne kode:
if (rb.position.y < -1f)
{
FindObjectOfType<GameManager>().EndGame();
}
Nu kommer der et problem med at fordi at denne kode er inde i et void update, så sker koden flere gange, og det vil vi ikke have, vi vil gerne have at den køre 1 gang, det kan vi fixe inde i vores GameManager script:
bool gameHasEnded = false;
public void EndGame ()
{
if (gameHasEnded == false)
{
gameHasEnded = true;
}
}
Det vi har gjort er at vi har lavet en boolean, en boolean kan kun være true eller false, vi har så kaldt denne variabel for "gameHasEnded" og sat den til false. Det gør at koden kun bliver kørt en gang.
Det sidste vi skal gøre er at restart vores spil når den kode kører. Det gør vi ved at lave en seperat funktion i vores GameManager script.
Oppe i toppen skriver vi using UnityEngine.SceneManagement;
Det gør at vi kan styre hvilken scene der skal køre.
Vores kode kommer til at se sådan ud nu.
bool gameHasEnded = false;
public void EndGame ()
{
if (gameHasEnded == false)
{
gameHasEnded = true;
Restart();
}
}
void Restart ()
{
SceneManager.LoadScene(SceneManager.GetActiveScene().name);
}
Inde i vores public void EndGame kalder vi på vores void Restart(), som så bruger SceneManager til at load den scene vi er på, som så betyder at spillet restarter. Nu er der et nyt problem, og det er at, funktionen sker med det samme og det vil vi ikke have. Vi vil gerne kunne se vores kollision physics, så vi skal tilføje et delay til vores funktion, det gør vi ved at bruge Invoke. Den virker ved at man skriver sin funktion et komma og så sin delay. Vi kan først lige lave en variabel, som vi kalder restartDelay, det gør det nemmere at ændre senere i selve unity engine.
public float restartDelay = 1f;
Invoke("Restart", restartDelay);
Triggers, UI, Loading next level og animation er de ting episode 9 handler om.
Vi starter med at lave en 3d cube som vi putter i slutningen af vores level, som vi bruger som en trigger. En god ide er at gøre den samme bredde som selve banen, da man skal køre ind i den før, at koden aktivere. Derudover er vi ikke interesserede i at kunne se selve cuben, så vi slår mesh renderer fra.
Vi tilføjer et script component, som vi kalder for EndTrigger.
Inde i den laver vi en ny void, som hedder void OnTriggerEnter (), vi skal nu referere til vores GameManager, og her bruger vi bare public fordi det er simplere. Vi skriver den sådan her: public GameManager gameManager; Vi kan nu referere til en funktion som er inde i GameManager, men vi har ikke oprettet funktionen endnu. Inde i GameManager scriptet laver vi nu en funktion ved at skrive
public void CompleteLevel ()
{
}
Vi kan nu kalde på den funktion inde i EndTrigger scriptet, hvor vi skriver:
void OnTriggerEnter()
{
gameManager.CompleteLevel()
}
Vi kan nu lave UI'en til hvordan det skal se ud, under vores Canvas object, skal der laves en ny ui, det skal være et panel som vi kalder LevelComplete, Du kan gøre det til hvilken som helst farve, men jeg har valgt hvid. Under det panel skal du nu oprette 2 Text objecter, hvor den ene hedder Level og den anden hedder complete, center begge tekster og skriv level og complete, hvor hver respektiv objekt.
Vi vil ikke have at vi altid kan se LevelComplete panelet, så vi skal gøre at når man rammer den usynlige boks, så kalder den på panelet. Det gør man ved først at deaktivere panelet.
Derefter går vi ind i vores GameManager og laver en reference variable til den, v ikalder den bare:
public GameObject completeLevelUI;
Dernæst skriver vi inde i vores CompleteLevel funktion:
completeLevelUI.SetActive(true);
Husk at dragge LevelComplete panelet ind i selve variablen inde i unity editoren.
Vi kan animere panelet, gennem animation vinduet. Her kan man optage hvilke ting der skal ændre og hvornår.
Til sidst vil vi gerne have at der bliver skiftet scene, det gør man ved at trykke på event flaget i animations vinduet, vi tilføjer et nyt script under LevelComplete panelet, som vi kalder LevelComplete, inde i den skriver vi:
Det er vigtigt at vi bruger using UnityEngine.SceneManagement; for at få adgang til SceneManager.
public void LoadNextLevel()
{
SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex + 1);
}
Hver scene har et build index som man kan finde ved at gå under file -> build settings. Den starter fra 0, så vores scene 1 har build indexet 0.
Hvis vi laver en ny scene som hedder level 2 vil den have buildindexet 1, derfor siger vi dot buildIndex +1, for at få næste scene.
I den sidste episode skal man lave en credit scene og en velkomst scene, og klargøring af export.
Det er en god ide at lave sine vigtigste objecter til Prefabs, ved at dragge dem fra hierarchy til assets.
Man kan nu lave en ny scene, som kommer til at være vores credit scene.
Vi opretter et nyt panel under UI, som vi kalder Credits under credits panelet laver vi et text ui element.
Her laver du tre text elemnts en som hedder Thanks, hvor der står thanks for playing
en som hedder MadeBy, hvor der står Made by:
og en sidste, du kalder dit navn, hvor der står dit navn.
Vi kan nu tilføje en knap, som gør at man kan gå ud af spillet. Under credits laver vi et scripts som hedder credits.
Vi laver en funktion som er public:
public void Quit()
{
}
Vi kan nu gå under vores button object og under on click vælge vores funktion.
Inde i vores funktion skriver vi:
Application.Quit();
Den kommer først til at virke når vi har ekspoteret vores spil.
Vi kan duplicere denne scene og kalde den for Menu, og ænder lidt tekst så det bliver en menu.
Nu kan man gå under panelet, og fjerne credits scriptet for at lave en Menu script i stedet.
I menu scripet skriver using UnityEngine SceneManagment;
og laver en public void funktion
public void StartGame()
{
SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex + 1);
}
Nu skal man bare drag welcome objektet ned i on click på button, og vælge Menu scriptet.
Til sidst skal man ind i build settings, og putte alle scener i rigtige rækkefølge.
Jeg har lært hvordan man laver et simpelt spil i Unity, jeg har især fået et overblik over at scripte, og få koblet scriptet på de rigtige objekter, derudover har jeg lært mange af de forskellige termer, som object, hierarchy, assets, funktions, canvas og meget mere.