Jump to content
Unity Insider Forum

Wir bauen uns ein Space Shoot em Up [Teil 4 - Waffen]


Mark

Recommended Posts

Nachdem wir nun schon angefangen haben uns Komponenten zu basteln die wir an das Schiff bauen können um mehr Funktionalität zu erhalten führen wir das fort indem wir uns den Sachen zuwenden die uns dabei helfen andere Sachen kaputt zu machen: Waffen!

 

Überlegen wir zuerst einmal was genau wir alles abdecken wollen mit unseren Waffen.

 

Es gibt Waffen die Projektile abfeuern können und Waffen die sofort treffen sollen. Es gibt Waffen die stark streuen und welche die sehr genau schießen.

Waffen sollen unterschiedlich schnell feuern können. Auch wäre es toll wenn wir Waffen haben die mehrere Projektile auf einmal feuern, etc etc.

 

Vieles können wir zusammen fassen. Dadurch können wir uns einem Konzept der C# Sprache zuwenden (dieses Konzept existiert in vielen Sprachen), abstrakte Klassen.

 

Abstrakte Klassen sind Klassen in denen fehlende Funktionen implementiert müssen bevor sie verwendet werden können. Dazu leiten wir von dieser Abstrakten Klasse ab und implementieren diese fehlenden Funktionen in unserer neuen Klasse. Wir werden in diesem Tutorial eine abstrakte Klasse genannt "Weapon" implementieren und eine abgeleitete Klasse genannt "ProjectileWeapon". Später können wir noch mehr Klassen von "Weapon" ableiten, zB die Waffen die keine Projektile besitzen und sofort treffen.

 

Wir erzeuge uns also ein neues C# Script mit dem Namen "Weapon" und ändern

 

public class Weapon : MonoBehaviour

 

zu:

 

public abstract class Weapon : MonoBehaviour

 

abstract ist ein weiteres C# Keyword welches besagt dass die Klasse nicht direkt verwendet werden kann und erst abgeleitet werden muss. Damit legen wir klar fest, Weapon kann so nicht verwendet werden.

 

Unsere Weapon Klasse soll dennoch ein wenig machen, zB regeln wann wir wieder feuern dürfen und einige Grundmethoden vorstellen.

 

Fügt daher als erstes ein paar Variablen zur Klasse hinzu:

 

public float ReloadTime = 0.0f;
public int AmmoPerMagazin = 1;
public float DelayPerShoot = 0.1f;
public float SpreadAngle = 10;
public int ShootsPerFire = 1;

private int firedShootsPerFire = 0;
private int currentAmmoInMagazin = 1;
private bool shouldFire = false;
private bool isFiring = false;
private bool isReloading = false;
private bool isCooling = false;

 

Diese Regeln wie viele Schüsse wir feuern können bis wir nachladen müssen. Die Zeit die fürs Nachladen benötigt wird. Wie lange wir warten müssen bis ein neuer Schuss gefeuert werden kann. Wie sehr unsere Waffe streut und wie viele Schüsse wir noch im Magazin haben.

 

shouldFire wird vom Benutzer verändert über 2 Methoden die wir gleiche implementieren werden. isFiring gibt an ob wir grade am feuern sind, wenn wir zB eine Waffe haben die immer 10 Schüsse abgeben soll, dann wird isFiring so lange true bleiben bis diese 10 Schüsse verschossen sind, egal was der Spieler möchte. isReloading gibt an ob die Waffe grade nachlädt und isCooling gibt an dass die Waffe einen Moment warten muss bevor ein weiterer Schuss gelöst wird.

 

Um unsere Waffe benutzen zu können müssen wir die isFiring Variable je nachdem ob wir feuern wollen oder nicht verändern.

Deswegen fügen wir 2 Methoden zur Klasse hinzu:

 

public void StartFiring()
{
shouldFire = true;
}

public void StopFiring()
{
shouldFire = false;
}

 

