Jump to content
Unity Insider Forum
Mark

Wir bauen uns ein Space Shoot em Up [Teil 3 - Antrieb]

Recommended Posts

Zeit für etwas Umbauarbeiten, bisher haben wir einen PlayerController der etwas mehr macht als nur zu kontrollieren. Schwer zu glauben bei nur 43 Zeilen nicht wahr?

 

Schauen wir uns einmal an was unser PlayerController so macht, er reagiert auf Tastendrücke vom Spieler und verändert direkt dadurch die Geschwindigkeit und Richtung unseres Raumschiffes. Das sind 2 verschiedene Aufgabenbereiche die wir trennen sollten. Um anschließend die Stärke des von Unity uns auferlegten Komponentensystemes auszuspielen. Wiederverwendbarkeit!

 

Unser PlayerController Script sollte wie der Name schon impliziert nur dafür zuständig sein die Eingaben des Spielers auszuwerten und das was dann damit gemacht werden sollte an andere Komponenten übergeben. Deswegen die Zweiteilung des Scriptes.

 

Ein Teil wird die Eingaben entgegen nehmen, dies bleibt unser PlayerController und der andere Teil wird die Geschwindigkeit und Drehung des Schiffs kontrollieren.

 

Wir fangen an indem wir uns ein neues C# Script erstellen und es "Drive" (Antrieb) nennen.

 

Für unsern Antrieb, welchen wir später wiederverwenden werden (zB für gegnerische Raumschiffe) benötigen wir folgende Dinge:

- Beschleunigen (Accelerate)

- Abbremsen (Deaccelerate)

- Drehen

 

Und um die Steuerung leichter zu machen fügen wir noch etwas hinzu:

- Automatisches abbremsen

 

Automatisches abbremsen ist eine passive Eigenschaft unseres Scriptes, bedeutet das wir es nicht extra aufrufen müssen damit es funktioniert.

 

Wir beginnen daher damit dass wir uns einige Basiselemente vom PlayerController nehmen und diese im Drive Script einfügen. Und zwar alle Elemente die direkt den Antrieb des Schiffes betreffen. Was so ziemlich alle Variablen des PlayerController Scriptes wären:

 

public float Acceleration = 1000.0f;
public float Deacceleration = 1000.0f;
public float RotationAcceleration = 300.0f;

public float MaxForce = 1000.0f;
public float MinForce = -500.0f;
public float CurrentForce = 0.0f;

 

Dies sollte im Drive Script stehen und nicht im PlayerController Script.

 

Nun legen wir mit der ersten Fähigkeit unseres Drive Scriptes los:

Beschleunigen!

 

Erstellt eine neue Methode mit dem Namen Accelerate welche einen zusätzlichen float Parameter entgegen nimmt. Dieser Parameter soll dazu dienen fein zu regeln wie sehr wir beschleunigen wollen. Da wir bisher selbst noch keinerlei Parameter in selbst geschriebenen Methoden benutzt haben, hier die Methode:

 

public void Accelerate(float factor)
{

}

 

Wir benutzen hier so wie bei den Variablen ein public direkt vor der Methode. Da wir diese Methode von dem PlayerController Script aufrufen wollen muss diese public sein (öffentlich erreichbar).

 

Wer nun ein wenig aufgepasst hat weiß auch was ungefähr in diese Methode hinein muss. Den Part vom PlayerController Script welcher ausgeführt wird wenn wir die nach Oben Taste drücken:

 

CurrentForce += Time.deltaTime * Acceleration;

 

Wir müssen noch unseren factor verwenden, wir verwenden ihn indem wir alles rechts von += mit dem factor multiplizieren.

 

CurrentForce += Time.deltaTime * Acceleration * factor;

 

Genau das Gleiche erledigen wir für die Deaccelerate Methode:

 

public void Deaccelerate(float factor)
{
CurrentForce -= Time.deltaTime * Deacceleration * factor;
}

 

Wenn ihr euch noch daran erinnert haben wir im PlayerController Script eine Begrenzung der CurrentForce eingebaut, bisher machen wir dies immer egal ob wir Beschleunigt haben oder Abgebremst haben. Diesen kleinen Fehler können wir beheben indem wir die Stelle welche die Begrenzung aufrechterhält, nach Accelerate und Deaccelerate überträgt. Als Beispiel, so sollte die Accelerate Methode nach dieser Ergänzung aussehen:

 

