www.math.uni.lodz.pl/ radmat
Cel ćwiczeń Celem bieżących ćwiczeń jest stworzenie prostej gry 2D.
Prosta gra Stworzymy prostą grę, w której będziemy sterować pojazdem kosmicznym i będziemy mogli strzelać do rakiet przeciwnika.
Rysunek: Uruchomiona gra
Foldery W nowo utworzonym projekcie 2D proszę utworzyć foldery Prefabs, Scenes, Scripts oraz Sprites. W ostatnim katalogu proszę zapisać utworzone / pobrane z Internetu pliki (najlepiej w formacie PNG) statku kosmicznego gracza (plik PlayerStarship.png) oraz statku kosmicznego przeciwnika (plik EnemyStarship.png) (odpowiednimi wymiarami pliku będzie 100 na 100 pikseli), tła (plik background.jpg) oraz światło lasera (plik Laser.png). Uwaga! W oknie Inspector należy ustawić Texture Type na Sprite (2D and UI).
Tworzymy scenę gry Wstawiamy grafikę PlayerStarship na scenę i ustawiamy pozycję na (0, 0). Dodajemy do obiektu Box Collider 2D. Wstawiamy tło background.jpg, a następnie w oknie Inspector: Zmieniamy Texture Type na Default, Wrap Mode ustawiamy na Repeat, po czym zatwierdzamy zmiany. Tworzymy obiekt 3D Cube, zmieniamy jego nazwę na Background i usuwamy jego Box Collider wybierając Remove Component.
W zakładce Project z menu kontekstowego wybieramy Create Material i nadajemy mu nazwę materialbackground. W zakładce Inspector ustawiamy Shader na Unlit Texture. Zaznaczamy Texture i wybieramy teksturę tła. W polu Tiling wpisujemy wymiary grafiki będącej tłem. W oknie Hierarchy zaznaczamy obiekt Background, po czym w oknie Inspector w zakładce Mesh Renderer rozwijamy Materials i w polu Element 0 zmieniamy domyślny materiał na materialbackground. W zakładce Transform ustawiamy Position na (0, 0, 1), a Scale na (100, 100, 1).
Skrypt Player.cs public float playerspeeddefault = 3.0f; private float playerspeedcurrent = 0.0f; private float playerdecreasespeed = 0.99f; private Vector3 playerlastdirection = new Vector3(); public List<KeyCode> buttonup; public List<KeyCode> buttondown; public List<KeyCode> buttonleft; public List<KeyCode> buttonright; Powyższy kod dodajemy oczywiście do obiektu PlayerStarship.
W zakładce Inspector dla Button Up, Button Down, Button Left i Button Right ustawiamy Size na 2. Dla każdego z przycisków w polu Element 0 przypisujemy Up Arrow, Down Arrow, Left Arrow i Right Arrow odpowiednio, natomiast w polu Element 1 przypisujemy litery, np. W, S, A, D odpowiednio.
Dopiszmy następujący kod do funkcji Update: PlayerRotate(); PlayerMove();
void PlayerRotate() Vector3 mouseworldposition=camera.main.screentoworldpoint (Input.mousePosition); float mousedirectionx=mouseworldposition.x -this.transform.position.x; float mousedirectiony=mouseworldposition.y -this.transform.position.y ; float angle=mathf.atan2(mousedirectiony,mousedirectionx) *Mathf.Rad2Deg; this.transform.rotation = Quaternion.Euler (new Vector3(0,0,angle-90));
Na tym etapie możemy już przetestować zachowanie naszego statku kosmicznego (należy zakomentować funkcję PlayerMove()), który powinien obracać się w stronę kursora.
void PlayerMove() Vector3 thisframemove = new Vector3(); thisframemove += CheckMove(buttonUp, Vector3.up); thisframemove += CheckMove(buttonDown, Vector3.down); thisframemove += CheckMove(buttonLeft, Vector3.left); thisframemove += CheckMove(buttonRight, Vector3.right); thisframemove.normalize (); if(thisframemove.magnitude > 0) playerspeedcurrent = playerspeeddefault; playerlastdirection = thisframemove; else playerspeedcurrent *= playerdecreasespeed; this.transform.translate(playerlastdirection * Time.deltaTime * playerspeedcurrent, Space.Self);
Vector3 CheckMove(List<KeyCode> keycodelist, Vector3 move) foreach (KeyCode element in keycodelist) if(input.getkey(element)) return move; return Vector3.zero; Po wpisaniu powyższego kodu naszym pojazdem powinno już także dać się sterować za pomocą strzałek, bądź liter W, S, A i D.
Dodamy teraz możliwość strzelania. Na początku do istniejącego skryptu dopiszmy następujące zmienne: public Transform laser; public float laserdistance =.2f; public float timebetweenfires =.2f; private float timetillnextfire = 0.0f; public List<KeyCode> buttonfire; Dodatkowo do funkcji Update należy dopisać metodę LaserFire();.
void LaserFire() if (timetillnextfire <= 0) foreach (KeyCode element in buttonfire) if (Input.GetKey(element)) timetillnextfire = timebetweenfires; MakeLaserFire(); break; else timetillnextfire -= Time.deltaTime;
void MakeLaserFire() float laserx=this.transform.position.x+ Mathf.Cos((transform.localEulerAngles.z-90) *Mathf.Deg2Rad)*(-laserDistance); float lasery=this.transform.position.y+ Mathf.Sin((transform.localEulerAngles.z-90) *Mathf.Deg2Rad) *(-laserdistance); Instantiate(laser,new Vector3(laserX,laserY,0), this.transform.rotation);
W oknie Inspector dla obiektu PlayerStarship w polu Button Fire należy ustawić wartość 2, w polu Element 0 ustawiamy Mouse 0, a w polu Element 1 ustawiamy Space.
Skrypt Laser.cs Na początku do skryptu dodajemy następujące zmienne oraz uzupełniamy metody Start i Update. public float laserspeed = 6.0f; public float laserlifetime = 2.0f; public int laserpower = 1; void Start () Destroy(gameObject, laserlifetime); void Update () transform.translate(vector3.up * Time.deltaTime * laserspeed);
Dodajemy do sceny plik laser.png. Do obiektu laser dodajemy skrypt Laser.cs. Do obiektu laser dodajemy Box Collider 2D. Z okna Hierarchy przenosimy obiekt laser do katalogu Prefabs. Usuwamy obiekt laser ze sceny. W oknie Inspector obiektu PlayerStarship przenosimy prefab laser w pole Laser.
Rysunek: Okno Inspector obiektu PlayerStarship
Rysunek: Uruchomiona gra: nasz statek wystrzeliwuje laser
Skrypt Enemy.cs Dodamy teraz do sceny statek naszego przeciwnika, a następnie przypiszemy do niego nowy skrypt Enemy.cs. private Transform playertransformation; public float enemyspeed = 1.0f; public int energy = 1; void Start () playertransformation = GameObject.Find("PlayerStarship").transform;
void Update () Vector3 directiontoplayer= playertransformation.position-transform.position; directiontoplayer.normalize(); float movespeed=enemyspeed*time.deltatime; transform.position=transform.position +(directiontoplayer*movespeed); float playerdirectionx=this.transform.position.x -playertransformation.position.x; float playerdirectiony=this.transform.position.y -playertransformation.position.y; float angle=mathf.atan2(playerdirectiony,playerdirectionx *Mathf.Rad2Deg; this.transform.rotation= Quaternion.Euler(new Vector3(0,0,angle-90));
void OnCollisionEnter2D(Collision2D thecollision) if(thecollision.gameobject.name.contains("laser")) Laser l = thecollision.gameobject.getcomponent("laser") as Laser; energy -= l.laserpower; Destroy(theCollision.gameObject); if (energy <= 0) Destroy(this.gameObject);
Do obiektu EnemyStarship dodajemy Box Collider 2D. Dodajemy komponent Rigidbody 2D i ustawiamy Gravity Scale na 0. Analogicznie jak w przypadku obiektu laser, również z obiektu EnemyStarship wykonujemy prefab. Tworzymy pusty obiekt i zmieniamy jego nazwę na EnemyController.
Skrypt EnemyController.cs Tworzymy nowy skrypt i dodajemy go do obiektu EnemyController. private Transform playertransformation; private float timetocreateenemy = 0; private int currentnumberofenemies = 0; public Transform enemy; public float timebetweenenemies = 2.0f; public int maxenemies = 5; void Start () playertransformation = GameObject.Find("PlayerStarship").transform;
void Update () timetocreateenemy-=time.deltatime; if (timetocreateenemy <= 0 && currentnumberofenemies < maxenemies) float randdirection=random.range(0,360); float randdistance=random.range(5,10); float newenemypositionx=playertransformation.position.x Mathf.Cos((randDirection)*Mathf.Deg2Rad)*randDistance; float newenemypositiony=playertransformation.position.y (Mathf.Sin((randDirection)*Mathf.Deg2Rad)*randDistance) float playerdirectionx=newenemypositionx -playertransformation.position.x;
float playerdirectiony=newenemypositiony -playertransformation.position.y; float angle= Mathf.Atan2(playerDirectionY,playerDirectionX) *Mathf.Rad2Deg; Instantiate(enemy,new Vector3(newEnemyPositionX, newenemypositiony,0), Quaternion.Euler(new Vector3(0,0,angle-90))); currentnumberofenemies++; timetocreateenemy=timebetweenenemies; public void EnemyWasKilled() currentnumberofenemies--;
W oknie Inspector do zmiennej Enemy obiektu EnemyController przenosimy prefab EnemyStarship. Do skryptu Enemy.cs dopisujemy następujące linijki kodu (w instrukcji warunkowej if(energy <= 0)) EnemyController s = GameObject.Find("EnemyController").GetComponent("EnemyController") as EnemyController; s.enemywaskilled();
Ćwiczenie Na tym etapie gry jesteśmy w stanie poruszać naszą rakietą i unicestwiać wrogów. Proszę dodać możliwość strzelania przez rakiety przeciwnika. Każde trafienie powinno powodować zestrzelenie naszego pojazdu, tj. zniknięcie z planszy.