Untitled

mail@pastecode.io avatar
unknown
plain_text
a year ago
6.9 kB
13
Indexable
Never
extends CharacterBody2D

signal punch_animation_finished

@onready var animation_tree = $AnimationTree
@onready var animation_state_machine = animation_tree.get("parameters/playback")


var DamageLabelScene = load("res://Scenes/DamageLabel.tscn")
var CorpseScene = preload("res://Scenes/Corpse.tscn")

# Punching Variables
enum State {IDLE, MOVING, PUNCHING, RUNNING}
var state = State.IDLE
var punch_key = ""
var punch_damage = randi_range(7, 12)
var stamina_cost = 5
var bodies_in_hitbox = []
var hitbox_collision_shape
var punch_cooldown = 1.0
var punch_timer = 0.0

var walk_speed = 55
var run_speed = 80
var current_speed = walk_speed
var follow_distance = 300
var minimum_distance = 26
var player_follow = false
var player = null
var current_dir = "none"
var last_dir = "down"
var linear_velocity = Vector2.ZERO
var running = false

# Attributes
var maxHealth = 100
var currentHealth
var minHealth = 0
var maxStamina = 100
var currentStamina
var minStamina = 0

var hitbox
var input_vector = Vector2.ZERO
var last_input_vector = Vector2.ZERO

func _ready():
	add_to_group("npc")
	$healthbar.max_value = maxHealth
	currentHealth = maxHealth
	$healthbar.value = currentHealth
	$staminabar.max_value = maxStamina
	currentStamina = maxStamina
	$staminabar.value = currentStamina
	set_motion_mode(MOTION_MODE_FLOATING)
	hitbox = get_node("npc_hitbox")
	hitbox_collision_shape = hitbox.get_node("CollisionShape2D")
	animation_tree.set("parameters/Idle/blend_position", Vector2(0, 1))
	animation_tree.set("parameters/Walk/blend_position", Vector2(0, 1))
	animation_tree.set("parameters/Run/blend_position", Vector2(0, 1))
	animation_tree.set("parameters/RPunch/blend_position", Vector2(0, 1))
	animation_tree.set("parameters/LPunch/blend_position", Vector2(0, 1))
	animation_state_machine.start("Idle")

	#animated_sprite.connect("animation_finished", self, "_on_animated_sprite_2d_animation_finished")

func _physics_process(delta):
	update_running_state()
	if state != State.PUNCHING:
		move_and_slide()
	if player_follow:
		follow_player(delta)
		velocity = linear_velocity
		move_and_slide()
	else:
		velocity = Vector2.ZERO
	
	punch_timer += delta
	if player in bodies_in_hitbox and punch_timer >= punch_cooldown:
		check_punch_condition()
		punch_timer = 0
		
	update_animation()


func update_animation():
	var anim_name = ""

	if state == State.PUNCHING:
		anim_name = "RPunch" if last_input_vector.x > 0 else "LPunch"
	else:
		if input_vector != Vector2.ZERO:
			last_input_vector = input_vector.normalized()

		if state == State.IDLE:
			anim_name = "Idle"
		elif state == State.MOVING and current_speed == walk_speed:
			anim_name = "Walk"
		elif state == State.RUNNING:
			anim_name = "Run"

	if anim_name != "" and animation_state_machine.get_current_node() != anim_name:
		animation_tree.set("parameters/{0}/blend_position".format([anim_name]), last_input_vector)
		animation_state_machine.travel(anim_name)



func play_punch_anim():
	var blend_space_node = "RPunch" if last_input_vector.x > 0 else "LPunch"
	animation_tree.set("parameters/Idle/blend_position", last_input_vector)
	animation_tree.set("parameters/Walk/blend_position", last_input_vector)
	animation_tree.set("parameters/Run/blend_position", last_input_vector)
	animation_tree.set("parameters/RPunch/blend_position", last_input_vector)
	animation_tree.set("parameters/LPunch/blend_position", last_input_vector)
	animation_state_machine.travel(blend_space_node)





func check_punch_condition():
	if state != State.PUNCHING and player in bodies_in_hitbox and punch_timer >= punch_cooldown:
		state=State.PUNCHING # Set state to PUNCHING before calling perform_punch function.
		perform_punch()
		print("hit")
		punch_timer=0

func follow_player(_delta):
	var distance = global_position.distance_to(player.global_position)

	if distance <= follow_distance:
		input_vector = (player.global_position - global_position).normalized()
		linear_velocity = input_vector * current_speed
		if distance < minimum_distance:
			linear_velocity = Vector2.ZERO
	else:
		linear_velocity = Vector2.ZERO

	if linear_velocity.length() < 0.1:
		state = State.IDLE
	else:
		if running:
			state = State.RUNNING
		else:
			state = State.MOVING
		last_input_vector = input_vector.normalized()





func update_running_state():
	if state != State.PUNCHING:
		if currentStamina > 20:
			running = true
			current_speed = run_speed
			state = State.RUNNING
		else:
			running = false
			current_speed = walk_speed
			state = State.MOVING


@warning_ignore("unused_parameter")
func take_damage(damage, attacker_position):
	if currentStamina > 0:
		currentStamina -= damage
		update_stamina_bar()
	else:
		currentHealth -= damage
		update_health_bar()

	var damage_label=DamageLabelScene.instantiate()
	damage_label.text=str(damage)
	damage_label.modulate=Color.WHITE
	var x_offset=randf_range(-10,10) # Adjust the range as needed.
	damage_label.position=Vector2(x_offset,-50)
	add_child(damage_label)

	var tween=get_tree().create_tween()
	tween.tween_property(damage_label,"position:y",damage_label.position.y-100,1)
	tween.tween_property(damage_label,"modulate:a",0,1)

	if currentHealth <= 0:
		die()

func die():
	set_physics_process(false)

	await get_tree().create_timer(15).timeout 
	queue_free()
	$CollisionShape2D.disabled=false


	await get_tree().create_timer(15).timeout 
	queue_free()
	$CollisionShape2D.disabled=false

func create_corpse():
	var corpse=CorpseScene.instance()
	corpse.global_position=get_node("npc").global_position 
	corpse.currentHealth = 0
	corpse.take_damage = null
	#corpse.sprite_resource = animated_sprite.frames
	get_parent().add_child(corpse)

	await get_tree().create_timer(15).timeout

func update_health_bar():
	$healthbar.value = currentHealth

func update_stamina_bar():
	$staminabar.value = currentStamina




func perform_punch():
	if currentStamina > 0:
		punch_damage = randi_range(7, 12)
		play_punch_anim()
		for body in bodies_in_hitbox:
			if body.has_method("take_damage"):
				body.take_damage(punch_damage, global_position)
		currentStamina -= stamina_cost
		state = State.PUNCHING




func _on_detectionarea_body_entered(body):
	if body.is_in_group("player"):
		player = body
		player_follow = true
		set_physics_process(true)
		print("Following player")

func _on_detectionarea_body_exited(body):
	if body.is_in_group("player"):
		player = null
		player_follow = false
		state = State.IDLE  # Set the state to IDLE when the NPC stops following the player
		print("Not following player")


func enemy():
	pass

func _on_npc_hitbox_body_entered(body):
	if body.is_in_group("player"):
		bodies_in_hitbox.append(body)
		print("npc hitbox")
		if not $PunchTimer.is_stopped():
			$PunchTimer.start()

func _on_npc_hitbox_body_exited(body):
	if body.is_in_group("player"):
		bodies_in_hitbox.erase(body)
		print("npc out hitbox")
		$PunchTimer.stop()

func _on_punch_timer_timeout():
	perform_punch()
	print("hit")