public void Accelerate(float factor)
{
CurrentForce += Time.deltaTime * Acceleration * factor;
CurrentForce = Mathf.Clamp(CurrentForce, MinForce, MaxForce);
}

 

Nun haben wir die Beschleunigung und Abbremsung, aber etwas Kleines fehlt hierbei noch, wir wollen ja eine automatische Abbremsung wenn weder beschleunigt als auch abgebremst wurde. Aus diesem Grund merken wir uns wenn eines dieser beiden Aktionen ausgeführt wurde. Dazu erstellen wir uns zuerst eine neue Variable für das Drive Script:

 

private bool hasChangedCurrentForce = false;

 

Wir ihr bemerkt habt ist diesmal ein private vor dem Typ und kein public. Dies liegt daran dass wir nicht wollen dass diese Variable ausserhalb des Scriptes Bedeutung hat und auch nicht angefasst werden soll. private bedeutet dass die Variable oder Methode nur im inneren der Klasse in der es definiert wurde verwendet werden kann.

 

Wir setzen hasChangedCurrentForce auf true immer dann wenn wir Accelerate oder Deaccelerate verwenden:

 

hasChangedCurrentForce = true;

 

Fügt diese Zeile in beide Methoden ein.

 

Nun fehlt nur noch das Drehen, dies können wir lösen indem wir uns 2 Methoden, für jede Richtung in die wir drehen können wollen eine, einfügen.

Wie bei Accelerate und Deaccelerate benutzen wir einen factor Parameter. Und wie zuvor übernehmen wir zu aller erst den Inhalt aus dem PlayerController Script welche für die Drehungen zuständig waren:

 

public void RotateRight(float factor)
{
rigidbody.AddTorque(0, Time.deltaTime * RotationAcceleration * factor, 0);
}

public void RotateLeft(float factor)
{
rigidbody.AddTorque(0, -Time.deltaTime * RotationAcceleration * factor, 0);
}

 

Das wars. Die Drehung wurde eingebaut und sollte funktionieren.

 

Was nun noch fehlt ist die automatische Abbremsung und die Anwendung der CurrentForce. Der letzte Part ist der einfachste, da wir auch hier direkt den Code aus dem PlayerController übernehmen können. Daher kopiert die notwendige Zeile und fügt sie in die Update Methode des Drive Scriptes ein:

 

void Update ()
{
rigidbody.AddForce(CurrentForce * Time.deltaTime * transform.forward);
}

 

Nun zum letzten Feature des Scriptes, die automatische Abbremsung. Da wir am Anfang des Tutorials klar gestellt haben wann dies einsetzen soll und zwar nur dann wenn weder beschleunigt noch abgebremst wurde, können wir bereits die ersten Zeilen dafür schreiben (wieder in die Update Methode):

 

if (!hasChangedCurrentForce)
{

}

 

Wir setzen hasChangedCurrentForce immer auf true wenn wir beschleunigen oder abbremsen.

Nach der Prüfung sollten wir daher die Variable wieder auf false setzen. Schreibt dies direkt unter den if Scope:

 

hasChangedCurrentForce = false;

 

Wie soll nun aber die automatische Abbremsung funktionieren? Ganz einfach, wir schauen uns die Richtung an in der unser Raumschiff schaut (transform.forward) und vergleichen dies mit der Richtung und Geschwindigkeit in der wir uns bewegen (rigidbody.velocity). Wir benutzen dazu die Vector3.Dot Methode welche uns einen Wert liefert den wir benutzen werden um zu entscheiden ob wir Beschleunigen müssen (wenn wir rückwärts fliegen) oder Abbremsen müssen (wenn wir vorwärts fliegen).

 

Tragt dazu folgendes in den if Scope für die automatische Abbremsung ein:

 

var forwardFactor = Vector3.Dot(transform.forward, rigidbody.velocity);

 

Diesen forwardFactor verwenden wir nun für die Entscheidung was gemacht werden soll:

 

if (forwardFactor > 1.0f)
{
Deaccelerate(1.0f);
}
else if (forwardFactor < -1.0f)
{
Accelerate(1.0f);
}
else
{
CurrentForce = 0;
}

 

Das if Keyword kennen wir ja bereits, neu sind dagegen das else if und das else. else if wird aufgerifen wenn das vorherige if oder ein vorheriges else if selbst nicht erfüllt werden konnten. else if bietet also einen alternativen Weg an. Sollten auch alle folgenden else if scheitern so wird der Code im else Scope ausgeführt. if, else if und else können also übersetzt werden mit: Wenn X dann Y, Ansonsten Wenn Z dann W, Ansonsten R.

 

Um einen Ping Pong Effekt zu vermeiden interessieren wir uns nur forwardFactor wenn er größer 1 oder kleiner -1 ist, im anderen Fall lassen wir den Luftwiederstand für uns arbeiten, den es im Weltraum zwar nicht gibt, aber für das Spielgefühl dennoch zuträglich ist. Wir stellen daher den "Drag" Wert in der "Rigidbody" Komponente des Spieler Raumschiffs auf 1. Dies sorgt dafür dass wir wenn wir keine Kraft auf unser GameObject auswirken, dieses GameObjekt immer langsamer wird.

 

Unser Drive Script ist damit fertig. Zur Vollständigkeit halber, hier das Drive Script:

 

using UnityEngine;
using System.Collections;

public class Drive : MonoBehaviour {

public float Acceleration = 1000.0f;
public float Deacceleration = 1000.0f;
public float RotationAcceleration = 300.0f;

public float MaxForce = 1000.0f;
public float MinForce = -500.0f;
public float CurrentForce = 0.0f;

private bool hasChangedCurrentForce = false;

// Use this for initialization
void Start () {

}

// Update is called once per frame
void Update ()
{
	rigidbody.AddForce(CurrentForce * Time.deltaTime * transform.forward);

	if (!hasChangedCurrentForce)
	{
		var forwardFactor = Vector3.Dot(transform.forward, rigidbody.velocity);

		if (forwardFactor > 1.0f)
		{
			Deaccelerate(1.0f);
		}
		else if (forwardFactor < -1.0f)
		{
			Accelerate(1.0f);
		}
		else
		{
			CurrentForce = 0;
		}
	}
	hasChangedCurrentForce = false;
}

public void Accelerate(float factor)
{
	CurrentForce += Time.deltaTime * Acceleration * factor;
	CurrentForce = Mathf.Clamp(CurrentForce, MinForce, MaxForce);
	hasChangedCurrentForce = true;
}

public void Deaccelerate(float factor)
{
	CurrentForce -= Time.deltaTime * Deacceleration * factor;
	CurrentForce = Mathf.Clamp(CurrentForce, MinForce, MaxForce);
	hasChangedCurrentForce = true;
}

public void RotateRight(float factor)
{
	rigidbody.AddTorque(0, Time.deltaTime * RotationAcceleration * factor, 0);
}

public void RotateLeft(float factor)
{
	rigidbody.AddTorque(0, -Time.deltaTime * RotationAcceleration * factor, 0);
}
}

 

Nun müssen wir es nur noch benutzen. Auf auf zum PlayerController Script, welches nun so aussehen sollte:

 

using UnityEngine;
using System.Collections;

public class PlayerController : MonoBehaviour {

// Use this for initialization
void Start () {
}

// Update is called once per frame
void Update () {
if (Input.GetKey(KeyCode.UpArrow))
{

}
if (Input.GetKey(KeyCode.DownArrow))
{

}
if (Input.GetKey(KeyCode.RightArrow))
{
}
if (Input.GetKey(KeyCode.LeftArrow))
{
}
}
}

 

Dieses Script wird unser Drive Script benutzen, daher sollten wir uns dieses Drive Script auch suchen. Fügt daher eine neue Variable in das PlayerController Script hinzu:

 

private Drive drive;

 

private deswegen weil es nur für die Internas des PlayerController Scriptes von Relevanz ist.

 

Wir weisen diese Variable innerhalb der Start Methode zu:

 

drive = GetComponent<Drive>();

 

