Een beat-em-up game maken met Godot - de speler
Tags: tutorial, beginners, godot, gamedev
Published: 2023-04-08 08:55:13

[Terug naar deel 1](https://dev.to/bgie/een-beat-em-up-game-maken-met-godot-4-deel-1-42bi)

In deel 2 van deze reeks voegen we onze speler toe.

Maak een nieuwe scene.
![Create new scene menu screenshot](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/n4mkbcgqne6417f6h24y.png)

De `node` die we aanmaken moet van het type `CharacterBody2D` zijn. Dit is een soort `node` die wel meedoet met fysica simulatie (vallen en botsen) maar waar we volledige controle over hebben.
Als naam van de `scene` gebruiken we gewoon 'Player' (dit is vrij te kiezen).
![Create Characterbody2d scene for player screenshot](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2ti3tmj954rawdfdfyp6.png)

We krijgen nu een extra tabblad voor deze nieuwe 'Player' scene. Via de knoppen hieronder kan je wisselen tussen scenes die je open hebt.
![Navigation buttons game scene - player scene screenshot](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/a1zvv7pl5iyop33o9p2i.png)

We voegen 2 nodes toe aan onze player: 
- een `AnimatedSprite2D` voor de graphics,
- en een `CollisionShape2D` om botsingen te kunnen detecteren.
![Add nodes to player scene](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/j3qmrzkwjh1kmzsjy96o.png)

Om de graphics van de `AnimatedSprite2D` te kiezen, moeten we eerst zorgen dat ie links geselecteerd is. Dan kunnen we rechts bij `Sprite Frames` via het uitklap menu een nieuwe `SpriteFrames` toevoegen.
![Add new spriteframes to player animatedsprite](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4bd6cidu5uofn5m5k8ys.png)

De nieuwe `SpriteFrames` is nog leeg. Klik er op. Midden-beneden opent nu de editor voor de `SpriteFrames` in een paneel.
![Click on spriteframes to open editor](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2n0zwmessoipcqg9fo0a.png)

De Godot ontwikkelomgeving zit vol met panelen en tabbladen... Hieronder zie je de knop die hoort bij het `SpriteFrames` paneel, waaraan je ziet dat dit paneel open staat.
![Spriteframes editor with navigation button](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/g2cn95wqlyf4wotmcva7.png)

We gaan onze animaties toevoegen: in het `SpriteFrames` paneel heb je onder 'Animations' wat knoppen en een lijstje met animaties die in de `SpriteFrames` zitten.
Met de `Add Animation` knop voegen we de volgende animaties toe: `attack`, `die`, `hurt`, `idle` en `walk` (`default` mag weg).
De naam veranderen van een animatie kan door 2 keer (langzaam) te klikken met de linkermuisknop.
![Add animations](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wwyrbyp10luwoa517pz3.png)

![Spriteframes editor buttons used](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qnfs9mx9xfa89hzpdrrr.png)

De volgende knoppen gaan we gebruiken om alle animaties correct in te stellen. Van links naar rechts:
- de `animation looping` knop
- FPS = snelheid van de animatie (frames per seconde)
- `play` knop om een voorbeeld te zien
- `add frame from file` knop om losse afbeeldingen toe te voegen.

Klik op de `add frame from file`. In de dialoog die volgt, zoek de map met de juiste afbeeldingen en gebruik shift-muisklik om ze allemaal te selecteren.
(Klik op de eerste afbeelding, houdt dan `SHIFT` ingedrukt en klik op de laatste afbeelding)

![Add pngs as animation frames dialog](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lprnec8u1ubggwxdm8gr.png)

Voeg de juiste beelden toe aan alle animaties, en stel de juiste opties in:

- alle animaties spelen aan 30 FPS.
- 'idle' en 'walk' hebben `animation looping` AAN staan (knop icoon is blauw)
- 'attack', 'hurt', 'die' hebben het UIT staan (knop icoon heeft zelfde kleur als andere knoppen). Deze animaties spelen maar 1 keer, tot we via code een nieuwe animatie starten.

Nu gaan we voor de eerste keer code gebruiken, om onze 'Player' tot leven te brengen!
In het linkerpaneel zorgen we dat de 'Player' geselecteerd is, en klikken we op de knop `Attach script`.
![Attach new script to player scene root node](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dpcwiwe2vjoda4me2k4e.png)

We krijgen een dialoog, waar we een template (voorbeeld) kunnen kiezen, en een naam voor het script. Omdat we onze node 'Player' hebben genoemd, krijgen we automatisch de naam 'Player.gd' als standaard, wat prima is. Klik `Create`.
![Create new script from template](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/98y5uo6cv8qy53c32wft.png)

![Script editor example screen](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8xa7htxf02x6hgoyy1zv.png)

Je krijgt van Godot nu wat voorbeeldcode voor een platformer, met springen. We hebben springen niet nodig. Je mag alle code wegdoen, behalve de eerste 2 regels:

```gdscript
extends CharacterBody2D

const SPEED = 300.0
```

Omdat we dit script verbinden met onze player `node`, en dat een `CharacterBody2D` is, start het script met de regel `extends CharacterBody2D`.

De tweede regels is de definitie van een constante: we gaan het woord 'SPEED' later in ons script gebruiken, en daar wordt overal de waarde '300' ingevuld. Dit is de loop-snelheid van onze speler. We maken er '400' van.

```gdscript
const SPEED = 400.0
```

We willen dat de speler onze 'held' kan laten bewegen. Hij moet kunnen links-rechts en boven-onder bewegen met de pijltoetsen. Deze logica gaan we in de `_physics_process` functie steken: dit is een functie die de Godot engine oproept voor elke `game tick`. Standaard is dit 60 maal per seconde. Deze snelheid is vast en hangt niet af van de kracht van je grafische kaart. We willen dat onze speler overal even snel loopt, of je nu een krachtige grafische kaart hebt of niet.

```gdscript
func _physics_process(_delta):
	velocity.x = Input.get_axis("ui_left", "ui_right") * SPEED
	velocity.y = Input.get_axis("ui_up", "ui_down") * SPEED
	move_and_slide()
```

We kunnen dit al testen.
Ga terug naar de game scene en sleep de `player.tscn` naar de 'Arena' node, als kind van de node.

![Drag player onto scene](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jk0ipxf65bp08477v127.png)

Klikken we nu op `Run Project` rechtsboven, dan opent onze game en kunnen we met de pijltoetsen onze speler bewegen!

Er zijn nog een paar basis zaken die ontbreken:
- het personage zelf beweegt niet
- het personage kijkt altijd naar dezelfde kant
- het personage kan 'buiten beeld' lopen.

De eerste 2 punten kunnen we snel oplossen met wat extra code.

Ga terug naar het script via de `Script` knop boven-midden.

![Script button screenshot](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bdlwpb7jlsaqodbi9hcc.png)

We hebben daarstraks de animaties reeds gemaakt, nu moeten we enkel nog de juiste animatie starten vanuit onze code. Wanneer de speler loopt, spelen we de 'walk' animatie. Als hij stilstaat, spelen we 'idle'.

De animaties worden getoond door de `AnimatedSprite2D` die we aan onze player `scene` hebben gehangen. In onze code gaan wie deze `node` zoeken en opslaan in een variabele die we 'sprite' noemen. Dit stukje code komt vlak onder onze constante SPEED te staan, en wordt eenmaal uitgevoegd als het spel start:

```gdscript
@onready var sprite: AnimatedSprite2D = $AnimatedSprite2D
```

In onze `_physics_process` functie kunnen we nu de variabele `sprite` gebruiken om een animatie te starten. 

We vervangen het stukje `move_and_slide()` door deze blok code:
```gdscript
	if velocity:
		move_and_slide()
		sprite.play("walk")
	else:
		sprite.play("idle")
```

Onze code ziet er dan zo uit:

```gdscript
extends CharacterBody2D

const SPEED = 400.0

@onready var sprite: AnimatedSprite2D = $AnimatedSprite2D

func _physics_process(_delta):
	velocity.x = Input.get_axis("ui_left", "ui_right") * SPEED
	velocity.y = Input.get_axis("ui_up", "ui_down") * SPEED

	if velocity:
		move_and_slide()
		sprite.play("walk")
	else:
		sprite.play("idle")

```

Test of het werkt via die `Run Project` knop of de `F5` toets.
Het is vaak een goed idee je code te testen na elke kleine wijziging.

De kijkrichting van de speler wijzigen doen we via een trukje. Je kan de schaal (grootte) van een afbeelding wijzigen, en zelfs de hoogte (y) en breedte (x) apart. Schaal 1 is de originele grootte. Schaal 2 is dan dubbel zo groot. Maar schaal -1 is originele grootte, maar gespiegeld. Als we de sprite schaal voor x veranderen van 1 naar -1 wordt de sprite gespiegeld in de breedte.

Aan onze `_physics_process` functie voegen we het volgende stukje code toe (onder de regels waar `velocity.x` en `velocity.y` worden ingesteld via `Input.get_axis`):

```gdscript
if velocity.x < 0:
	sprite.scale.x = -1
elif velocity.x > 0:
	sprite.scale.x = 1
```

De hele code ziet er nu zo uit:

```gdscript
extends CharacterBody2D

const SPEED = 400.0

@onready var sprite: AnimatedSprite2D = $AnimatedSprite2D

func _physics_process(_delta):
	velocity.x = Input.get_axis("ui_left", "ui_right") * SPEED
	velocity.y = Input.get_axis("ui_up", "ui_down") * SPEED

	if velocity.x < 0:
		sprite.scale.x = -1
	elif velocity.x > 0:
		sprite.scale.x = 1

	if velocity:
		move_and_slide()
		sprite.play("walk")
	else:
		sprite.play("idle")

```

Als je het project test, merk je dat het personage nu ook kijkt in de juiste richting als hij loopt.

Er voor zorgen dat onze speler niet 'buiten beeld' kan lopen doen we in het volgende [deel](https://dev.to/bgie/een-beat-em-up-game-maken-met-godot-4-deel-3-329).