Sascha Geschrieben 15. August 2011 Melden Share Geschrieben 15. August 2011 Dieses Tutorial beschäftigt sich mit der Entwicklung eines Scripts zur Steuerung eines CharacterControllers für ein Jump'n'Run mit 2D-Gameplay. Kurz gesagt: Links/Rechts/Springen und Schwerkraft. Dieses Tutorial setzt voraus, dass die ersten drei Scripting-Tutorials gelesen wurden, damit die Grundlagen des Scriptens vorhanden sind. Ich benutze weiterhin JavaScript in diesem Tutorial. Anmerkung zum Üben: Die Script-Zwischenstände sind dieses Mal, insbesondere im späteren Teil, meistens in Spoiler-Tags, also versteckt. Versucht, beim Durcharbeiten des Tutorials, diese Spoiler nicht anzuklicken, sondern selbst zu programmieren. Geht irgendetwas schief, versucht es zu lösen, klappt das nicht, schaut nach. Wenn ihr das schafft, trainiert es das Programmieren ohne Skriptbeispiele. Viel Spaß und Erfolg! Scripten in der Praxis - Der CharacterController Heute widmen wir uns einmal einer Komponente in Unity, die, wenn ein Script dafür erstellt werden soll, vielen Scripting-Einsteigern einen Schauer über den Rücken laufen lässt: Dem CharacterController. Die Standard-Scripts zur Steuerung dieser Komponente sind zwar ausreichend, wenn man eine Welt baut und diese ingame ansehen will, aber in den meisten Fällen behindern sie einen, das gewünsche Gameplay zu erstellen. Darum programmieren wir jetzt selbst. Wann benutzen? Der CharacterController und der Rigidbody sind die einzigen beiden Komponenten, die es ermöglichen, Körper durch den Raum zu bewegen, sodass sie mit anderen Objekten kollidieren können, und nicht einfach hindurch gehen. Beide haben dabei unterschiedliche Anwendungsfelder, und es ist von der Anwendung abhängig, welche der beiden Komponenten man benutzen sollte. Faustregel: Der Rigidbody ist für Physikobjekte, sie sich physikalisch korrekt verhalten sollen: Rollende Bälle, fallende Kisten, Fahrzeuge. Rigidbodys haben Masse und Trägheit imlpementiert und werden jeden FixedFrame von der PhysikEngine beeinflusst, es sei denn, sie "schlafen". Der CharacterController dagegen ist, wie der Name schon andeutet, für Charaktere, also Menschen konzipiert, ist aber in den meisten Fällen für alle Arten von Lebewesen geeignet. Ein CharacterController kann nicht gekippt werden, "rollt" nicht "aus" und bewegt oder dreht sich nur, wenn man es will, was parallel steht zu "wenn die Spielfigur es will". Spielt man also nicht gerade ein Murmel, sondern eine Figur, sollte dieser per CharacterController realisiert sein. Zur Komponente Jetzt klären wir erst einmal: Was ist der CharacterController überhaupt? Die Scripting Reference fasst es ganz gut zusammen: Es ist eine Unterart eines Colliders Er bewegt sich nur, wenn man die Move()-Funktion benutzt Er beachtet dabei Kollisionen Aus 1. ergibt sich: Ein GameObject kann nur einen CharacterController oder einen normalen Collider haben, weil es immer nur einen Collider pro GameObject geben kann und der CharacterController selbst einer ist. Ausserdem bedeutet es: Andere Objekte werden mit dem CharacterController kollidieren können. 2. bedeutet: Der CharacterController hat keine Gravitation und keine Trägheit. Wenn man ihm sagt, bewege dich drei Meter weit, dann bewegt er sich drei Meter weit. Sagt man es nicht, bewegt er sich nicht. 3. schränkt das ein: Kollidiert der CharacterController während das Move()-Aufrufs mit einem anderen Collider, so bewegt er sich nicht weiter in diese Richtung. 2. ist allerdings nicht ganz richtig: Man kann ein CharacterController-GameObject auch über seine Transform-Komponente bewegen - in diesem Fall gibt es aber wieder keine Kollisionen! Zusammenfassend müssen wir also nur einen schönen Vektor finden, der sich vermutlich aus dem Input ergibt, und dann Move() mit diesem Vektor aufrufen. Alles bereit Wir erstellen uns jetzt am besten eine kleine Scene, die wie folgt aussieht: Ein paar Cubes, ein Licht, eine Kamera, die eine Rotation von (0,0,0) hat, und eine Kapsel (GameObject => Create Other => Capsule). Keine Prefabs aus den Standard Assets! Die Spielwelt erstreckt sich auf der x-Achse, da sich der Controller auf dieser Achse bewegen wird. Die Kapsel sollte den Boden nicht berühren, da der CharacterController einen kleinen Mindestabstand braucht. Jetzt die Kapsel markieren und über "Component => Physics => Character Controller" einen CharacterController hinzufügen. Da die Kapsel schon einen Capsule Collider hat, muss dieser ersetzt werden, bei der erscheinenden Meldung also "Replace" anklicken. Wie man sieht, hat der CharacterController exakt die selbe Form wie der Capsule Collider. Diese Form ist nämlich für alle aufrecht gehenden Lebewesen gut geeignet und hat auch weitere Vorteile. Dazu später mehr. Los geht's Fangen wir jetzt also mit einem neuen Skript an: function Update() { } Wir fügen eine private Variable hinzu, die die Referenz auf die CharacterController-Komponente halten soll, sodass wir darauf zugreifen können. Diese Referenz holen wir uns in Awake() mit GetComponent(): private var controller : CharacterController; function Awake() { controller = GetComponent(CharacterController); } function Update() { } Wir holen uns die Referenz schon am Anfang, damit wir GetComponent() nur einmal und nicht in jedem Frame aufrufen müssen, weil es keine sehr performante Funktion ist. Wir machen das in Awake() und nicht in Start(), weil Awake() gerade für solche Referenzzuweisungen sind; Start() dagegen ist für erste Aktionen, die z.T. fertige Referenzzuweisungen benötigt. Wenn z.B. ein anderes Skript beim Start auf "controller" zugreifen wollen würde, würden wir so sicherstellen, dass controller auch schon gesetzt ist, weil alle Start()-Aufrufe nach allen Awake()-Aufrufen ausgeführt werden. "controller" ist ausserdem private, damit die Variable nicht im Inspektor auftaucht (warum auch) und nicht von anderen Skripts angefasst werden kann. Ab jetzt können wir in Update() jederzeit mit "controller" auf unseren CharacterController zugreifen. Damit wir keinesfalls ein null bei GetComponent() bekommen, sorgen wir mit einem netten Trick dafür, dass dieses Skript beim Hinzufügen automatisch einen CharacterController mit hinzufügt: @script RequireComponent(CharacterController) Diesen Code, so wie er ist (ohne Semikolon!), ganz an den Anfang (wahlweise auch das Ende...) des Skripts platzieren. Soll der CharacterController jetzt gelöscht werden, und dieses Script ist auch eine Komponente des Objekts, dann gibt es eine Warnmeldung, dass zuerst die Skriptkomponente entfernt werden soll. So sieht das Script jetzt aus: @script RequireComponent(CharacterController) private var controller : CharacterController; function Awake() { controller = GetComponent(CharacterController); } function Update() { } Den Input-Vektor finden Jetzt erstellen wir uns in der Update-Funktion einen Vector3 namens dir (für direction), den wir am Ende der Move()-Funktion übergeben werden. Diesen initialisieren wir mit dem Wert der standardmäßigen horizontalen Input-Achse (links/rechts bzw. A/D) als X-Komponente. var dir : Vector3 = Vector3(Input.GetAxis("Horizontal"), 0, 0); Diesen übergeben wir jetzt, multipliziert mit Time.deltaTime, an Move(). controller.Move(dir * Time.deltaTime); Jetzt sieht das Script so aus: @script RequireComponent(CharacterController) private var controller : CharacterController; function Awake() { controller = GetComponent(CharacterController); } function Update() { var dir : Vector3 = Vector3(Input.GetAxis("Horizontal"), 0, 0); controller.Move(dir * Time.deltaTime); } Das Script wird jetzt der Kapsel gegeben. Zeit zum Testen! Wie man sieht, kann man das Objekt bewegen - es geht nicht durch die Wand, fällt aber auch nicht herunter. Das ist richtig so - schließlich haben wir die volle Kontroller über die Move-Funktion, und in der steckt noch nichts über Schwerkraft drin. Jetzt fügen wir aber erstmal eine Variable "speed" ein, die für etwas mehr Geschwindigkeit sorgt. Diese wird mit dem Rückgabewert von GetAxis() multipliziert. @script RequireComponent(CharacterController) private var controller : CharacterController; var speed : float = 6; function Awake() { controller = GetComponent(CharacterController); } function Update() { var dir : Vector3 = Vector3(Input.GetAxis("Horizontal") * speed, 0, 0); controller.Move(dir * Time.deltaTime); } Herunter fallen Jetzt wollen wir uns um die Schwerkraft kümmern. Dazu führen wir eine Schwerkraft-Variable ein: var gravity : float = 9.81; Jetzt wird es Zeit, sich ein wenig Gedanken zu machen. Im Moment haben wir einen direction-Vektor für Move(), der in jedem Update(), also in jedem Frame, einmal neu erzeugt wird. Die Geschwindigkeit aus vorherigen Frames sind also nicht vorhanden, da der Vektor am Ende jedes Update()s verloren geht. Die Fallgeschwindigkeit ist aber abhängig von der letzten Fallgeschwindigkeit, die sich ja konstant erhöht (wir haben ja eine Beschleunigung). Wir müssen also zumindest die y-Komponente von dir als Variable außerhalb des Update()s speichern, um sie in Update() zu verändern und im nächsten Frame wieder zu benutzen. Wer jetzt ein bisschen weiter denkt oder schon probiert hat, merkt: Meist will man noch z.B. Air Control haben, also eine Beschleunigung nach links und rechts, wenn man in der Luft ist. Also entschließen wir uns am besten dazu, gleich den ganzen dir-Vektor aus Update() raus zu holen. @script RequireComponent(CharacterController) private var controller : CharacterController; private var dir : Vector3 = Vector3.zero; var speed : float = 6; function Awake() { controller = GetComponent(CharacterController); } function Update() { controller.Move(dir * Time.deltaTime); } dir sollte dabei private sein, da wieder kein Bedarf besteht, im Inspektor an den Werten zu spielen, und auch kein anderes Skript daran rumpfuschen können sollte. Jetzt können wir dir.x und dir.y in Update() beeinflussen. dir.x = Input.GetAxis("Horizontal") * speed; dir.y -= gravity * Time.deltaTime; //dir.y um "gravity"m/s senken Jetzt fällt der Charakter herunter, aber etwas stimmt noch nicht. dir.y sinkt jetzt kontinuierlich, auch, wenn man steht. Das heißt: Steht man eine Minnute lang irgendwo und geht dann die Kante herunter, fällt man sofort mit einer wahnsinnigen Geschwindigkeit. Das Problem wird natürlich gelöst, wenn man die Gravitation nur dann wirken lässt, wenn man auch auf dem Boden steht. Ob man auch auf dem Boden steht, ... ...sieht man, wenn controller.isGrounded abgefragt wird. isGrounded (boolean) ist ein sehr nützlicher Shortcut, der angibt, ob der Controller mit einem Collider unter sich kollidiert ist oder nicht, sprich: Ob er auf dem Boden steht. Wir benutzen diese Eigenschaft folgendermaßen in Update(): if(controller.isGrounded) //auf dem Boden { dir.x = Input.GetAxis("Horizontal") * speed; } else //in der Luft { dir.y -= gravity * Time.deltaTime; } Wie Du siehst: dir.x wird jetzt nur noch neu gesetzt, wenn man auf dem Boden ist, sonst bleibt der Wert wie im letzten Frame. Jetzt ist der Schwerkraft-Feher immernoch nicht ganz behoben: Fällt man, sodass dir.y verändert wird, und landet danach, dann bleibt dir.y danach auf diesem Wert. Läuft man nochmal von der Kante, fällt man sofort mit dieser Geschwindigkeit weiter. Also müssen wir den Wert neu setzen, wenn wir auf dem Boden stehen: dir.y = -1; Warum -1? Ganz einfach: Wenn wir nicht ein bisschen nach unten Move()n, wenn wir auf dem Boden sind, kollidieren wir ja nicht mehr damit, und isGrounded gibt false zurück! Das bedeutet zwar, dass wir im nächsten Frame fallen und somit wieder mit dem Boden kollidieren, aber nur jeden zweiten Frame springen zu können ist ungut, oder? Das vollständige Script bis jetzt: @script RequireComponent(CharacterController) private var controller : CharacterController; private var dir : Vector3 = Vector3.zero; var speed : float = 6; var gravity : float = 9.81; function Awake() { controller = GetComponent(CharacterController); } function Update() { if(controller.isGrounded) //auf dem Boden { dir.x = Input.GetAxis("Horizontal") * speed; dir.y = -1; } else //in der Luft { dir.y -= gravity * Time.deltaTime; } controller.Move(dir * Time.deltaTime); } Zeit zum Testen! Bewege die Kapsel ggf. auf einen der Blöcke, um das Fallen zu testen. Bei dieser Gelegenheit darf "Gravity" gerne ein wenig angepasst werden, aber bitte gleich über den Inspektor Springen! Jetzt müssen wir nur noch eines: Richtig springen. Dazu definieren wir uns einfach eine Variable jumpPower vom Typ float, z.B. mit Wert 5. Wird der "Jump"-Button gedrückt, während man auf dem Boden ist, wird dir.y nicht auf -1, sondern auf jumpPower gesetzt. Das Skript sieht dann also so aus: @script RequireComponent(CharacterController) private var controller : CharacterController; private var dir : Vector3 = Vector3.zero; var speed : float = 6; var gravity : float = 9.81; var jumpPower : float = 5; function Awake() { controller = GetComponent(CharacterController); } function Update() { if(controller.isGrounded) //auf dem Boden { dir.x = Input.GetAxis("Horizontal") * speed; if(Input.GetButtonDown("Jump")) //gesprungen? { dir.y = jumpPower; } else { dir.y = -1; } } else //in der Luft { dir.y -= gravity * Time.deltaTime; } controller.Move(dir * Time.deltaTime); } Da es für den Spieler etwas frustrierend sein kann, sekundenlang durch die Luft zu fliegen, während er schon weiß, dass er den Sprung verpatzt hat, bauen wir Air Control ein, damit er sich im Sprung noch retten kann. Dazu wieder eine neue Variable, die nennen wir airControl, sie ist wieder vom Typ float und hat bei mir erstmal den Wert 15 (Warum höher als speed? Siehst Du gleich). (Stattdessen kann man z.B. auch airControlFactor einbauen, der mit speed mutlipliziert den selben Zweck erfüllt. Ich bleibe aber beim ersten Ansatz.) In den Rumpf des else, also, wenn der Spieler in der Luft ist, bauen wir dazu ein, dass dir.x um Input.GetAxis("Horizontal") erhöht (nicht gesetzt) wird, und zwar multipliziert mit Time.deltaTime (weil es eine Beschleunigung ist und damit FPs-abhängig!) und airControl anstatt speed. Das fertige Skript sieht jetzt so aus: @script RequireComponent(CharacterController) private var controller : CharacterController; private var dir : Vector3 = Vector3.zero; var speed : float = 6; var gravity : float = 9.81; var jumpPower : float = 5; var airControl : float = 15; function Awake() { controller = GetComponent(CharacterController); } function Update() { if(controller.isGrounded) //auf dem Boden { dir.x = Input.GetAxis("Horizontal") * speed; if(Input.GetButtonDown("Jump")) //gesprungen? { dir.y = jumpPower; } else { dir.y = -1; } } else //in der Luft { dir.y -= gravity * Time.deltaTime; dir.x += Input.GetAxis("Horizontal") * airControl * Time.deltaTime; } controller.Move(dir * Time.deltaTime); } Wie man sieht, muss airControl mit Time.deltaTime multipliziert werden. airControl ist daher nicht direkt mit speed zu vergleichen und kann (und sollte, testet es ) daher durchaus einen höheren Wert annehmen. Das Skript ist somit erst einmal fertig - man kann laufen, springen und hat sogar Air Control. Damit also... Zurück zum CharacterController Eingangs erwähnte ich, dass die Kapselform sehr gut für Menschen und dergleichen geeignet ist. Warum? Nun, zuerst einmal ist die Kapsel ein Rotationskörper und, da man den CharacterController nicht neigen kann, in diesem Fall um die y-Achse. Das heisst: Man kann den Controller um die y-Achse drehen, ohne dass sich die Form, von irgendeiner Seite gesehen, ändert. Ergo kann man beim Drehen um die y-Achse nirgendwo mit kollidieren! Vergleich mit einem BoxCollider: Dreht man ihn, könnte man mit einer Kante irgendwo anecken. Für uns bedeutet das jedenfalls, dass man den CharacterController völlig sorglos über transform.Rotate() um die y-Achse drehen kann, ohne fürchten zu müssen, schlaue Spieler könnten sich damit in eine Wand hineindrehen. Deshalb hat der CharacterController auch keine Rotate()-Funktion. Des Weiteren ist die Kapsel nicht nur ein Zylinder, sondern hat oben und unten je eine Halbkugel. Das ermöglicht es, die Kapsel Schrägen oder kleine Stufen hinauflaufen zu lassen, ohne dass das als Kollsion mit der Seite erkannt wird. Die Halbkugelform ermöglicht es sogar, einen genauen Winkel anzugeben, bis zu dem eine Schräge erklommen werden kann (Eigenschaft "Slope Limit"). Erweiterungsbeispiele Dieses Skript kann man natürlich nach blieben mit feinen Raffinessen erweitern. Wie wäre es z.B. mit einem Multijump? Neu einfügen: var multiJumpCount : int = 3; private var currentJumpCount : int = 0; Update() ändern: function Update() { if(controller.isGrounded) //auf dem Boden { dir.x = Input.GetAxis("Horizontal") * speed; if(Input.GetButtonDown("Jump")) //gesprungen? { dir.y = jumpPower; currentJumpCount = 1; //Jump Counter zurücksetzen } else { dir.y = -1; } } else //in der Luft { if(currentJumpCount < multiJumpCount && Input.GetButtonDown("Jump")) //darf man noch springen & gesprungen? { dir.y = jumpPower; //+= wäre auch eine Möglichkeit, oder man könnte eine zweite jumpPower-Variable für in-der-Luft einfügen ++currentJumpCount; //das gleiche wie currentJumpCount++; } else { dir.y -= gravity * Time.deltaTime; } dir.x += Input.GetAxis("Horizontal") * airControl * Time.deltaTime; } controller.Move(dir * Time.deltaTime); } Anstatt einer einfachen Geschwindigkeit könnte man auch ein beschleunigtes Laufen bauen! Neu einfügen: var acceleration : float = 0.5; Update() ändern: if(controller.isGrounded) //auf dem Boden { dir.x = Mathf.Lerp(dir.x, Input.GetAxis("Horizontal") * speed, acceleration * Time.deltaTime); //an gegebenen Speed-Wert annähern, anstatt zu setzen //... Um den Unterschied zu bemerken, ist ein höherer Speed-Wert sinnvoll. Acceleration darf durchaus niedriger sein. Acceleration heisst: Innerhalb einer Sekunde nähern wir uns um das accelearion-fache an den angepeilten Speed-Wert an. Bei 0.5 heisst das: Nach einer Sekunde 0,5 = 50% Geschwindigkeit, nach 2 Sekunden 0,5+(Rest*0,5) = 0,5+((1-0,5) * 0,5) = 0,5+(0,5*0,5) = 0,75 = 75% Geschwindigkeit, usw. Fertig So, jetzt kannst Du einen CharacterController für einen Sidescroller programmieren! Viel Spaß damit! Anmerkungen und Kritik: Immer her damit. Sascha Ende. 10 Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
Tiles Geschrieben 15. August 2011 Melden Share Geschrieben 15. August 2011 Klasse Tutorial Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
Graphiler Geschrieben 15. August 2011 Melden Share Geschrieben 15. August 2011 DANKE! Du machst einem das (Unity) Leben um vieles einfacher. Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
Bowserkoopa Geschrieben 16. August 2011 Melden Share Geschrieben 16. August 2011 Jup, nach dem ersten Durchlesen schauts eigentlich gut erklärt und auch verständlich aus. Auch von dem was präsentiert wird, ist der Umfang eig. groß. Somit mal ein "Bowserkoopa gefällt das" Bei mir tun sich die Fragen allerdings immer erst dann auf, wenn ich versuche das Tutorial auf eine eigene Spielfigur anzupassen, also würd ich sagen mach ich das mal Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
Graphiler Geschrieben 7. September 2011 Melden Share Geschrieben 7. September 2011 Wann komm das nächste Tutorial ? Kommt überhaupt eins ? Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
Sascha Geschrieben 8. September 2011 Autor Melden Share Geschrieben 8. September 2011 Im Moment habe ich nichts geplant, weil ich nicht weiß, worüber ich schreiben sollte Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
Naim Geschrieben 8. September 2011 Melden Share Geschrieben 8. September 2011 Heißt das, man kann sich was wünschen? Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
Sascha Geschrieben 8. September 2011 Autor Melden Share Geschrieben 8. September 2011 Jap. In welcher Zeit (und im Extremfall ob überhaupt) der Wunsch erfüllt wird, ist aber ein anderes Thema ^^ Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
YGOFreak1997 Geschrieben 4. Dezember 2011 Melden Share Geschrieben 4. Dezember 2011 Wie wärs mit nem First-Person-CharacterController-Tut? Mit MouseLook und so? Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
La_AlexoO Geschrieben 2. Februar 2012 Melden Share Geschrieben 2. Februar 2012 Klasse Tutorial !! Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
Sascha Geschrieben 2. Februar 2012 Autor Melden Share Geschrieben 2. Februar 2012 Danke Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
Graphiler Geschrieben 2. Februar 2012 Melden Share Geschrieben 2. Februar 2012 Also ich hätte gerne mal ein richtig gutes Editor-Scripting Tutorial mit Sachen wie EditorWindows,CustomInspectors und so Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
Sascha Geschrieben 2. Februar 2012 Autor Melden Share Geschrieben 2. Februar 2012 Das ist eigentlich nichts weiter als das Grundgerüst aus der Scripting Reference zu mopsen und OnGUI zu beherrschen... 1 Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
notnamed Geschrieben 9. Februar 2012 Melden Share Geschrieben 9. Februar 2012 Hallo finde deine Programmier-Tutorials super. Würde mich über C# Unity Tutorials freuen. Mal ein paar Anstöße die ich gerne ich gleicher form lesen wollen würde: Wann legt man neue Szenen an? Wie macht man ein Hauptmenü bzw. Hauptmenü-Layer Erste Netzwerkscripte - Server & Clients Erstes Game mit allen Elementen .... Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
Hannow Geschrieben 23. März 2012 Melden Share Geschrieben 23. März 2012 Danke, es ist sehr ausführlich !! Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
DukeD Geschrieben 30. März 2012 Melden Share Geschrieben 30. März 2012 Ganz großer Sport deine Tutorials!!! Sind extrem hilfreich für Pixelschubser wie mich da Sie sehr schön anschaulich geschrieben sind. Auch die geschichte mit dem Spoilen von Scripten finde ich super (ich hab mich nur einmal hinreissen lassen reinzuschauen ;-) Vielen Dank für deine Mühe!!! Naja und falls man sich was Wünschen darf als nächstes Tutorial fänd ich eine Erklärung zu RayCast's super. Das Ding will einfach nicht in meine rübe rein. Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
Sascha Geschrieben 30. März 2012 Autor Melden Share Geschrieben 30. März 2012 Was Raycasts angeht, da bist du nicht der erste. Von daher werde ich vermutlich das als nächstes Thema nehmen, wenn ich Zeit finde. Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
Zero Geschrieben 2. November 2012 Melden Share Geschrieben 2. November 2012 Klasse Tutorial ! Bin noch ein Anfänger und hab alles gut Verstanden & hinbekommen ! 10/10 Punkte Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
steave007 Geschrieben 6. Februar 2013 Melden Share Geschrieben 6. Februar 2013 (bearbeitet) Hey ich hab ein kleines Problemchen, und zwar wollte ich dass man wenn man 5 Sekundne gelaufen ist man schneller läuft. Klappt aber iwi nicht: (ignoriert die Kommentare einfach) @script RequireComponent(CharacterController) //vergewissert, dass CharacterController-Komponente vorhanden ist private var controller : CharacterController; //findet den CharacterController und speichert ihn als Variable private var dir : Vector3 = Vector3.zero; //Variable für Richtung der Bewegung private var jumpCount : int = 0; //Variable für Doppelsprung; bisher kein Sprung daher 0 private var speedPlus : boolean = false; //Speedbonus erhalten? var speed : int = 3; //Geschwindigkeit var gravity : float = 9.81; //Schwerkraft var jumpPower : float = 5; //Sprunghöhe var airControl : int = 15; //Korrektur im Sprung function Awake() //wird vor Update Funktion ausgeführt da controller in Update benötigt wird { controller = GetComponent(CharacterController); //findet den CharacterController uns speichert ihn in der Variable Controller } function Update() { if (controller.isGrounded) //checkt ob der Character auf dem Boden steht { dir.x = Input.GetAxis("Horizontal")*speed; //Bewegung nach links/rechts auf y-Achse if (Input.GetAxis("Horizontal") && speedPlus == false) //wenn sich Char bewegt und noch kein Speedbonus erhalten wurde { speedPlus = true; //Speedbonus wurde erhalten yield WaitForSeconds(5); //warte 5 Sekunden (Speedbonus soll nach 5 Sekunden laufen aktiviert werden) speed = speed*2; //Geschwindigkeit verdoppelt sich temporär } else { speedPlus = false; //Speedbonus wurde nicht erhalten (zum Zurücksetzen der Variable) } if (Input.GetButtonDown("Jump"))//wenn Spieler springt { dir.y = jumpPower; //Bewegung nach oben in Höhe von jumpPower jumpCount = 1; //Sprung wird gezählt } else { dir.y = -1; //Charakter bleibt auf Boden stehen } } else { if (jumpCount == 1 && Input.GetButtonDown("Jump")) //Wenn schon gesprungen wurde, aber nur einmal und gesprungen wird { dir.y = jumpPower; //charakter springt jumpCount = 2; //es wurde 2x gesprungen, kein weiterer Sprung nötig } else { dir.y -= gravity*Time.deltaTime; //Fallbeschleunigung } dir.x += Input.GetAxis("Horizontal")*Time.deltaTime*airControl; //Retten des Spielers } controller.Move(dir * Time.deltaTime); //Bewegen } bearbeitet 7. Februar 2013 von Sascha Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
Sascha Geschrieben 7. Februar 2013 Autor Melden Share Geschrieben 7. Februar 2013 Warum hast du so viel Leerzeilen da drin, das kann man gar nicht lesen >.< //e: Hab mal ein bisschen Leerzeilen weg gemacht und gesehen, wo dran es liegt: yield gibt's in Update nicht. Du kannst das yield-Gedöns in eine Methode auslagern und sie aufrufen, aber nicht yield in Update benutzen. Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
steave007 Geschrieben 7. Februar 2013 Melden Share Geschrieben 7. Februar 2013 ok Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
snooop87 Geschrieben 28. Januar 2014 Melden Share Geschrieben 28. Januar 2014 super tutorial!! Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.