GetComponent sucht eine Komponente, welche Komponente geben wir über einen generischen Parameter an. Die spitzen Klammern (< und >) umgrenzen die generischen Parameter. Generische Parameter sind immer Typen, mit GetComponent<Drive>() sagen wir demnach dass wir eine Komponente an unserem GameObjekt suchen welche vom Drive Typ ist. Alternativen zu dieser Variante eine Komponente zu suchen gibt es ebenfalls, entweder per Namen der Komponente (GetComponent("Drive")) oder wieder über den Typen der Komponente (GetComponent(typeof(Drive))).

 

Wir benutzen die generische Variante, weil es automatisch einen Fehler gibt wenn es den Typen nicht gibt (zB: ein anderen Namen hat) was bei GetComponent("Drive") keinen Fehler geben würde. Ausserdem hat sie den Vorteil besser lesbar zu sein als GetComponent(typeof(Drive)). Ausserdem bekommen wir direkt als Rückgabetyp unser Drive zurück. Bei allen anderen Varianten müssen wir anschließend den Rückgabewert erst umwandeln, was wieder mehr Schreibarbeit bedeutet und auch unlesbarer wäre, vergleicht selber:

 

drive = GetComponent<Drive>();

 

vs:

 

drive = (Drive)GetComponent(typeof(Drive));

 

Fügt nun die Verwendung unseres Drive Scriptes in die Update Methode ein:

 

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);
}
}
}

 

Wie man vermutlich gut sehen kann haben wir eine weitere if Bedingung eingefügt:

 

if (drive)

 

Damit können wir testen ob unsere Drive Komponente eventuell nicht gefunden oder gar gelöscht wurde. Das fertige PlayerController Script sollte nun so aussehen:

 

using UnityEngine;
using System.Collections;

public class PlayerController : MonoBehaviour {

private Drive drive;

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

// 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);
		}
	}
}
}

 

Startet nun wieder die Szene in Unity und schaut wie sich das ganze nun verhält. Abseits vom automatischen Abbremsen sollte sich alles wie gehabt verhalten.

 

Feedback ist wiederum gern gesehen.

 

PS: Das Forum macht mir immer die Tabs im Code kaputt ;(

 

Teil 4:

http://forum.unity-community.de/topic/7112-wir-bauen-uns-ein-space-shoot-em-up-teil-4-waffen/

  • Like 8

Share this post


Link to post
Share on other sites

Uff, das war schon um einiges schwieriger als die ersten Teile, musste einige Sachen mehrmals durchlesen, da ich das auf Anhieb nicht gecheckt habe, aber Du hast auch alles gut erklärt, Danke.

im anderen Fall lassen wir den Luftwiederstand für uns arbeiten, den es im Weltraum zwar nicht gibt, aber für das Spielgefühl dennoch zuträglich ist.

Sehr schön, diesen "Luftwiderstand" könnte man also auch anpassen, also gemäß Einstein eine kosmische Konstante einbauen. :D

Also falls man unterschiedliche Level oder Levelareas erstellt, in denen dieser "Widerstand" anders ist. Finde ich gut. :)

 

Ich musste am Ende noch das Drive Script dem Raumschiff anhängen, glaube im Text steht das noch nicht drin.

Also das mit dem Abbremsen funktioniert hervorragend! :)

Meine aktuellen Werte im Inspection für Acceleration, Deacceleration, Min und Max sind jeweils auf 200, bzw. -200 und Rotation auf 100, damit das Raumschiff nicht so hastig reagiert. Aber das kann jeder für sich selber einstellen.

Share this post


Link to post
Share on other sites

Hi,

erstmal danke für dieses wunderbare Tutorial, hilft ungemein weiter um den Umgang mit Unity3D zu lernen.

 

Folgenes Problem hat sich derzeit ergeben, bekomme es irgendwie nicht gebacken das mein Raumschiff stehenbleibt nachdem es beschleunigt hat.

CurrentForce geht zwar runter bis minForce (bremst), geht kurz danach auf 0 und das Raumschiff fliegt trotzdem langsam weiter.

Hab auch schon versucht dein ScriptPackage aus den folgenden Tut's zu verwenden aber der Fehler bleibt bestehen.

Zufällig ne Idee woran das liegen kann ?

 

 

Edit: Lol *mich selbst facepalme* ^^

Fehler gefunden, hatte iwie vergessen den Dragwert von RigidBody auf 1 zu setzen, fiel mir in dem mom auf als ich beim Post abschicken das vorherige Zitat gelesen habe.

Naja dann mal weiter bis zum nächsten Problem xD

  • Like 1

Share this post


Link to post
Share on other sites

Hi,

 

ich habe ein kleines Verständnisproblem:

 

In der Accelerate-Methode wird Time.deltatime benutzt, um die neue CurrentForce zu berechnen. Bei der Anwendung der CurrentForce in der Update-Funktion wird die Deltatime dann nochmal berücksichtigt. Gibts dafür einen Grund?

 

Alex

Share this post


Link to post
Share on other sites

Accellerate verändert kontinuierlich die Beschleunigung, damit da nicht krasse Frame abhängige Sprünge entstehen bei der Beschleunigungs wird deltaTime verwendet.

 

Das gleiche beim anwenden der Beschleunigung. Man kann beim Accellerate auch deltaTime weglassen, dann dürfte man aber keine kontinuierliche Beschleunigung haben und müsste in Absoluten rechnen.

 

Probiere es aus und nehme was dir besser gefällt :)

Share this post


Link to post
Share on other sites

Beim Accelerate ist die Deltatime natürlich sinnvoll, das ist klar. Aber die CurrentForce ist nach Accelerate ja bereits "gedeltatimed", so dass eine erneute Anwendung in Update meines Erachtens doppelt gemoppelt ist. Ich habs in Update weggelassen:

 

