Gode unity-resources
Simple game (easy)
2D gamemaking (medium)
Sebastian Lague (hard)
Tank-spil
Tank projekt som det var d. 21/11: NNY Tank NOV21
Tank projekt med nedenstående funktionalitet: NNY Tank COMPLETE
Reloading
Full script: TankShooting
Vi ændrer vores TankShooting-script til at inkludere en Reload-funktion, der gør at vi er nød til at reloade, istedet for bare at skyde for evigt.
Først laver vi nogle nye variabler:
Ammo: Hvor meget ammo, der er loaded og kan bruges lige nu.
TotalAmmo: Hvor meget ammo, vi har i alt.
MaxClipSize: Hvor meget ammo vi max kan have loaded.
Herefter laver vi en reload funktion:
Først finder vi ud af hvor meget vi skal reloade, ved at subtraktere vores maxClipSize med den ammo vi har lige nu.
F.eks. 30 – 17 = 13: Der skal reloades 13 skud.
int ammoToReload = maxClipSize – ammo;
Vi bruger dette tal (13), til at se om vi overhovedet har nok totalAmmo tilbage (fx: if totalAmmo < 13), og hvis vi ikke har, så addere vi det til ammo og sætter totalAmmo til 0. Altså har vi loaded vores sidste ammunition, og har ikke mere tilbage.
if(totalAmmo<ammoToReload){ammo+=totalAmmo;totalAmmo=0;}
else{ammo=maxClipSize;totalAmmo-=ammoToReload;}
public void AdjustAmmo(int adj){totalAmmo+=adj;ammoText.text=”AMMO: “+ammo+” / “+totalAmmo;}
if(Input.GetKeyDown(KeyCode.R)){Reload();}
Camera obstruction fix
Full script: CameraScript
Der var nogle klager over at man tit endte i situationer, hvor kameraet kigger direkte ind i en væg, så man ikke kan se fjenderne.
Her laver vi et script, som tjekker om der er en væg mellem spilleren og kameraet, og hvis der er så gør vi den gennemsigtig.
OBS: Dette script er ikke ideelt, da den kun gør en væg gennemsigtig af gangen uanset størrelsen, men det virker godt til simple spil som vores :).
Unity setup
Først skal vi ændre lidt på tingene i Unity. Sæt det material, der bruges på væggene til “Transparent”.
Herefter skal vi lave et nyt Layer, ved at vælge et GameObject og trykke > Layer > AddLayer > skriv nyt layer navn (fx: “Wall”).
Vælg derefter alle de gameobjecter, der spærrer kameraet og sæt deres later til det nye layer, du lavede.
Nu er vi klar til at programmere i CameraScript. Først laver vi en LayerMask, som indeholder nogle layers.
public LayerMask wallMask;
Denne sættes i Unity til de layers vi gerne vil tjekke efter kamera-obstruktioner på. I dette tilfælde vores nye Layer; “Wall”:
code
Vi har bruge for at vide om der er noget mellem to punkter, hvilket der heldigvis er en god funktion til. Vi sætter følgende in i vores Update funktion:
RaycastHit hit;Physics.Linecast(transform.position, player.position, out hit, wallMask);Debug.DrawLine(transform.position, player.position);
Her har vi først en Hit-variable, som indeholder var end der bliver ramt mellem spilleren og kameraet.
Så bruger vi Physics.Linecast, til at kigge mellem vores (kameraets) position og spillerens position. Den har også en out hit, hvilket betyder den smider resultatet ud til vores hit-variabel, og vores wallMask fra tidligere, som gør at Linecast ignorerer alle lag, der ikke er deri.
Til sidst har vi en Debug.DrawLine, der tegner den streg, som Linecast laver. Dette gør det lettere for os at visualisere, hvad koden gør.
if(hit.transform != null){Material mat = hit.transform.GetComponent<MeshRenderer>().materials[0];}
Color c = mat.color;c.a = 0.5f;mat.color = c;
if(hit.transform != null){Material mat = hit.transform.GetComponent<MeshRenderer>().materials[0];Color c = mat.color;c.a = 0.5f;mat.color = c;lastWall = hit.transform;}
if (lastWall != null && lastWall != hit.transform){}
Material mat = lastWall.GetComponent<MeshRenderer>().materials[0];Color c = mat.color;c.a = 1f;mat.color = c;
Making code reusable
lastWall.GetComponent…
hit.transform.GetComp…
c.a = 0.5f;c.a = 1f;
void SetAlphaOnObj(Transform trans, float alpha){}
void SetAlphaOnObj(Transform trans, float alpha){Material mat = trans.GetComponent<MeshRenderer>().materials[0];Color c = mat.color;c.a = alpha;mat.color = c;}
if (lastWall != null && lastWall != hit.transform){SetAlphaOnObj(lastWall, 1f);}if(hit.transform != null){SetAlphaOnObj(hit.transform, 0.5f);lastWall = hit.transform;}
Fixing scorescript
Full script: ScoreScript, HighscoreSystem
I denne sektion fixer vi vores ScoreScript, man kan ændre på om et level er færdigt når en timer når 0 eller når man får en vis mængde points.
Derudover, så gemmes scoren ikke mellem levels, så ens points starter forfra i nye levels.
Keeping score
Vi starter med at gemme scoren. Da vi kommer til at gemme scoren ofte, må vi først sikre os at den starter på 0, så man ikke lige pludselig starter med 1000 points i første level. Dette gør vi ved at sætte scoren til 0, efter vi er færdig med at bruge den i Highscore-scriptet. Det gør vi ved at placere følgende linje til sidst i start-funktionen:
PlayerPrefs.SetInt(“Score”, 0);
Vi sætter også følgende ind i Start-funktionen i ScoreScript:
score = PlayerPrefs.GetInt(“Score”);
Denne linje sætter scoren til den score vi har gemt globalt, så hvis vi får 100 points i første level, så starter vi også med 100 points i anden level.
Derudover fixer vi en lille fejl, der blev lavet i GameOver, hvor vi brugte sceneCount istedet for sceneCountInBuildSettings. Vores GameOver-funktion, skulle gerne se sådan her ud:
public void GameOver(){PlayerPrefs.SetInt(“Score”, score);SceneManager.LoadScene(SceneManager.sceneCountInBuildSettings-1);}
void OnApplicationQuit(){PlayerPrefs.SetInt(“Score”, 0);}
gameover by timer or by points
Først laver vi en bool, der holder styr på om banen færdiggøres ved timer der udløber eller points der når en vis mængde. Derudover laver vi en variable, der siger hvor mange points man skal have for at “vinde” banen:
public bool gameOverByTimer = false;public int scoreToGameOver = 10;
int scoreThisLevel = 0;
I Update, ændrer vi vores timer-if-statement til også at checke vores bool:
if(timer <= 0 && gameOverByTimer)
else if (scoreThisLevel > scoreToGameOver && !gameOverByTimer){PlayerPrefs.SetInt(“Score”, score);SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex+1);}
public void LoadNextLevel(){// Saves scorePlayerPrefs.SetInt(“Score”, score);// Loads next sceneSceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex+1);}
if (gameOverByTimer)timerText.text = “Timer: ” + timer.ToString(“F0”);elsetimerText.text = “Score: ” + scoreThisLevel + ” out of ” + scoreToGameOver;
Grunden til at vi bruger scoreThisLevel er at hvis vi brugte score og man kom fra et level med 10 points til et level hvor man scoreToGameOver er 10, så ville banen bare blive skippet, da man allerede har opnået målet. ScoreThisLevel sikre at man får 10 point i det level vi er i.
Vi skal derfor også huske at opdatere den i AdjustScore:
public void AdjustScore(int adj){// Add the adjustment to total score / score this lvlscore += adj;scoreThisLevel += adj;// Update score textscoreText.text = “Score: ” + score;}
Done!
Spillet kan nu klare at i laver mange forskellige levels (bare husk og adde dem til build settings) og derudover kan i udvide med jeres egne kreationer, som power-ups, flere slags våben osv.
Det var mega awesome at være jeres lærer :). Kontakt mig bare, hvis i har problemer med jeres projekter: