How to store game data in Godot? Dictionary vs Resource

I am trying to create a utility-based AI system in a Godot project (reference). Basically, it funnels game data into considerations which drive actions. In order to do this, I need to store relevant game data in Godot.

For example, suppose I have a LineOfSightComponent which has target and ray_to_target within it. Whether an NPC has line of sight on a target or not determines whether they can Chase the target. If they decide to Chase, the NPC also needs this information to move towards the target (say, the Player). This can apply to lots of different situations (e.g. a HealthRemaining consideration needing hp and MAX_HP game data from NPC, a Threat consideration needing data from the Player, etc.).

With that in mind, what is the best way to store this data? I’ve been reading about Resources in Godot, but I’m not sure what advantages it has over my current setup. I made a Dictionary-based Database that is stored in the “Game” scene and collects data on anything that extends a “Data” class I made.

Here is the Database class:

# database.gd

extends Node
class_name Database

var game_state: Dictionary

func _ready():
    traverse_tree(get_tree().root)

## Add all data to game_state. Connect data signals to Database
func traverse_tree(node):
    # Add CharacterBody2D nodes to Database
    if node is CharacterBody2D:
        # Ensure the node dictionary exists in game_state
        if not game_state.has(node.name.to_lower()):
            game_state[node.name.to_lower()] = {}
        
        # Add CharacterBody2D node
        game_state[node.name.to_lower()]["self"] = node
        
    
    for child in node.get_children():
    
        # Add Data node to Database
        if child is Data:
            # Ensure the node dictionary exists in game_state
            if not game_state.has(node.name.to_lower()):
                game_state[node.name.to_lower()] = {}
            
            # Add data
            game_state[node.name.to_lower()][child.name.to_lower()] = child.get_data()
            
            #print("game state: ", game_state) # Debug
            
            # Connect data_changed signal in Data to _on_data_changed() method in Database
            child.connect("data_changed", Callable(self, "_on_data_changed"))
        
        # Allow Considerations to request Database data
        elif child is Consideration:
            # Connect data_request signal in Consideration to _on_request_data() method in Database
            child.connect("data_request", Callable(self, "_on_request_data"))
        
        # Allow any child with request_data() method and data_request signal,
        # i.e. with proper infrastructure, to request Database data
        else:
            # Check if child has request_data() method
            if child.has_method("request_data"):
                var properties = child.get_property_list()
                # Check if child has data_request signal
                for property in properties:
                    if property.name == "data_request":
                        print("Connecting %s to Database..." % [child.name.to_lower()])
                        child.connect("data_request", Callable(self, "_on_request_data"))
                        break
        
        traverse_tree(child) # Recursively check all sub-trees

## Update game_state when data changes
func _on_data_changed(node_name, child_name, data):
    game_state[node_name][child_name] = data

func _on_request_data(node_key, child_key, requester):
    # Check game_state has requested data
    if node_key in game_state:
        if child_key in game_state[node_key]:
            if requester.has_method("receive_data"): # Check requester can receive data 
                requester.receive_data(node_key, child_key, game_state[node_key][child_key]) # Send data

Here is the Data class:

# data.gd

extends Node
class_name Data

signal data_changed(node_name, new_data)

func get_data() -> Dictionary: 
    return {} # Returns data formatted as a Dictionary

func update_data(): 
    data_changed.emit(self.get_parent().name.to_lower(), self.name.to_lower(), get_data())

Here is an example extension of the Data class:

extends Data
# Line of Sight Component
class_name LoSComponent

var target: CharacterBody2D = null
var ray_to_target: RayCast2D = null
signal target_found(entity: CharacterBody2D, ray: RayCast2D)

func get_data():
    return {
        "target": target,
        "ray_to_target": ray_to_target
    }

# ... (implementation goes here) ... #

And here is an example of calling this data for use in a consideration:

extends Consideration

func _ready():
    self.parent_keys = ["npc"]
    self.data_keys = ["loscomponent"] 

## Return 1.0 if there is line of sight, else 0.0
func get_derived_value() -> float:
    if data.has("npc"):
        if data["npc"]["loscomponent"]["target"] != null: 
            return 1.0
    return 0.0

Would using Resources be better than this system? As the code scales in complexity, I would like something that doesn’t rely on a strict file structure; if I move a scene or node somewhere, I wouldn’t like want ten other files to break. Resources seem to require the load() method, which requires a file path. On the other hand, I can see some potential downsides to nested Dictionaries. For one thing, I really only need to read the data; I don’t want to create copies, and any data change should be sent out as a signal.

All this has left me a bit stuck on what’s best for this case. Any advice?

New contributor

Michael Peters is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa
Thiết kế website Thiết kế website Thiết kế website Cách kháng tài khoản quảng cáo Mua bán Fanpage Facebook Dịch vụ SEO Tổ chức sinh nhật