void Update (
{
// rigidbody.AddForce(CurrentForce * Time.deltaTime * transform.forward)
rigidbody.AddForce(CurrentForce  * transform.forward);
if (!hasChangedCurrentForce)
	...

 

In der Funktionsweise kann ich keinen Unterschied erkennen, nur die Beschleunigung muss angepasst werden. Das meinte ich.

 

Alex

Share this post


Link to post
Share on other sites

Dann würde es aber passieren dass die Force Frametime unabhängig angewandt wird, stell dir vor das Spiel läuft nun mit 60FPS bei dir und mit 30FPS bei jemand Anderem. Der mit 30FPS hätte das langsamere Raumschiff.

Share this post


Link to post
Share on other sites

Ich habe mich wohl missverständlich ausgedrückt, entschuldige bitte. Ich meinte das hier:

 

 

public void Accelerate(float factor)
{
CurrentForce += Time.deltaTime * Acceleration * factor; // erste deltatime
CurrentForce = Mathf.Clamp(CurrentForce, MinForce, MaxForce);
}

Hier in Accelerate wird die CurrentForce bereits mit der deltaTime berechnet, ist also abhängig von der vergangenen Zeit.

 

void Update ()
{
rigidbody.AddForce(CurrentForce * Time.deltaTime * transform.forward); // zweite deltatime
}

DIe Updatefunktion multipliziert die bereits zeitbereinigte CurrentForce nochmals mit deltaTime. Das ist mMn doppelt gemoppelt und was du bisher geschrieben hast, hat es mir noch nicht hinreichend erklärt. Dein letzter Post deutet an, dass die Force nur im Update deltabereinigt wird, das ist aber nicht der Fall, so weit ich das sehe.

 

Alex

Share this post


Link to post
Share on other sites

Naja das eine erhöht CurrentForce, das andere verwendet CurrentForce. Ich sehe da kein Problem dabei.

Share this post


Link to post
Share on other sites

Naja das eine erhöht CurrentForce, das andere verwendet CurrentForce. Ich sehe da kein Problem dabei.

Alles klar, ich gebe auf ;). Vielen Dank für deine Geduld.

 

Alex

Share this post


Link to post
Share on other sites

Wenn ich mich kurz reinhängen darf:

Man muss auch die Erhöhung der Force mit der deltaTime multiplizieren, da sonst je nach Rechnerleistung unterschiedliche Erhöhungen entstehen würden.

Die deltaTime ist die Zeit, die zwischen dem letzten und dem jetzigen Frame vergangen ist und da bei langsamen Systemen weniger Frames pro Sekunde gezeigt werden als bei schnellen, ist die deltaTime bei langsamen Systemen höher.

 

In die Funktion Acellerate wird rein gesprungen, wenn in der Update erkannt wird, dass eine Taste gedrückt wird. Somit ist die Funktion ein Teil der Updatefunktion, die einmal pro Frame ausgeführt wird.

Drückt jetzt jemand die Acc. Taste und hat einen schnellen Rechner dann würde vielleicht 200 Mal pro Sekunde die Force angehoben werden. Bei einem langsamen Rechner aber nur 60 Mal. Und damit die Force auf allen Systemen gleich stark geändert wird, muss auch dort die deltaTime eingebunden werden.

Und natürlich muss das hinzufügen der Force in der Update dann nocheinmal mit der deltaTime multipliziert werden, weil es ist ja ein Add und kein Set!

Also beim Einen wird ein Wert verändert (mit deltaTime, damit die Änderung überall gleich groß ist) und beim Anderen wird dieser veränderte Wert übergeben (wieder mit deltaTime, damit überall die gleiche Kraft hinzugefügt wird).

  • Like 1

Share this post


Link to post
Share on other sites

Wenn ich mich kurz reinhängen darf:

Man muss auch die Erhöhung der Force mit der deltaTime multiplizieren, da sonst je nach Rechnerleistung unterschiedliche Erhöhungen entstehen würden.

Die deltaTime ist die Zeit, die zwischen dem letzten und dem jetzigen Frame vergangen ist und da bei langsamen Systemen weniger Frames pro Sekunde gezeigt werden als bei schnellen, ist die deltaTime bei langsamen Systemen höher.

 

In die Funktion Acellerate wird rein gesprungen, wenn in der Update erkannt wird, dass eine Taste gedrückt wird. Somit ist die Funktion ein Teil der Updatefunktion, die einmal pro Frame ausgeführt wird.

Drückt jetzt jemand die Acc. Taste und hat einen schnellen Rechner dann würde vielleicht 200 Mal pro Sekunde die Force angehoben werden. Bei einem langsamen Rechner aber nur 60 Mal. Und damit die Force auf allen Systemen gleich stark geändert wird, muss auch dort die deltaTime eingebunden werden.

Und natürlich muss das hinzufügen der Force in der Update dann nocheinmal mit der deltaTime multipliziert werden, weil es ist ja ein Add und kein Set!

Also beim Einen wird ein Wert verändert (mit deltaTime, damit die Änderung überall gleich groß ist) und beim Anderen wird dieser veränderte Wert übergeben (wieder mit deltaTime, damit überall die gleiche Kraft hinzugefügt wird).

HA! Na wer sagts denn? Jetzt hab ichs auch kapiert. Accelerate wird ja nur ausgeführt, wenn die Taste gedrückt wird.

Vielen Dank für die Klarstellung, Malzbie! Und vielen Dank für die Mühe, die ich euch gemacht habe^^

 

Alex

Share this post


Link to post
Share on other sites

Vermutlich aus Gewohnheit. HAst natürlich recht damit dass alle Physik ändernden Elemente nach FixedUpdate gehören sollten.

Share this post


Link to post
Share on other sites

Hi,

klasse Tutorial!

Allerdings habe ich grade ein Problem, mit dem irgendwie nicht klar komme:

Meine "Drive"-Variable im PlayerController-Script wird nicht initialisiert und ich komme einfach nicht dahinter,

warum...

 

Meine Scripte soweit:

using UnityEngine;
using System.Collections;
public class PlayerController : MonoBehaviour {
private Drive _drive;

// Use this for initialization
void Start () {
_drive = GetComponent<Drive>();
if (!_drive) {
print ("Konnte _drive nicht initialisieren");
}
}

// Update is called once per frame
void Update () {
//print ("PlayerController 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);
}
}
}
}

 

Im "Start"-Event ist "!_drive" true. Warum ? Die Klasse "Drive" existiert und ich bekomme auch keine andere Fehlermeldung.

 

Bin für jeden Tip dankbar.

 

Gruß

Share this post


Link to post
Share on other sites

Du musst das Drive Script wie jede andere Komponente die du per GetComponent finden möchtest auf dein GameObjekt legen. So wie du es mit dem PlayerController gemacht hast.

Share this post


Link to post
Share on other sites

Du musst das Drive Script wie jede andere Komponente die du per GetComponent finden möchtest auf dein GameObjekt legen. So wie du es mit dem PlayerController gemacht hast.

 

Hi,

danke, das hat noch gefehlt

Share this post


Link to post
Share on other sites