Diese beiden Methoden machen nun wirklich nicht viel, was feuert denn nun? Eine weitere Methode, die aber so wie die Klasse selbst als abstract markiert wird, diese Methode muss später von ableitenden Klassen überschrieben und implementiert werden.

 

protected abstract void Fire();

 

abstract haben wir ja bereits erklärt, neu ist allerdings das protected Keyword. Protected ist in der gleichen Kategorie wie private und public, es regelt also die Erreichbarkeit der Methode. protected hat die Eigenschaft dass die damit ausgeschmückte Methode nur von der eigenen Klasse (so wie private) UND abgeleiteten Klassen aufgerufen oder implementiert werden kann.

 

Nun regeln wir wie das Waffensystem nun agieren soll. Es soll, wenn wir keine Munition mehr im Magazin haben, dieses neu laden und das feuern in dieser Zeitspanne verbieten. Gefeuert darf nicht jeden Frame, dies regeln wir durch die DelayPerShoot Variable, die genauso wie beim nachladen in der Zeitspanne verhindern soll dass die Waffe gefeuert wird.

 

Wie implementieren uns einige kleine Methoden welche sowohl das Nachladen als auch das Verzögern regeln sollen, zuerst das nachladen:

 

private void ReloadWhenNeeded()
{
if (currentAmmoInMagazin > 0 || isReloading)
{
	return;
}

if (ReloadTime <= 0.0f)
{
	currentAmmoInMagazin = AmmoPerMagazin;
	return;
}

isReloading = true;
isFiring = false;

StartCoroutine(Reload());
}

IEnumerator Reload()
{
yield return new WaitForSeconds(ReloadTime);

isReloading = false;
currentAmmoInMagazin = AmmoPerMagazin;
}

 

Wow, was für ein Brocken, aber keine Angst, ich beschreibe die einzelnen neuen Aspekte. Die ReloadWhenNeeded Methode prüft am Anfang ob wir überhaupt nachladen müssen und ob wir grade nachladen. Wir testen im ersten if, genau 2 Bedingungen, wenn eine davon erfüllt ist, wird die Methode wieder verlassen. Wir können mehrere Bedingungen aneinander Reihen, wir haben dies zB mit dem || Symbolen getan, || bedeutet "oder", also wird diese if Bedingung erfüllt sein wenn entweder mehr als ein Schuss im Magazin ist, oder wir grade am nachladen sind.

 

Die nächste if Abfrage schaut nach ob wir für diese Waffe überhaupt die Notwendigkeit haben nachladen zu müssen, wir lösen das indem wir einfach schauen wie lange das nachladen dauert, wenn es keine Dauer hat dann setzen wir die aktuelle Munition i Magazin aufs Maximum und beenden die Methode wieder.

 

Wenn keine der if Bedingungen erfüllt wurde dann sagen wir dass wir nun am nachladen sind (isReloading), brechen das aktuelle feuern der Waffe ab und machen nun etwas besonderes:

 

Wir starten unsere erste Coroutine. Coroutinen sind Methoden die über mehrere Frames hinweg arbeiten können. Unsere zweite Methode die Reload genannt wird und ein IEnumerator als Rückgabetyp besitzt ist diese Coroutine. in C# und Unity müssen Coroutinen diesen Typen zurückgeben. Durch das yield sagen wir an dass alles bis zu diesem yield ausgeführt werden soll und erst im nächsten Frame weiter gemacht werden soll. Durch yield return new WaitForSeconds(ReloadTime); besagen wir sogar dass die Methode erst weiter machen soll wenn ReloadTime Sekunden vergangen sind. Wenn diese Zeit vergangen ist sagen wir dass wir fertig sind mit dem Nachladen und füllen das Magazin wieder auf.

 

Das Verzögern sieht ähnlich aus:

 

public void Delay()
{
if (isCooling)
{
	return;
}

isCooling = true;

StartCoroutine(DelayFiring());
}

