Pixel to Unity Teil 4 – Wie man einen Character Controller zum Steuern einer animierten Spielfigur erstellt

Im vierten Teil unserer Pixel-To-Unity Reihe wollen wir einen einfachen Character Controller für Unity implementieren, der unser Pixel-Sprite bewegen und die passende Animation abspielen soll.

Im vorherigen Teil unserer Reihe haben wir einen AnimationController erzeugt und angepasst, der die Animationen unserer Spielfigur kontrolliert. Nun wollen wir einen einfachen Character Controller schreiben, der unsere Spielfigur steuert und jeweils die passende Animation triggert.

Player Controller Script erstellen

Wir starten damit, dass wir in Unity ein neues C# Script für unseren Player Controller erstellen.
Dazu wählen wir im Menü Assets->Create->C# Script aus oder über das Kontex-Menü bei Rechtsklick. Dadurch wird in dem Ordner, in dem wir uns befinden, ein neues Script erstellt, das automatisch von der Unity-Klasse MonoBehaviour erbt und somit als Component an jedes GameObject angehangen werden kann.

Alternativ kann man das Skript natürlich auch direkt in der IDE der Wahl anlegen.

Dann fügen wir das Script als Component zu unserem SoldierChar-GameObject hinzu, welches wir im vorherigen Teil unserer Artikelserie in die Szene gezogen hatten.

Variablen

Als erstes benötigen wir ein paar Variablen, die wir zum Teil über den Inspector füllen können und zum Teil dynamisch während der Laufzeit setzen.


[SerializeField] public float walkingSpeed = 1f;
[SerializeField] public float runningSpeed = 2f;
[SerializeField] public float jumpForce = 200f;

Rigidbody2D rigidbody;
BoxCollider2D boxCollider2D; 
Animator animatorPlayer;


float directionX;
bool isWalking = false;
bool isRunning = false;
bool isJumping = false;

Die ersten drei Variablen sind public und somit kann darauf über den Inspector zugegriffen werden.

  • walkingSpeed – Parameter zum Steuern der Geschwindigkeit und der Beschleunigung beim Laufen.
  • runningSpeed – Parameter zum Steuern der Geschwindigkeit und der Beschleunigung beim Rennen.
  • jumpForce – Parameter für die Sprungkraft, welche die Sprunghöhe und Falldauer beeinflusst

Dann folgen drei private Variablen, welche zur Laufzeit die Referenzen zu den anderen Components des GameObjects zugewiesen bekommen.

  • rigidbody – Rigidbody2D Component zum Anwenden von einfachen physikalischen Kräften auf das Objekt
  • boxCollider – BoxCollider2D Component für die Kollisionserkennung
  • animatorPlayer – Animator Component, welche den Animation Controller für unseren Character enthält

Zum Schluss folgen ein paar private Variablen, die als Zwischenspeicher zur Laufzeit verwendet werden.

  • directionX – Float-Wert, der die horizontale Eingabe bei Tastendruck speichert
  • isWalking, isRunning, isJumping – Flags zum Speichern von Zuständen je nach Eingabe

An der Component können wir nun die Werte verändern, bis Steuerung und Animation passen.

Fürs Springen muss man ein wenig mit dem JumpForce-Wert herumprobieren, damit die Sprunghöhe mit der Dauer der Animation übereinstimmt. Doch dazu später.

Initialisieren in der Start-Methode

Nun können wir die zur Laufzeit benötigten Variablen initialisieren. Das machen wir in der Start-Methode.
Im Speziellen setzen wir hier die Referenzen zu den anderen Components unseres GameObjects, auf welche wir in diesem Controller-Skript zugreifen wollen.


void Start()
{
  animatorPlayer = GetComponent<Animator>();
  rigidbody = GetComponent<Rigidbody2D>();
  boxCollider2D = GetComponent<BoxCollider2D>();
}

Animationen steuern

Jetzt wollen wir uns um die Bewegung kümmern und um die Animationen dazu.
Dazu holen wir uns den Input – also die Werte der Tasten oder Sticks, die auf Tastatur oder GamePad betätigt wurden – berechnen daraus die Bewegung auf dem Bildschirm und spielen die passende Animation ab.

Wir greifen dabei auf die vor konfigurierten Achsen des Input Managers zu.
Über den Namen kann man die Achse auslesen.

