• Godot Help
  • Problem With Projectile in a Micro Turn-Based RPG

Godot Version

4.3

I have successfully setup most of a micro, turn-based RPG game. There are two attack types, one where the character himself moves towards the opponent and one where he shoots a projectile. The attack and heal moves are defined as a resource, but the main action happens in the character script which is shared by both player and enemy. The problem i am facing is that while the basic attack action is taking place as expected, the same thing happens when a fireball projectile is supposed to be hurled towards the opponent.

The resources, character and projectile scripts are as follows:

Resource

extends Resource
class_name CombatAction
enum Type {
  Attack,
  Heal
}
@export var display_name : String
@export var action_type : Type
@export_category("Damage")
@export var damage : int
@export var projectile_scene : PackedScene
@export_category("Heal")
@export var heal_amount : int
@export var heal_scene : PackedScene

Character

extends Area2D
signal on_health_change
signal on_die(character : Area2D)

@export var combat_actions : Array[CombatAction]
@export var opponent : Area2D
@export var is_player : bool
@export var character : Area2D
@export var current_health : int = 25
@export var max_health : int = 25

var start_position : Vector2

var attack_opponent : bool
var current_combat_action : CombatAction

func _ready():
    start_position = position
    get_parent().connect("on_begin_turn", on_begin_turn)
    
    
func heal(health_amount : int) -> void:
    current_health += health_amount
    
    if current_health > max_health:
      current_health = max_health
    
    emit_signal ("on_health_change")
    
   
    
func cast_combat_action(combat_action : CombatAction) -> void:
    current_combat_action = combat_action
    if combat_action.damage > 0:
        attack_opponent = true
    elif combat_action.projectile_scene != null:
        var projectile_instance : Sprite2D = combat_action.projectile_scene.instantiate()
        projectile_instance.initialize(opponent, get_parent().end_turn)
        get_parent().add_child(projectile_instance)
        projectile_instance.position = position
        attack_opponent = false
    elif combat_action.heal_amount > 0:
        heal(combat_action.heal_amount)
        get_parent().end_turn()


func _process(delta):
  if attack_opponent:
    position = position.move_toward(opponent.position, delta * 2500)
  if attack_opponent == false:
    position = position.move_toward(start_position, delta * 1500)
    
    
  if position.x == opponent.position.x and attack_opponent:
    attack_opponent = false
    opponent.take_damage(current_combat_action.damage)
    
    
    get_parent().end_turn()
    
func take_damage(damage_to_take : int) -> void:
    current_health -= damage_to_take
    emit_signal("on_health_change")
    
    if current_health <= 0:
      pass
    
    
func on_begin_turn(c: Area2D) -> void:
  if character == c:
    determine_combat_action()
    
    
func determine_combat_action() -> void:
    var health_percentage : float = get_health_percentage()
    var want_to_heal : bool
    var ca : CombatAction
    
    if health_percentage <= 35:
      var random : int = randi() % 3
    
      if random == 0:
          want_to_heal = true
    
    if want_to_heal and has_combat_action_of_type(CombatAction.Type.Heal):
      ca = get_combat_action_of_type(CombatAction.Type.Heal)
    elif has_combat_action_of_type(CombatAction.Type.Attack):
      ca = get_combat_action_of_type(CombatAction.Type.Attack)
        
        
      if ca != null:
        cast_combat_action(ca)
        
      else:
       get_parent().end_turn()

    
func get_health_percentage() -> float:
    return float(current_health) / float(max_health) * 100
   
func has_combat_action_of_type(type : CombatAction.Type) -> bool:
  for element in combat_actions:
    if element.action_type == type:
      return true
  return false
    
func get_combat_action_of_type(type : CombatAction.Type) -> CombatAction:
  var available_actions : Array[CombatAction] = []
  
  for element in combat_actions:
    if element.action_type == type:
      available_actions.append(element)
      
  return available_actions[randi() % available_actions.size()]`

Projectile

extends Sprite2D
 
signal hit_callback

@export var damage : int
@export var speed: float

var target : Area2D

func initialize(projectile_target : Area2D, on_hit_callback: Callable) -> void:
    target = projectile_target
    hit_callback.connect(on_hit_callback)
    
func _process(delta):
    if target == null:
        return
        
    position = position.move_toward(target.position, speed * delta)
    
    if position == target.position:
        target.take_damage(damage)
        emit_signal("hit_callback")
        queue_free()

Please let me know if you need further information to help me!

  • xyz replied to this.

    vivekchakraverty Learn to debug your code by planting print statements and breakpoints in important or suspicious parts. This will let you surveil if the code does what you expect it to every step of the way and if variables have expected values.