IEnumerator DelayFiring()
{
yield return new WaitForSeconds(DelayPerShoot);

isCooling = false;
}

 

Ist aber weitaus weniger komplex als das Nachladen.

 

So Zeit das ganze zusammen zu führen, wir erweitern unsere Update Methode welche prüft ob wir feuern sollen und können, feuert wenn alles stimmt und nachlädt wenn nötig.

 

if (shouldFire && !isFiring && !isCooling && !isReloading)
{
isFiring = true;
firedShootsPerFire = 0;
}

if (isFiring && !isCooling && !isReloading)
{
firedShootsPerFire ++;
currentAmmoInMagazin --;
if (firedShootsPerFire == ShootsPerFire)
{
	isFiring = false;
}

Fire();

Delay();
ReloadWhenNeeded();
}

 

Im ersten if gibt es eine weitere Neuigkeit die && Symbole, welche und bedeuten, so wie das oder (||) wird das und benutzt um mehrere Bedingungen zu verknüpfen. Die Bedingung gilt dann nur als erfüllt wenn alle mit dem und verknüpften Unterbedingungen erfüllt sind.

 

Das erste if sagt das wirklich gefeuert wird wenn der Spieler feuern will (shouldFire), wir nicht bereits am feuern sind (isFiring) wir nicht grade eine auf den nächsten Schuss warten (isCooling) und wir nicht grade am nachladen sind (isReloading).

 

Das nächste if erledigt die Hauptarbeit wenn die Bedingung erfüllt ist. Erst wird der Zähler erhöht der festhält welchen Schuss in einer Reihe wir grade machen. Dazu werde die ++ Symbole verwendet. ++ ist eine Kurzform von += 1. Die Kurzform für -= 1 wäre das --.

 

Wenn die Sequenz der Schüsse erledigt ist dann hören wir auf zu feuern bis zum nächsten Update Zyklus in dem erneut geprüft wird ob wir feuern sollen.

 

Anschließend wird gefeurt indem wir unsere abstrackte Fire Methode aufrufen und das Nachladen geprüft sowie der Delay zwischen den Schüssen gestartet.

 

Wir erweitern an dieser Stelle noch schnell unseren PlayerController indem wir wie beim Drive eine Weapon Komponente suchen:

 

weapon = GetComponent<Weapon>();

 

Nicht vergessen die weapon Variable auch in den PlayerController einzuführen.

 

Benutzung wäre diesmal in der Update Methode des PlayerControllers so:

 

if (weapon)
{
if (Input.GetKeyDown(KeyCode.Space))
{
	weapon.StartFiring();
}
if (Input.GetKeyUp(KeyCode.Space))
{
	weapon.StopFiring();
}
}

 

Neu ist hier dass wir anstatt Input.GetKey, Input.GetKeyDown und Inout.GetKeyUp verwenden. Im gegensatz zu GetKey wird GetKeyDown nur ein einziges mal true liefern und zwar in dem Frame in dem der Spieler die Taste herunter drückt. GetKeyUp wird ein einziges mal in dem Frame gefeuert in dem der Spieler die Taste wieder los lässt.

 

Nun erstellen wir uns das ProjectileWeapon Script welches von der Weapon Klasse ableitet und die Fire Methode implementiert die dann ein Projektil verschießen soll.

 

Erstellt also ein neues C# Script mit dem Namen ProjectileWeapon. Wenn ihr das Script öffnet sieht dieses noch so aus:

 

using UnityEngine;
using System.Collections;

public class ProjectileWeapon : MonoBehaviour {

// Use this for initialization
void Start () {

}

// Update is called once per frame
void Update () {

}
}

 

Noch hat dieses Script nichts mit dem Weapon Script zu tun von dem es ableiten soll. Ändert daher den Namen "MonoBehaviour" nach den Doppelpunkt unseres Klassennamens zu "Weapon". Ausserdem könnt ihr die Start und Update Methoden entfernen. Wir benötigen diese hier nicht mehr.

 