Wir beginnen mit der horizontalen Bewegung.

Horizontale Bewegung

In der Update-Methode, welche einmal per Frame durchlaufen wird, schauen wir zunächst, ob ein Input auf der horizontalen Achse angekommen ist und speichern den Wert.
Links ergibt einen negativen Wert, rechts einen positiven. Ist der Wert 0, wurde keine entsprechende Taste gedrückt / Stick bewegt.

Die Werte Gravity und Sensitivity können wir im Input Manager anpassen und so den Ablauf der Bewegung und der Animation optimieren.

Gleichzeitig schauen wir, ob die Shift-Taste gedrückt gehalten wird, wodurch wir in den Zustand des Rennens wechseln.
Je Zustand setzen wir die boolschen Variablen isWalking oder isRunning und setzen entsprechend die Parameter des AnimationControllers.


void Update()
{
	directionX = Input.GetAxis("Horizontal");
	if(directionX != 0 && Input.GetKey(KeyCode.LeftShift)) {
		animatorPlayer.SetBool("isWalking", true);
		animatorPlayer.SetBool("isRunning", true);
		isRunning = true;
	} else if (directionX != 0 && !Input.GetKey(KeyCode.LeftShift)) {
		animatorPlayer.SetBool("isRunning", false);
		animatorPlayer.SetBool("isWalking", true);
		isWalking = true;
		isRunning = false;
	} else {
		animatorPlayer.SetBool("isWalking", false);
		isWalking = false;
		isRunning = false;
	}
}

Die Berechnung der Beschleunigung machen wir in der FixedUpdate-Methode.
Diese wird mehrmals per Frame durchlaufen, was unsere Bewegungen flüssiger macht.


void FixedUpdate()
{
	if(isRunning) {
		rigidbody.velocity = new Vector2(directionX * runningSpeed, rigidbody.velocity.y);
	}
	if(isWalking && !isRunning) {
		rigidbody.velocity = new Vector2(directionX * walkingSpeed, rigidbody.velocity.y);
	}
}

Wenn wir Play drücken, können wir unseren Character bereits steuern.

Feuern

Zum Abspielen der Animation zum Feuern einer Waffe erweitern wir die Update-Methode.


if(Input.GetAxis("Fire1") != 0) {
	animatorPlayer.SetBool("isShooting", true);
} else {
	animatorPlayer.SetBool("isShooting", false);
}

 

Jumping

Das Springen implementieren wir analog in der Update-Methode, hier prüfen wir jedoch vorher in einer separaten Methode IsGrounded, ob der Character auf dem Boden steht.
Wir lassen ihn nur Springen, wenn das der Fall ist.


if(Input.GetKeyDown(KeyCode.Space) && IsGrounded()) {
	animatorPlayer.SetBool("isJumping", true);
	rigidbody.AddForce(Vector3.up * jumpForce);
	isJumping = true;
} else {
	animatorPlayer.SetBool("isJumping", false);
	isJumping = false;
}

In der IsGrounded-Methode wird einfach geschaut, ob der BoxCollider des Character auf einen anderen Collider trifft.
Ist das der Fall, wird true zurückgegeben.

 
private bool IsGrounded() {
	RaycastHit2D raycastHit = Physics2D.BoxCast(
		boxCollider2D.bounds.center, 
		boxCollider2D.bounds.size,
		0f, 
		Vector2.down * 0.1f 
	);
	return raycastHit.collider != null;
}

Zum Schluss erweitern wir noch die FixedUpdate-Methode, um den Zustand des Springens zu prüfen und zu setzen.


void FixedUpdate()
{
	// ...
	if(isJumping) {
		isJumping = false;
	}
}

Und das war es schon – der Character ist nun minimal spielbar.

Fazit

Wir wissen nun also, wie wir einen Pixel-Haufen für Unity animieren können, um daraus einen spielbaren oder auch nicht-spielbaren Character zu machen.
Die Grundlagen haben wir. In einem weiteren Teil der Serie könnte man die Geschosse der Waffe einbauen und einen zweiten Spieler. Schauen wir mal, was wir nächstes machen.

Bis dahin hoffe ich, diese Artikel-Serie war hilfreich.

Ähnliche Beiträge

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert