From 61ec26edd10e03d68ce7154f60daadfa54a68e7a Mon Sep 17 00:00:00 2001 From: OddlyTimbot Date: Mon, 15 Jul 2024 17:26:12 -0400 Subject: [PATCH] force push example --- week2/exercise2_jumpcontrol.md | 138 +++++++++++++++++++++++++++++++++ 1 file changed, 138 insertions(+) create mode 100644 week2/exercise2_jumpcontrol.md diff --git a/week2/exercise2_jumpcontrol.md b/week2/exercise2_jumpcontrol.md new file mode 100644 index 0000000..a859ac6 --- /dev/null +++ b/week2/exercise2_jumpcontrol.md @@ -0,0 +1,138 @@ +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 +``` \ No newline at end of file