captain-holetooth
captain-holetooth copied to clipboard
Forest critters: Add animation frames for "turning"
Turning for NPCs look pretty ugly right now, because its just an instant "snap!". What I would like to achieve is this:
- Slight pause before NPC is turning
- play 2 frame animation for turning
- continue walk
- The pause at the start could be part of the turning animation(?)
- The animationplayer should emit a "finished" signal when the animation is done
That would give you what you need to catch when to allow/disallow movement. I would have to look at the code for the NPCs (the red crabs from the demo?) to see the best approach. Probably a flag on the monster that disallows movement when TRUE. The function that initiates the animation will make it True, and the finished signal will make it False.
When I have the time I can monkey with the code and see how it works in practice. It shouldn't be too complex, but you never know...
Yes, its the crab monsters almost unchenged in my game
Yes, this should be do-able with minimal adjusting of the existing script.
Here's a rundown of the steps I take. All code is being done on forest_crawler.gd:
- New animation for Turning: Add a callfunc track pointing to the enemy base node, at the end of the animation, add a key with the name "_done_turning"
- declare new state constant
STATE_TURNING = 2
- check if current state is STATE_TURNING, convert that bool to int, which gives 0 or 1:
var W = int(state!=STATE_TURNING)
- line 80, where linear velocity for that frame is set, multiply by W:
lv.x = direction*WALK_SPEED*W
- whenever the integrate forces loop changes direction:
direction = -direction
, we define 'turn' as the new_anim and set state to STATE_TURNING:new_anim = "turn"; state = STATE_TURNING
- define the
_done_turning
function which will set state back to STATE_WALKING
Here's what the script looks like with the changes:
extends RigidBody2D
# Member variables
const STATE_WALKING = 0
const STATE_DYING = 1
const STATE_TURNING = 2
var state = STATE_WALKING
var direction = -1
var anim = ""
var rc_left = null
var rc_right = null
var WALK_SPEED = 50
var bullet_class = preload("res://src/actors/player/bullet.gd")
var destroyed = false
func _die():
destroyed = true
queue_free()
func _pre_explode():
# Stay there
clear_shapes()
set_mode(MODE_STATIC)
get_node("sfx").play("cork_pop")
func _integrate_forces(s):
var lv = s.get_linear_velocity()
var new_anim = anim
if (state == STATE_DYING):
new_anim = "explode"
elif (state == STATE_WALKING):
new_anim = "walk"
var wall_side = 0.0
for i in range(s.get_contact_count()):
var cc = s.get_contact_collider_object(i)
var dp = s.get_contact_local_normal(i)
if (cc):
if (cc extends bullet_class and not cc.disabled):
set_mode(MODE_RIGID)
state = STATE_DYING
#lv = s.get_contact_local_normal(i)*400
s.set_angular_velocity(sign(dp.x)*33.0)
set_friction(1)
cc.disable()
game.reset_bonus_score()
get_node("sfx").play("punch")
break
if (dp.x > 0.9):
wall_side = 1.0
elif (dp.x < -0.9):
wall_side = -1.0
if (wall_side != 0 and wall_side != direction):
direction = -direction
get_node("sprite").set_scale(Vector2(-direction, 1))
# set turning state
new_anim = 'turn'
state = STATE_TURNING
if (direction < 0 and not rc_left.is_colliding() and rc_right.is_colliding()):
direction = -direction
get_node("sprite").set_scale(Vector2(-direction, 1))
# set turning state
new_anim = 'turn'
state = STATE_TURNING
elif (direction > 0 and not rc_right.is_colliding() and rc_left.is_colliding()):
direction = -direction
get_node("sprite").set_scale(Vector2(-direction, 1))
# set turning state
new_anim = 'turn'
state = STATE_TURNING
var W = int(state != STATE_TURNING)
lv.x = direction*WALK_SPEED*W
if(anim != new_anim):
anim = new_anim
get_node("anim").play(anim)
s.set_linear_velocity(lv)
func _ready():
rc_left = get_node("raycast_left")
rc_right = get_node("raycast_right")
func _done_turning():
state = STATE_WALKING
I tested it a little and it appears to be doing what it should.
OK I'll implement it soon