GodotCourse/week2/exercise2_jumpcontrol.md
2024-07-15 17:26:12 -04:00

4.1 KiB

The template for the character controller in Godot is very basic.

extends CharacterBody2D


const SPEED = 300.0
const JUMP_VELOCITY = -300.0

# Get the gravity from the project settings to be synced with RigidBody nodes.
var gravity = ProjectSettings.get_setting("physics/2d/default_gravity")


func _physics_process(delta):
	# Add the gravity.
	if not is_on_floor():
		velocity.y += gravity * delta

	# Handle jump.
	if Input.is_action_just_pressed("ui_accept") and is_on_floor():
		velocity.y = JUMP_VELOCITY

	# Get the input direction and handle the movement/deceleration.
	# As good practice, you should replace UI actions with custom gameplay actions.
	var direction = Input.get_axis("ui_left", "ui_right")
	if direction:
		velocity.x = direction * SPEED
	else:
		velocity.x = move_toward(velocity.x, 0, SPEED)

	move_and_slide()

The basic template uses two helper functions is_on_floor and move_and_slide along with the velocity variable to achieve jumping, falling, and movement.

Let us use some of our newfound knowledge of physics to improve our player character!

Exported Variables

Exported variables allow us to make changes to them in the Godot editor. This is nice for play testing as it gives us a visual way to tweak our code. Let's take the imortant variables and export them.

@export var SPEED = 10400
@export var JUMP_VELOCITY = -300

Collisions with RigidBodies

Each time a PlayerCharacter body moves via move_and_slide any colliders it made contact with are stored in an array that can be retrieved via the get_slide_collision method.

We can use that to apply an impulse to any RigidBody the player collided with.

	# This represents the player's inertia
	# after calling move_and_slide()
	for i in get_slide_collision_count():
		var c = get_slide_collision(i)
		if c.get_collider() is RigidBody2D:
			c.get_collider().apply_central_impulse(-c.get_normal() * PUSH_FORCE)

Creating a Melee Force Push Attack

We can use our new knowledge of impulses to do some pretty cool attacks agains RigidBodies!

To pull off the attack we need to know:

  • Is there a target in range?
  • What direction is the player facing?
  • Is there a target in front of them in range?
  • Are they attacking?
  • How much force should be applied?

To tell if there is a target in range, we can use a handy feature called a Raycast.

Raycasts

Raycasts can be used to detect collisions within a very narrow line. They are very helpful for detecting objects within a certain proximity.

We will use them to detect if there are any items we can attack with a force-push within range of the player character.

First we make a reference to our two raycasts:

@onready var rightRay = $RightRaycast
@onready var leftRay = $LeftRaycast
var pushRightEnabled = false
var pushLeftEnabled = false

#note no type assigned
var pushTarget
#can not force-push right if facing left
var faceLeft = false

When we detect the action of a raycast we need to respond. First of all, we need to track which direction the player is facing, assuming that they can only force-push in the direction they are facing.

if direction:
		velocity.x = direction * SPEED
		faceLeft = true if direction<0 else false
if rightRay.is_colliding():
		var collider = rightRay.get_collider()
		if collider is Node:
			if collider.is_in_group("boxes"):
				pushRightEnabled = true
				pushTarget = collider
	else:
		pushRightEnabled = false

And we can do the same for the left ray:

if leftRay.is_colliding():
		var collider = leftRay.get_collider()
		if collider is Node:
			if collider.is_in_group("boxes"):
				pushLeftEnabled = true
				pushTarget = collider
	else:
		pushLeftEnabled = false

Now we just have to detect if the player is holding the force push button.

if Input.is_action_just_pressed("push") && pushRightEnabled && faceLeft == false:
		label.text="shove"
		pushTarget.apply_central_impulse(Vector2(1,0) * PUSH_FORCE * 20)
		pushRightEnabled = false
		
	if Input.is_action_just_pressed("push") && pushLeftEnabled :
		label.text="shove"
		pushTarget.apply_central_impulse(Vector2(-1,0) * PUSH_FORCE * 20)
		pushLeftEnabled = false