====== Brick Breaker ====== * [[https://unity3d.com/learn/tutorials/modules/beginner/live-training-archive/creating-a-breakout-game?playlist=17219|Tutorial Brick Breaker]] (Die hier erläuterte Lösung entspricht NICHT der des Tutorials!) ===== Setup ===== Man baut sich eine Szene, die drei Wände umfasst, einige Bricks und darunter Paddle und Ball. \\ Unter das Paddle soll dann noch ein Cube gelegt werden, der Water heißt.\\ Wichtig für alle Teile, die mit dem Ball in kontakt kommen (inkl. Ball selbst) ist, dass sie ein Physic Material "Bouncy" bekommen, dass ihnen maximalen Abstoß voneinander verleiht und die Reibung auf null setzt.\\ Die Szene sollte dann so aussehen: {{:inf:unity3d:documentation_scene_setup.png?nolink&500|}} Wichtig ist, dass die Bricks gleich heißen, dass Paddle und Ball einen Rigidbody (kinematisch, keine Gravitation) bekommen und, dass das Wasser auf "isTrigger" gesetzt wird.\\ Weiters muss der Ball ein "Child"-Objekt von Paddle sein.\\ Die Hierachie sollte dann etwa so aussehen: {{:inf:unity3d:documentation_hierachy.png?nolink&300|}} ===== Paddle-Controller ===== Das Paddle soll am unteren Rand des Bildes sich nur auf der x-Achse bewegen können. Dazu erstellt man folgendes Script: using UnityEngine; using System.Collections; public class PaddleScript : MonoBehaviour { public float paddleSpeed=1f; private Vector3 playerPos = new Vector3(0f,-9.5f,0f); // Use this for initialization void Start () { } // Update is called once per frame void Update () { float xPos = transform.position.x + Input.GetAxisRaw ("Horizontal") * paddleSpeed; xPos = Mathf.Clamp (xPos, -8f, 8f); playerPos = new Vector3 (xPos, -9.5f, 0f); transform.position = playerPos; } } paddleSpeed beschreibt den Geschwindigkeitsmultiplikator für die Bewegung und soll öffentlich geändert werden können.\\ Die aktuelle Position wird durch den Vector3 "playerPos" angezeigt.\\ Um nun die neue x-Position zu berechnen, wird zu der aktuellen Position der Input auf der horizontalen Achse (multipliziert mit paddleSpeed) addiert und durch Mathf.Clamp eingeschränkt, damit das Paddle das Spielfeld nicht verlässt.\\ Die neue x-Koordinate wird dann in die Player-Position eingelesen und dann die wirkliche Position verändert. ===== Ball-Controller ===== Auch für den Ball selbst ist ein Script zu erstellen. Dieses soll bewirken, dass der Ball beim ersten STRG-Klick vom Paddle gelöst wird und einen Stoß bekommt.\\ Des Weiteren soll in diesem Script bei Kollision mit einem Brick dieser zerstört werden und mitgezählt werden, wie viele bereits zerstört wurden.\\ Auch soll in einem Text (der noch eingefügt werden muss), die Anzahl der verbleibenden Bricks angezeigt werden.\\ Ein weiterer Text, der eingefügt werden muss, soll die Anzahl der verbleibenden Leben anzeigen.\\ Dieses sollte dann so aussehen: using UnityEngine; using UnityEngine.UI; using System.Collections; public class BallScript : MonoBehaviour { public float initVel=600; //Intensität des ersten Stoßes public int anzahlBricks=16; //Anzahl der zu zerstörenden Bricks (MUSS genau die Anzahl der erstellten Bricks sein!) public int Leben = 3; //Anzahl der Leben (MUSS mit Text übereinstimmen!) public Text anzahlText; //Zeigt Anzahl der verbleibenden Bricks an public Text anzahlLeben; //Zeigt Anzahl der verbleibenden Leben an public Text gameover; //Gameovertext public Rigidbody paddle; //Erlaubt Zugriff auf das Paddle private Rigidbody rb; //Variable für den Rigidbody private bool inPlay = false; //Kontrolliert, ob Ball schon im Spiel ist (kein 2. Stoß möglich) // Use this for initialization void Awake () { rb = GetComponent (); //Rigidbody des Balls wird eingelesen inPlay = false; //Am Start ist der Ball nicht im Spiel } // Update is called once per frame void Update () { if (Input.GetButtonDown ("Fire1") && inPlay==false) { inPlay=true; //Ball ist nun im Spiel transform.parent=null; //löst den Ball vom Paddle rb.isKinematic=false; //nicht mehr kinematisch (kann sich bewegen) rb.AddForce(new Vector3(initVel,initVel,0)); //Stoß wird mitgegeben } } void OnCollisionEnter(Collision other) //Wenn Kollision mit einem ANDEREN Objekt { if (other.gameObject.name == "Brick") { //Wenn "Brick" getroffen wird other.gameObject.SetActive(false); //nicht mehr aktiv //Alternative: //Destroy(other.gameObject); anzahlbricks--; anzahlText.text="Anzahl: "+anzahlBricks; //Passt den Anzahltext auf die aktuelle Anzahl der Bricks an CheckGameOver(); } } void OnTriggerEnter(Collider other) { if (other.gameObject.name == "Water") { //Wenn mit Wasser kollidiert wird (und dadurch ein Leben verloren werden soll) Leben--; anzahlLeben.text="Lives: "+Leben; //Zurücksetzen des Balls: inPlay=false; rb.isKinematic=true; //Wieder statisch //paddle.transform.position=new Vector3(0f,-9.5f,0f); //Zurücksetzen des Paddles auf die Ausgangsposition float xPos=paddle.transform.position.x; //Schreibt die xPos des Paddles in die Variable rb.transform.SetParent(paddle.transform); //Setzt den Ball wieder als "Child" des Paddles rb.transform.position=new Vector3(xPos,-8.5f,0f); //Setzt Ball wieder auf das Paddle CheckGameOver(); } } void CheckGameOver() { if (Leben == 0) { gameover.text="GAME OVER"; rb.gameObject.SetActive(false); paddle.gameObject.SetActive(false); Invoke("Reset",4f); } if (anzahlBricks == 0) { gameover.text="YOU WON"; rb.gameObject.SetActive(false); paddle.gameObject.SetActive(false); Invoke("Reset",4f); } } void Reset() { Application.LoadLevel (Application.loadedLevel); } }