Cyclic dependency error between actor and actor controller

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By AaronWizard

I have an Actor class and a Controller class. Each actor has a controller which may either be the player or an AI.

I’ve started with this:

# actor.gd
# Scene has a child Controller node
extends Node2D

class_name Actor

onready var controller : Controller = $Controller

func _process(delta: float) -> void:
	controller.run(self, delta)

----

# controller.gd
# Subclassed for different behaviour. i.e. Player control and different AI types
extends Node

class_name Controller

func run(actor: Actor, delta: float) -> void:
	...

But this causes a cyclic dependency error.
How else should I arrange this?

(I’ve considered that making controllers the parents of actors is an option, but that wouldn’t be feasible for me. It’s the actors that get placed in the level, and I’d want to be able to take an actor and change what controller it has.)

:bust_in_silhouette: Reply From: AaronWizard

After discussing this elsewhere, the conclusion is to not specify types where they’d cause cyclic dependencies.

# controller.gd
# Same as before

class_name Controller

func run(actor: Actor, delta: float) -> void:
    ...

---

# actor.gd
extends Node2D

class_name Actor

onready var controller = $Controller # Type not specified

func _process(delta: float) -> void:
	controller.run(self, delta)

This is actually similar to what’s done in the GDQuest OpenRPG project. In combat scenes there are Battlers that have BattlerAIs. Battlers have a variable for their BattlerAI but they don’t specify its type.

# CombatArena.gd
extends Node2D
class_name CombatArena

...

func play_turn():
    var battler : Battler = get_active_battler()
    var targets : Array
    var action : CombatAction
    ...
    action = yield(battler.ai.choose_action(battler, opponents), "completed")
    targets = yield(battler.ai.choose_target(battler, action, opponents), "completed")
    ...

---

# BattlerAI.gd
extends Node
class_name BattlerAI

func choose_action(actor : Battler, battlers : Array = []):
    ...

func choose_target(actor : Battler, action : CombatAction, battlers : Array = []):
    ...

---

# Battler.gd
extends Position2D
class_name Battler

...

onready var ai = $AI # Not typed

...

Any way to get “jump to declaration / definition” working without specyfing of the class?

DarklinkFighter | 2020-08-03 22:56

:bust_in_silhouette: Reply From: Galilus

Hi, until now I have used the below recommendation. To simply avoid this issue.

This week I noticed not to have this error when creating the parent or referred class in a different folder.

Folder
L baseclass.GD
L Folder
| L ExtendedClass.GD #extends baseclass