captain-holetooth icon indicating copy to clipboard operation
captain-holetooth copied to clipboard

Forest critters: Add animation frames for "turning"

Open oliver-ruehl opened this issue 7 years ago • 4 comments

Turning for NPCs look pretty ugly right now, because its just an instant "snap!". What I would like to achieve is this:

  1. Slight pause before NPC is turning
  2. play 2 frame animation for turning
  3. continue walk

oliver-ruehl avatar Mar 27 '17 06:03 oliver-ruehl

  1. The pause at the start could be part of the turning animation(?)
  2. 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...

YeOldeDM avatar Mar 27 '17 06:03 YeOldeDM

Yes, its the crab monsters almost unchenged in my game

oliver-ruehl avatar Mar 27 '17 07:03 oliver-ruehl

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.

YeOldeDM avatar Mar 28 '17 23:03 YeOldeDM

OK I'll implement it soon

oliver-ruehl avatar Mar 29 '17 14:03 oliver-ruehl