Godot Version
godot 3.5
Question
this one has been bugging me for a while so i think i need help. I finally busted open an old game i was making (hence it being in 3.5) and i’m trying to do an interrupted function, where when a player hits an enemy or vice versa, it also interrupts the other party’s attack. I’ve got a little bit of interrupted code, but i’ve googled and I’m at a loss of how to preumaturely end an animation like an attack animation, that normally plays until end.
I feel like I probably just have the wrong search terms, but if anyone else knows how to help that would be good.
Here is waht I have os far for code (its not much)
#this is the func we call to make it so that whoever was hit cannot do another hting
#until their interrupted timer passes
func interrupted():
var sprites_to_freeze = [0] #fuck it it doesn't even need to be all sprites
#we need to freeze the node
#NOW I am thinking lets freeze indivdiual parts...
#if we want a knockback...
can_move = false
sprites_to_freeze = check_nodes_types_and_return_sprites()
#okay this dont work in an array :X so we must loop
for i in sprites_to_freeze.size():
sprites_to_freeze[i].self_modulate = Color(0, 0, 1)
right now, as you can see, it just freezes th sprites, but does not make the one hit restart their animation.
here is the full script, though i think tahts the relevant part up there.
extends KinematicBody2D
var velocity = Vector2(0,0)
export var maxHealth = 10.0 #use for diffiuclty lvl mods
export var currentHealth = 10.0 #use for difficulty lvl mods
export var damage_done = 1.0#affects how much the user (this script) does in damage
export var damage_taken = 1.0 #for difficultymods. affects damage reduction
var knockback_smidge_value = 3.0 #totally guessed the value. we use this when deciding
#which way to knock the combatant - diagnoally or in 4 directions
export var is_pushable = true
#use knockback amount also for diffuclty lvl mods
export var knockback_amount = 200 #this affects how much WE (the combatant ) are knocked back
#NOT how much the combatant knocks other people back!!!!
var maxHealth_modded
var currentHealth_modded
var damage_done_modded
var damage_taken_modded
var knockback_modded
var charge_speed_modded
var attack_speed_modded
export var team = "enemy"
enum directions {DOWN, RIGHT, UP, LEFT, UPRIGHT, UPLEFT, DOWNRIGHT, DOWNLEFT}
var facing = directions.DOWN
var prev_facing = facing
var can_take_damage = false
var is_in_safezone = false
var can_move = true
onready var immunity_timer = $ImmunityTimer
onready var interrupted_timer = $InterruptedTimer
onready var healthbar_total = $HealthBarTotal
onready var healthbar_current = $HealthBarTotal/HealthBarCurrent
onready var healthbar_new = $HealthBarNew
#thinking we're gonna need a placeholder sprite for tihs
#and then whenever we are changing the sprite in code on the player
#or enemy. we use this name, to modulate it!
#onready var sprite_holder = $Sprite
onready var test_sprite = $TestSprite
# Called when the node enters the scene tree for the first time.
func _ready():
#do we update difficulty mods here? Or manually on player and enemies?
#maybe i DO have to do it in the parent.... (here)
update_difficulty_lvl()
#we need to update health bar when we HEAL too!!!!
#function for taking damage should be here!
#so ... when we take damage we ALSO need to stop our current action!
func take_damage(var damage):
currentHealth_modded -= (damage * damage_taken_modded)
update_small_healthbar(currentHealth_modded)
#if we're dead, we dont need the timers!
if currentHealth_modded <= 0:
on_death()
else:
#knockback willb e called from the player GIVING damage, not here
#call interrupted to interrupt them
if interrupted_timer != null:
interrupted()
immune()
interrupted_timer.start()
immunity_timer.start()
else:
print ("Interrupted timer was null")
#dont think i've added custom knockback functionality yet. may add later.
#called in area entereds, on teh player/ item giving damage
func knockback(var dam_pos):
#first we need to compare the abs value. make sure that there is big
#enough difference to actually make it diagnonal (as opposed to just 4 directoinal)
var x_dif = self.position.x - dam_pos.x
var y_dif = self.position.y - dam_pos.y
var _abs_x_dif = abs(x_dif)
var abs_y_dif = abs(y_dif) #could do this in just two lines with abs around the expressoin
#but i noob and wnat it readable
if self.global_position.x < dam_pos.x:
#if the damage comes FROM the right.
if abs_y_dif <= knockback_smidge_value:
#we are in range. knocke em to the left
#it looks like we used move_and_slide for the player and moveable enemies
velocity.x += -knockback_amount
elif self.global_position.y < dam_pos.y:
#the damage comes FROM down direction
#knock em upleft
velocity.x += -knockback_amount
velocity.y += -knockback_amount
else:
#its not in smidge and not from down, it must be from up.
#knock em downleft
velocity.x += -knockback_amount
velocity.y += knockback_amount
elif self.global_position.x > dam_pos.x:
#damage came from the LEFT
if abs_y_dif <= knockback_smidge_value:
#knock em right
velocity.x += knockback_amount
elif self.global_position.y < dam_pos.y:
#damage comes FROM down directoin
#knock them up right
velocity.x += knockback_amount
velocity.y += -knockback_amount
else:
#dmaage should be coming from up.
#knock em downright
velocity.x += knockback_amount
velocity.y += knockback_amount
elif self.global_postiion.y < dam_pos.y:
#damage coming FROM down.
#we dont need to check for x smidge value as we started w/ x logic
#and its elfi
#knock em up
velocity.y += -knockback_amount
else:
#knocek em donw
velocity.y += knockback_amount
#this is the func we call to make it so that whoever was hit cannot do another hting
#until their interrupted timer passes
func interrupted():
var sprites_to_freeze = [0] #fuck it it doesn't even need to be all sprites
#we need to freeze the node
#NOW I am thinking lets freeze indivdiual parts...
#if we want a knockback...
can_move = false
sprites_to_freeze = check_nodes_types_and_return_sprites()
#okay this dont work in an array :X so we must loop
for i in sprites_to_freeze.size():
sprites_to_freeze[i].self_modulate = Color(0, 0, 1)
#This lasts longer than interrupted
func immune():
can_take_damage = false
var sprites = [0]
sprites = check_nodes_types_and_return_sprites()
for i in sprites.size():
sprites[i].self_modulate = Color(0, 0, 1, .5)
# we need to make the node see through or a slightly different color
#to clarify they cannot take damage now
#sprite_holder.self_modulate.a = 0.5 #jsut a test value
#function for actually updating our little health bar
func update_small_healthbar(new_value):
healthbar_new.value = new_value
# var transform_vector = Vector2(currentHealth_modded/ maxHealth_modded, 1)
# #we need to make it anchord to one side
# #could use set offset.
# #need to do some math probably to make it work though
# #when current health gets smaller, the amount of room by the bar is increased. which does make sense
# #ugh what kidn of math do i need to do to make this right
# #accoridng to print staement, bigger negative numbers numbers = more to the right
# #no thats just when it gets smaller. oops. because it is CENTERED
# var offset_vec = Vector2((0.5 * -maxHealth_modded), 0)
# print ("from character parent script and update small healthbar func, offset vec is")
# print (offset_vec)
# healthbar_current.set_offset(offset_vec)
# healthbar_current.set_scale(transform_vector)
#for destroying ourself if we die?
#or at least stopping our movement
func on_death():
set_physics_process(false)
set_process(false)
#play the animation for dying
#or we could just fade out? IG
func _on_ImmunityTimer_timeout():
can_take_damage = true #now we can take damage again
var sprites = [0]
sprites = check_nodes_types_and_return_sprites()
for i in sprites.size():
#this null check is very important. otherwise it bugs
#cuz of the first null sprite!
if sprites[i] != null:
sprites[i].self_modulate = Color(1, 1, 1, 1)
#so ...w e need to get ourself and all our children
#and see which are sprite nodes
#nad then return tehm!
func check_nodes_types_and_return_sprites():
# var array_of_children = [] #hahah crap we're gonna have an off by oen error
# var num_of_children
var array_of_sprites = [test_sprite]
#cuz of godots weird way to set arrays
for i in self.get_children():
#array_of_children.append(i)
if i is Sprite:
array_of_sprites.append(i)
#alrighty... test sprite is STILL null WTF.
#but w/es. ill deal with tha tlater
#print (array_of_sprites)
return array_of_sprites
#minus one is testing for off by one errors. I THINK
# num_of_children = array_of_children.size() - 1
# for n in range(0, num_of_children):
#DONT Delete this
#okay im a dumb dumb. i acutally need to get facing dir for raycasting code to work
#as it uses the facing dir to decide which way to cast the ray
#so this won't work on enemies at times?
#but it always works on player
#It LOOKS like when the enemy collides with the player, then they cannot get facing!
func get_facing_dir():
#if we are moving, we can change the facing dir
if velocity != Vector2(0,0):
#if we are moving positive in x dir
if velocity.x > 0.1:
#and not moving on y dir
if velocity.y == 0:
facing = directions.RIGHT
#if we are moving positive in y and x (remmeber, pos y is down)
elif velocity.y > 0.1:
facing = directions.DOWNRIGHT
elif velocity.y < -0.1:
facing = directions.UPRIGHT
#if we are moving left
elif velocity.x < -0.1:
if velocity.y == 0:
facing = directions.LEFT
elif velocity.y < -0.1:
facing = directions.UPLEFT
elif velocity.y > 0.1:
facing = directions.DOWNLEFT
elif velocity.y < -0.1 and velocity.x == 0:
facing = directions.UP
elif velocity.y > 0.1 and velocity.x == 0:
facing = directions.DOWN
#we enter else sometimes. need to find out why!
# else:
# print("could not get facing direction")
#we cannot simply use velocity
#because the entity may have zero velocity
#but still be facing in a direction
func get_facing_dir_as_vector():
match facing:
directions.DOWN:
return Vector2(0,1)
directions.UP:
return Vector2(0,-1)
directions.RIGHT:
return Vector2(1,0)
directions.LEFT:
return Vector2(-1,0)
directions.UPRIGHT:
return Vector2(1,-1).normalized()
directions.UPLEFT:
return Vector2(-1,-1).normalized()
directions.DOWNRIGHT:
return Vector2(1,1).normalized()
directions.DOWNLEFT:
return Vector2(-1,1).normalized()
#we need a way to update our variables.... for difficulty mods
func update_difficulty_lvl():
if team == "player":
#do player stuff
#do we have to laod current health and max health differently?
#based on IF the player or enemy already has helath off or not?
#I THINK SO
if currentHealth_modded == maxHealth_modded:
maxHealth_modded = maxHealth * DifficultyManager.p_health_mod
currentHealth_modded = maxHealth
healthbar_new.max_value = maxHealth_modded
healthbar_new.value = currentHealth_modded
#we need to check for IF they have already been modified... hmmm
#maybe i need hte bases as variables and hten teh modified variants as varialbes
#that seems overly complicated but lets try it
damage_done_modded = damage_done * DifficultyManager.p_damage_mod
damage_taken_modded = damage_taken * DifficultyManager.p_damage_per_taken
knockback_modded = knockback_amount * DifficultyManager.p_knocked_back
attack_speed_modded = 1.0 #multiplicative
charge_speed_modded = 1.0
elif team == "enemy":
#do enemy stuff:
if currentHealth_modded == maxHealth_modded:
maxHealth_modded = maxHealth * DifficultyManager.e_health_mod
currentHealth_modded = maxHealth_modded
healthbar_new.max_value = maxHealth_modded
healthbar_new.value = currentHealth_modded
damage_done_modded = damage_done * DifficultyManager.e_damage_mod
damage_taken_modded = damage_taken * DifficultyManager.e_damage_per_taken
knockback_modded = knockback_amount * DifficultyManager.e_knocked_back
#for some reason attack speed modded is being an ITEM/ node, NOT a number!!!!
#so is charge speed, fyi
attack_speed_modded = DifficultyManager.e_attack_speed
charge_speed_modded = DifficultyManager.e_charge_speed
else:
#probably frienld. do nothing
pass
#our save dict func
func save():
var save_dict = {
"filename" : get_filename(),
"parent" : get_parent().get_path(),
"pos_x" : position.x, #Vector 2 is not supported by JSON
"pos_y" : position.y,
"maxHealth" : maxHealth,
"currentHealth" : currentHealth,
"maxHealth_modded": maxHealth_modded,
"currentHealth_modded": currentHealth_modded,
"team" : team
}
return save_dict
func _on_InteruptedTimer_timeout():
var sprites_to_unfreeze = [0] #fuck it it doesn't even need to be all sprites
can_move = true
sprites_to_unfreeze = check_nodes_types_and_return_sprites()
#print ("Now we will print the sprites we are UNfreezing")
#print (sprites_to_unfreeze)
set_process(true)
set_physics_process(true)
for i in sprites_to_unfreeze.size():
sprites_to_unfreeze[i].self_modulate = Color(1, 1, 1, .5)
EDit; sorry realized i have moer info. I did override the player and enemy interrupted functions (they inherit from teh same combatant script)
here is the enemies overrode f unction:
func interrupted():
state = states.APPROACHTOATTACK
animation_tree.advance(0)#trhis doens't seem to be working :< ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#(hit box is in the attack anim)
var sprites_to_freeze = [] #fuck it it doesn't even need to be all sprites
#we need to freeze the node
can_move = false
sprites_to_freeze = check_nodes_types_and_return_sprites()
#okay this dont work in an array :X so we must loop
for i in sprites_to_freeze.size():
sprites_to_freeze[i].self_modulate = Color(0, 0, 1)
and here is the players :
func interrupted():
var sprites_to_freeze = [] #fuck it it doesn't even need to be all sprites
#we need to freeze the node
can_move = false
# set_process(false)
# set_physics_process(false)
sprites_to_freeze = check_nodes_types_and_return_sprites()
#print ("Now we will print the sprites we are freezing")
#print (sprites_to_freeze)
#okay this dont work in an array :X so we must loop
for i in sprites_to_freeze.size():
sprites_to_freeze[i].self_modulate = Color(0, 0, 1)
idle_sprite.visible = true
attack_sprite.visible = false
run_sprite.visible = false
animation_state.travel("Idle")