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