Player - acbarker19/Godot-Action-RPG GitHub Wiki

How to Create the Player

  1. Add a new KinematicBody2D
  2. Make sure it is a child of World
  3. Rename to Player
  4. Add a Sprite as a child
  5. Create the sprite animation
  6. Click on the Player node
  7. Attach a script
  8. Make sure the script path leads to the Player folder

Player Movement

Inside the Player.gd script, add the following:

const ACCELERATION = 10
const MAX_SPEED = 100
const FRICTION = 10

var velocity = Vector2.ZERO

func _physics_process(delta):
	var input_vector = Vector2.ZERO
	input_vector.x = Input.get_action_strength("ui_right") - Input.get_action_strength("ui_left")
	input_vector.y = Input.get_action_strength("ui_down") - Input.get_action_strength("ui_up")
	input_vector = input_vector.normalized()
	
	if input_vector != Vector2.ZERO:
		velocity = velocity.move_toward(input_vector * MAX_SPEED, ACCELERATION * delta)
	else:
		velocity = velocity.move_toward(Vector2.ZERO, FRICTION * delta)

	velocity = move_and_slide(velocity)
  • delta is the time it took the last frame to process
  • input_vector = input_vector.normalized() will normalize the velocity so that the player character will always travel at the same speed regardless of how many keys are held at the same time
  • At the end of the function, you can use move_and_collide(velocity * delta) if you want the player to stop when they run into a collidable object, or you can use velocity = move_and_slide(velocity) if you want the player to be able to slide around a collidable object
  • Setting velocity equal to move_and_slide(velocity) reduces the amount of shaking that the player does when moving into some collidable corners

Player Collisions

  1. Click on the Player node
  2. Add a new CollisionShape2D
  3. Select Shape > New CapsuleShape2D
  4. Change size of capsule using handles around capsule outline. If desired, turn on pixel snapping
  5. Move the capsule using the alt key
  6. Rotate the capsule if desired

Player Movement Animations

Once you have created an AnimationTree containing the idle and run animations and added transitions between them, go inside the Player.gd script and add the following (only the relevant code is shown):

onready var animationTree = $AnimationTree
onready var animationState = animationTree.get("parameters/playback")

func _physics_process(delta):
	if input_vector != Vector2.ZERO:
		animationTree.set("parameters/Idle/blend_position", input_vector)
		animationTree.set("parameters/Run/blend_position", input_vector)
		animationState.travel("Run")
	else:
		animationState.travel("Idle")

Create a State Machine to Control States the Character Can Be In

State machines can be used to control what state an object is in, such as moving, rolling, or attacking in this game. Only one state at a time should be used for the character. To create a state machine, go inside the Player.gd script and add the following (only the relevant code is shown):

enum {
	MOVE,
	ROLL,
	ATTACK
}

var state = MOVE

func _physics_process(delta):
	match state:
		MOVE:
			move_state(delta)
		ROLL:
			roll_state(delta)
		ATTACK:
			attack_state(delta)

func move_state(delta):
	// code for controlling movement
	
	// since MOVE is the default state, if must determine what the next state is
	if Input.is_action_just_pressed("attack"):
		state = ATTACK
	elif Input.is_action_just_pressed("roll"):
		state = ROLL
	
func attack_state(delta):
	// velocity must be set to zero to avoid character moving slightly after the attack animation is finished
	velocity = Vector2.ZERO
	animationState.travel("Attack")

func roll_state(delta):
	// velocity must be set to zero to avoid character moving slightly after the roll animation is finished
	velocity = Vector2.ZERO
	animationState.travel("Roll")

func attack_animation_finished():
	state = MOVE

The state should return to MOVE after the other states have completed their animation. To call animation_finished when the animation is complete, see Call a Function During an Animation. There must also be transitions between animations.

Add the Ability to Roll

  1. Create animations for rolling and add them to the player's AnimationTree
  2. Add a custom action for rolling
  3. Go inside the Player.gd script and add the following to the state machine as shown in the state machine tutorial (only the relevant code is shown):
const ROLL_SPEED = 120

var roll_vector = Vector2.DOWN

func move_state(delta):
	// code for controlling movement

	if input_vector != Vector2.ZERO:
		roll_vector = input_vector
	// code for setting animationTree animations and handing inputs - make sure Roll is set up like Attack
	
func roll_state(delta):
	velocity = roll_vector * ROLL_SPEED
	animationState.travel("Roll")
	move()

func move():
	velocity = move_and_slide(velocity)

func roll_animation_finished():
	velocity = velocity * 0.8
	state = MOVE
  1. Call the roll_animation_finished() function on the last frame of the animations

How to Create Player Stats That can be Accessed Anywhere

  1. In the top navigation bar, select Scene > New Inherited Scene...
  2. Select Stats.tscn to create a scene with a Stats node
  3. In the right menu, set Max Health to the desired amount
  4. Save the scene as PlayerStats.tscn
  5. In the top navigation bar, select Project > Project Settings
  6. In the popup, click the AutoLoad tab
  7. Select the path to the PlayerStats file and click Add
  8. Open the Player script and add the following:
var stats = PlayerStats

func _ready():
	stats.connect("no_health", self, "queue_free")
  1. Add a Hurtbox to the player
  2. In the right menu, select Collision > Layer > PlayerHurtbox
  3. In the right menu, select the Node tab
  4. In the right menu, double click area_entered(area: Area2D) to create a signal function in the Player script
  5. In the Player script, add the following:
func _on_Hurtbox_area_entered(area):
	stats.health -= 1