Das Script sollte nun so aussehen:

 

using UnityEngine;
using System.Collections;

public class ProjectileWeapon : Weapon
{

}

 

Um die ProjectileWeapon Klasse ohne Fehler benutzbar zu machen müssen wir noch die abstracte Fire Methode der Weapon Klasse überschreiben. Dies geht indem wir folgendes in die ProjectileWeapon Klasse schreiben:

 

protected override void Fire()
{

}

 

Das override Keyword gibt an dass wir eine abstrakte Methode implementieren wollen. Das override Keyword hat noch eine weitere Bedeutung auf die wir aber erst eingehen werden wenn es nötig wird.

 

Wir wollen das ein Projektil erzeugt wird wenn wir Fire aufrufen, dafür schauen wir uns ein neues Konzept von Unity an. Die Prefabs. Prefabs steht für pre fabricated, was auf deutsch mit vorbereitetes Objekt gleichzusetzen ist. Wir werden uns nun ein Projektil, einen einfachen Schuss zusammen basteln der einfach nur gerade aus fliegt und nach einer gewissen Zeitspanne oder wenn es etwas getroffen hat, verschwindet. Anschließend wandeln wir dieses Projektil in ein Prefab um.

 

Erstellt in Unity ein neues GameObjekt, eine weitere Cube reicht für den Anfang. Nennt dieses GameObjekt "Projektil" und ändert die Größe des Projektils indem ihr im Inspektor alle 3 Werte der Scale Eigenschaft der Transform Komponente auf 0.1 setzt. Um die Auswirkungen zu sehen könnt ihr das Projektil zur Seite schieben damit es nicht genau in eurem Spieler Raumschiff liegt.

 

Fügt nun eine Rigidbody Komponente hinzu und deaktiviert wieder die "Use Gravity" Checkbox im Inspektor.

 

Nun erstellen wir ein weiteres C# Script um das Projektil zu steuern. Wir nennen das Script "Projectile".

 

Fügt in diesem Script nun eine float Variable hinzu welche angibt wie schnell dieses Projektil fliegen soll:

 

public float StartVelocity = 20.0f;

 

Wir verwenden diese Variable in der Start Methode des Scriptes um die velocity des Rigidbodies damit zu füllen:

 

rigidbody.velocity += StartVelocity * transform.forward;

 

Nachdem die Start Methode aufgerufen wurde wird sich unser Projektil mit konstanter Geschwindigkeit vorwärts bewegen. Für den Anfang reicht uns das.

 

Nun muss noch eingebaut werden dass die Kugel automatisch verschwindet. Dazu fügen wir eine weitere Variable in das Script ein:

 

public float Lifetime = 5.0f;

 

Dieser Wert gibt an wieviele Sekunden unser Projekt lebt bevor es sich selbst zerstört.

 

Fügt nun noch folgende Zeile in die Start Methode hinzu:

 

DestroyObject(gameObject, Lifetime);

 

DestroyObject zerstört ein beliebiges Unity Object, in unserem Fall wollen wir dass das unser GameObject selbst zerstört wird weswegen wir dort gameObject angeben. Wir wollen aber nicht dass unser Projektil sofort verschwindet sondern erst nach der angebebenen Zeitspanne und genau dazu dient der zweite Parameter.

 

Speichert das Script und weist es unserem Projektil GameObject zu. Wenn ihr nun Unity startet seht ihr wie das Projektil wegfliegt und irgendwann aus der Hierarchy Ansicht verschwindet.

 

Das Projektil soll aber auch verschwinden wenn es etwas trifft, also fügen wir nun noch eine weitere Methode hinzu die genau das übernimmt:

 

void OnCollisionEnter(Collision collision)
{
DestroyObject(gameObject);
}

 

OnCollisionEnter wird dann aufgerufen wenn ein Objekt mit einem Rigidboy und Collider ein anderes Objekt mit Collider berührt. Das Script sollte nun so aussehen:

 

using UnityEngine;
using System.Collections;

public class Projectile : MonoBehaviour {

public float StartVelocity = 10.0f;
public float Lifetime = 5.0f;

void OnCollisionEnter(Collision collision)
{
	DestroyObject(gameObject);
}

// Use this for initialization
void Start () {
	rigidbody.velocity += StartVelocity * transform.forward;
	DestroyObject(gameObject, Lifetime);
}

// Update is called once per frame
void Update () {

}
}

 

Es wird Zeit unser Projektil GameObject in ein Prefab umzuwandeln. Erstellt daher zuerst ein leeres Prefab indem ihr im Asset Bereich "Create"->"Prefab" aufruft. Nennt dieses Prefab "Projektil".

 

Noch ies es leer, ändert dies indem ihr euer Projektil GameObject auf das Projektil Prefab zieht. Ihr könnt das GameObjekt anschließend löschen. Klickt nun auf das Prefab und setzt die Rotation und Positions Werte der Transform Komponente auf 0.

 

Das Prefab ist fertig, hässlich aber es funktioniert. Nur wie verwenden wir das Prefab und wozu genau dient es? Wie bereits erwähnt ist ein Prefab eine Art Vorlage. Wir verwenden diese Vorlage als Bestandteil unseres ProjectileWeapon Scriptes. Erweitert daher das Script um eine neue Variable:

 

public GameObject Projectile;

 

Wir hätten anstelle des GameObject Typs auch den Projectile Script typ verwenden können, so aber sind wir nicht darauf angewisen dass unser Prefab auch wirklich ein Projektil ist. Wenn wir Weltraumaffen verschießen wollen können wir das ebenso tun.

 

Erweitert nun die Fire Methode um folgendes:

 

var projectile = (GameObject)Instantiate(Projectile, transform.position, transform.rotation);
projectile.transform.eulerAngles += new Vector3(0, Random.Range(-this.SpreadAngle, this.SpreadAngle), 0);
projectile.rigidbody.velocity = rigidbody.velocity;

Physics.IgnoreCollision(collider, projectile.collider);

 

In der ersten Zeile erzeugen wir ein Klon unseres Prefabs (Projectile) an der Position (transform.position) und Rotation (transform.rotation) und weisen das gecastete Ergebniss einer lokalen Variable zu.

 

Diese lokale Variable, welche ein GameObjekt ist und unseren Klon entspricht werden wir nun etas drehen um die Streuung zu simulieren. Die dritte Zeile sorgt dafür dass unser Projektil mindestens so schnell ist wie unser Raumschiff.

 

Die letzte Zeile sorgt dafür dass unser Geschoss nicht mit der Waffe (dem Raumschiff) kollidiert welches es gefeuert hat.

 

Weist nun das ProjetileWeapon Script unserem Spieler Raumschiff zu und wählt als Projektil im Inspektor unser Projektil Prefab aus.

 

Wenn wir nun die Szene starten und die Leertaste drücken können wir beobachten wie sich viele kleine Projektile auf den Weg machen.

 

Bei den vielen Dingen die jetzt schon gemacht wurden, hier die Szene mit allen Daten als handliches Package:

https://dl.dropboxusercontent.com/u/2446365/ShootEmUpTutorial/Part4.unitypackage

 

Teil 5:

http://forum.unity-c...teil-5-schaden/

Link zu diesem Kommentar
Auf anderen Seiten teilen

Das klingt so als ob du sowohl auf der kugel als auch auf dem Raumschiff ein Script hast welches sich nach einer gewissen Zeitspanne zerstört. Das macht ja eigentlich nur das Projektil Script, schau mal ob das Script auf den GameObjects liegt. Das sollte eigentlich nur auf das Projektik Prefab.

 