echt tolle sache, macht freude wenn man etwas schafft.

Eine Frage habe ich da mal, wie muß ich das ändern damit das Raumschiff immer sofort in die Richtig fliegt in der es sich dreht?

Im moment fliegt es gerde aus und wenn ich es drehe fliegt es in die gleiche richtung weiter.

Share this post


Link to post
Share on other sites

Trägheit, du kannst das aber verändern indem du mit dem Drag Wert im Rigidbody herumspielst, ein höherer Wert sorgt dafür dass das raumschiff schneller abbremst und damit auch nicht so lang in die gleiche Richtung fliegt. Ansonsten natürlich auch noch die Max Geschwindigkeit und Beschleunigung anpassen.

Share this post


Link to post
Share on other sites

Ich möchte, dass das Raumschiff realistisch im Weltraum herum fliegt. Dazu habe ich einen bool autoBrake, welcher das automatische Bremsen abschalten soll. Leider geht das nicht wie gewünscht: (Wie in einem späteren Kommentar beschrieben:) Die Partikel-Engines feuern die ganze Zeit, das sollen sie aber nicht. Das Raumschiff soll nur die ursprüngliche Richtung und Geschwindigkeit beibehalten bzw an die neue anpassen.

 

Dazu bräuchte es einen Richtungs-Vektor, richtig?

 

Weiss jemand, wie man den berechnet unter Einbeziehung der currentForce bzw. der alten Richtung und OHNE Input-"Befehle"?

 

Also das Ziel ist, dass ich mit dem Raumschiff drehen und schiessen kann, ohne dass die Geschwindigkeit in der ursprünglichen Richtung abnimmt und ohne dass die Partikel-Engines feuern...also die ursprüngliche Richtung/Geschwindigkeit sollte soweit ohne "Accelerate", "DeAccelerate" und "RotateX" auskommen - hier sind die Partikel-Engines eingelinkt.

 

Hat da jemand eine Lösung parat?

Share this post


Link to post
Share on other sites

rigidbody.velocity

 

gibt dir die Geschwindigkeit als Vector3 wieder und enthält damit auch die Flugrichtung (velocity.normalized). Reicht dir das denn aus?

Share this post


Link to post
Share on other sites

rigidbody.velocity

 

gibt dir die Geschwindigkeit als Vector3 wieder und enthält damit auch die Flugrichtung (velocity.normalized). Reicht dir das denn aus?

 

Mal gucken, danke.

 

Ich weiss grad nicht genau, wie ich das implementieren soll.

 

 

vector3 newDir=rigidbody.velocity + currentForce*Time.deltaTime*transform.forward ????
rigidbody.AddForce(newDir) ????

und wenn jetzt zb. x =+1 ist bei beiden Vektoren, wie verhindere ich, das x>1 (unerwünscht) wird aber trotzdem currentForce einbezogen?

 

(ach, wenn ich doch grad den Developer-Lappi hier hätte...)

Share this post


Link to post
Share on other sites

Kannst du nochmal genau erklären was du erreichen willst?

 

Also: currentForce arbeitet mit Vector3.forward - d.h. wirkt immer in die Blickrichtung des Schiffes.

Das ist schon gut so, denn das ist ja die force für die Engines.

 

Wenn ich jedoch das Schiff im Weltraum drehe, ohne Gas zu geben (currentForce=0 bzw. Alle Thruster Off) soll es sich in der ursprünglichen Richtung weiterbewegen, in welche es zuletzt geflogen ist.

 

Süd: Vollgas

Dann kein Gas, autobrake=off (wenn möglich) bzw. currentForce = 0 - > hier bremst das Schiff glaub ich schon ab, oder nicht?

Dann drehen nach Nord, zum Feind hin und drauflos ballern - während man halt immer noch nach Süd driftet.

 

Wie im Weltraum halt, wo ein Ding ohne Gegendruck ewigs weiterfliegt...und die Thruster sind der Gegendruck, doch mit currentForce fliegt das Ding NUR gerade aus.

 

Wenn ich erst nach West geflogen bin und dann nach Norden Gas gebe, sollte das Ding nach NordWesten fliegen - kurz gesagt. ;)

Share this post


Link to post
Share on other sites

Join the conversation

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

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

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

Loading...

×
×
  • Create New...