|
|
|
|
Reply From: |
Anaxagor |
Disclaimer, still a bit new to Godot, but this works for our game.
Something simple like this could do, if you have a velocity
var implemented; in this case half the “energy” (speed) is “transferred” from the instigator to the collider.
To try it out, have two KinematicBody2D
with collision shape and this script. Have one with an InitialSpeed
so it moves towards the other.
extends KinematicBody2D
export (Vector2) var InitialSpeed = Vector2(0, 0)
onready var _speed = InitialSpeed
func _physics_process(delta):
var collision = move_and_collide(velocity * delta)
if collision:
collision.collider.velocity = velocity.length() * 0.5 * -collision.normal
velocity = velocity.bounce(collision.normal) * 0.5
Next, something more elaborate, if you want an actual push where the instigator follows through; in this case the instigator pushes the object at half its speed.
I fake the continuous collision (sticking) between instigator and collider since the actual collision will not be detected continuously even if we give the collider the same speed; FP error I suppose. Also note the unresolved issue of colliding with > 1 body that will move the instigator > 1 time.
To try it out, have two KinematicBody2D
with collision shape and this script. Have one with an InitialSpeed
so it moves towards the other with initial speed left to 0.
extends KinematicBody2D
const FLOOR_DIR = Vector2(0, 1)
export (Vector2) var InitialSpeed = Vector2(0, 0)
onready var _speed = InitialSpeed
var _appliedSpeed
var _pushedTimer = 0.0
var _pushedSpeed
func _physics_process(delta):
if _pushedTimer > 0.0:
if _pushedTimer < 0.1:
move_and_slide(_pushedSpeed, FLOOR_DIR)
_pushedTimer -= delta
_appliedSpeed = _speed
_speed = move_and_slide(_speed, FLOOR_DIR)
var slideCount = get_slide_count()
if slideCount > 0:
var pushCollisions = []
for i in range(slideCount):
pushCollisions.append(get_slide_collision(i))
# Process pushed colliders after looping through slide collisions
# since OnPushed can make additional calls to move_and_slide
for collision in pushCollisions:
collision.collider.OnPushed(self, collision.remainder)
func OnPushed(instigator, remainder):
_pushedTimer = 0.1
_pushedSpeed = instigator._appliedSpeed * 0.5
# Move out of the way of the player; the player did not move the full
# value of its speed because of the collision handled here
move_and_slide(_pushedSpeed, FLOOR_DIR)
instigator.ReperformMoveAfterPush(remainder)
#NOTE: should do only once per frame, in case there is more than one
# object pushed
func ReperformMoveAfterPush(remainder):
#NOTE: Not exactly what should be done, this will move the player
# more than required but will *probably* re-collide with the pushable
# anyway.
# We say *probably* since there is the *slide* part of move_and_slide
# that might have change the position from where the same speed will
# not result in another/the same collision.
move_and_slide(remainder, FLOOR_DIR)
_speed = _appliedSpeed # Keep the old speed, as if no collision occurred