Ansonsten schau mal welche Scripte auf der Sphere liegen, eigentlich sollte das nur das Destructable Script sein.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Ich finde es klasse, das Marrrk schon von vorn herein die Scripte so auslegt, das man später es viel einfacher hat um die verschiedensten Waffen zu erstellen und viel Kontrolle über diese hat. :)

 

Für mich, als teilweise noch Anfänger in Sachen Scripten, war dieser Teil teilweise sehr schwer nachzuvollziehen. Jetzt bin ich mit diesem Teil durch und es funktioniert prima. Nur eine Kleinigkeit noch : Bei dem Scripts PlayerController muss oben noch rein : private Weapon weapon; Edit : ( Steht drin, habe ich wohl überlesen^^)

 

Vielleicht entwerfe ich heute Abend noch Modelle für die Projektile, wie ich das schon für die Schiffe gemacht habe, mal sehen. :)

Link zu diesem Kommentar
Auf anderen Seiten teilen

  • 6 months later...

Also ich hab ein Model reingeladen und da tauchten folgende Probleme auf:

 

- Ich habe zwei Waffen, je eine an jedem Flügel. Mit der aktuellen Shoot-Methode im PlayerController wird nur die erste gefundene Waffe abgefeuert. Unten steht der Fix. ;)

 

- Die Waffen brauchen eine Schussposition, ansonsten schiessen sie von der Mitte des Meshs aus.

 

- Mit einem Mesh-Collider auf dem Player Mesh kann es zu seltsamen Rotationen/Fortbewegungsrichtungen kommen, deshalb sollte man im RigidBody die Constraints begrenzen.

 

- Die Kollision sollte Layer-basiert ignorieren (De Facto gings bei mir nicht mit der Tutorial-Methode, weil der Mesh ein Sub-Gameobject ist mit eigenem Mesh-Collider und DEN hat mir das Script nicht erkannt. Desweiteren könnten sich so Schüsse von selbst gegenseitig abschiessen.)

 

Also das unterste zuerst:

 

Layer-basiertes ignorieren:

 

+ Klick oben rechts auf Layers->Edit Layers

+ Gib Layer 8 den Namen "Player" und Nr. 9 den Namen "Player Shot"

+ Im Script "ProjectileWeapon.cs", tausche die Zeile

 

Physics.IgnoreCollision(collider, proj.collider);

 

durch die Zeilen:

 

Physics.IgnoreLayerCollision (8, 9); // Damit die Schüsse den Player ignorieren.
Physics.IgnoreLayerCollision(9,9);  // Damit die Schüsse sich nicht selbst abschiessen können.

 

...eventuell muss man das nur einmal machen in einer globalen Start-Methode...

 

Und nun muss man die Layer noch zuweisen:

Beim Player Prefab oben rechts, direkt unter dem Namen, das Layer auf "Player" stellen.

Beim Projektil Prefab dasselbe machen mit "Player Shot".

Und natürlich, die Prefabs aktualisieren.....

 

Constraints begrenzen:

 

Im Rigidbody Abschnitt des Players hat es eine Linie "Constraints". Wenn man da drauf klickt, tauchen zwei weitere Linien auf:

"Freeze Position" - Y anklicken, damit sich die Höhe des Raumschiffes nicht ändern kann.

"Freeze Rotation" - X UND Z anklicken, das verhindert das Kippen nach vorn oder auf die Seite.

 

Waffenpositionen

 

Erstelle für jede Waffen-Position ein Game-Objekt und bewege es an die richtige Position. Natürlich musst du es noch an den Player anhängen.

 

In "Weapon.cs" erstelle eine neue Variable:

 

public Transform weaponMountPoint;

 

(ich denke, JEDE Waffe braucht eine Position)

 

Nun musst du noch in "ProjectileWeapon.cs" die folgende Zeile ändern:

 

var projectile = (GameObject)Instantiate(Projectile, transform.position, transform.rotation);

 

nach:

 

var projectile = (GameObject)Instantiate(Projectile, weaponMountPoint.position, weaponMountPoint.rotation);

 

Als letztes musst du noch das erstellte Mountpoint-Gameobject auf die neue Variable im Waffen-Script des Players ziehen.

 

Mehrere Waffen

 

Du kannst mehrmals DASSELBE Script an ein GameObject anhängen. Bei mir hat es zwei ProjectileWeapon-Scripts, welche jeweils rechts und links ihren Mountpoint haben.

 

Um nun diese ALLE abzufeuern, muss man nochmal ein bisschen Code ändern:

 

Ich kopiere hier mein komplettes PlayerController-Script rein und erkläre dann, was ich gemacht habe.

 

 

public class PlayerController : MonoBehaviour {

private Drive drive;
private Weapon[] weapon;

// Use this for initialization
void Start () {
  drive = GetComponent<Drive> ();
  weapon = GetComponents<Weapon> ();
}

// Update is called once per frame
void Update () {
  if (drive) {
  if (Input.GetKey (KeyCode.UpArrow)) {
	  drive.Accelerate (1.0f);
  }
  if (Input.GetKey (KeyCode.DownArrow)) {
	drive.Deaccelerate (1.0f);
  }
  if (Input.GetKey (KeyCode.RightArrow)) {
	  drive.RotateRight (1.0f);
  }
  if (Input.GetKey (KeyCode.LeftArrow)) {
	  drive.RotateLeft (1.0f);
  }
  }

  if (weapon.Length>0)
  {
  if (Input.GetKeyDown(KeyCode.Space))
  {
	 foreach(Weapon w in weapon)
		 w.StartFiring();
   }
   if (Input.GetKeyUp(KeyCode.Space))
   {
	   foreach(Weapon w in weapon)
		  w.StopFiring();
   }
  }
}
}

 

 

Anstatt einer einzelnen Waffe wird ein Array erstellt.

private Weapon[] weapon;

 

Mit GetComponents ("s" am Ende) kann man nun alle Waffen-Scripts dort rein laden.

 

Anstatt zu prüfen ob die weapon "ist", prüfen wir, ob das Array mehr als null Einträge hat.

 

Beim Feuern wird durch das gesamte Array gegangen und jede Waffe darin abgefeuert.

 

PS: Bei "if" und "foreach" muss man KEINE Klammern setzen, wenn man nur EIN Kommando darunter schreibt.

Das nächste Kommando wird ganz normal ausgeführt (ohne if/foreach).

 

Ich hoffe das hilft. Mir jedenfalls schon. ;)

Link zu diesem Kommentar
Auf anderen Seiten teilen

Gut aufgepasst, aaaaaber: In Teil10 wird das behandelt ;)

 

http://forum.unity-c...10-waffenslots/

 

achso...okei, sorry für den spoiler ;)

 

Nehmt bloss keine Mesh-Collider für den Kram, die kollidieren aus Performance-Gründen nicht miteinander. Ausser du willst, dass die Schiffe durcheinander fliegen können. Baut euch ein "ähnliches" Gerüst mit Box/Sphere und Capsule-Collidern.

 

Mesh <-> Mesh = Geht Nicht

Mesh <-> Box/Sphere/Capsule = Geht

Box/.. <-> Box/.. = Geht

Link zu diesem Kommentar
Auf anderen Seiten teilen

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Gast
Auf dieses Thema antworten...

×   Du hast formatierten Text eingefügt.   Formatierung jetzt entfernen

  Only 75 emoji are allowed.

×   Dein Link wurde automatisch eingebettet.   Einbetten rückgängig machen und als Link darstellen

×   Dein vorheriger Inhalt wurde wiederhergestellt.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Lädt...
×
×
  • Neu erstellen...