You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

实例化对象时Resource未独立?塔防游戏资源共享问题求助

问题

我正在开发一款塔防游戏,每个塔实例都包含一个名为Upgrade的Resource数组,用于记录升级成本和等级,本该每个实例独立,但目前所有实例的资源处于共享状态;同时用于提升攻击范围的Collision Shape也存在共享问题。

经排查,脚本变量已正常复制,但Resource资源未独立。

Upgrade资源代码

class_name Upgrade extends Resource

@export var Name : String
@export var Inital_Cost : float
@export var Upgrade_Value : float = 10
var Cost : int = 0
var Level : float = 1
@export var Max_Level : int = 30
var Growth_Factor : float = 2
var Slot : Array

func Calculate_Cost() -> void:
    var calculated_cost : float = Inital_Cost * pow(Growth_Factor,Level)
    Cost = calculated_cost

塔实例化脚本

extends Node

@export var Basic_Tower : PackedScene
@export var Building_Mode : bool = false
var Current_Tower : Node3D
@export var Raycast : RayCast3D

func _process(_delta):
    if Input.is_action_just_pressed("Interact"):
        Building_Mode = !Building_Mode
    
    # Check which mode we are in and we either clear the hand or we give a tower
    Check_Mode()
    
    # Upgrade code where you can select the tower and upgrade them
    if not Building_Mode and Input.is_action_just_pressed("Left_Click"):
        if Raycast.is_colliding():
            var Obj = Raycast.get_collider()
            if Obj.is_in_group("Tower"):
                EventSystem.Emit_Event("Set_Upgrade_Target",[Obj])
    
    if Current_Tower == null: return
    # This bit allows to place the tower onto the ground
    var Collision_Point = Raycast.get_collision_point()
    
    if Raycast.is_colliding() and Input.is_action_just_pressed("Left_Click"):
            Current_Tower.global_position = Collision_Point
            Current_Tower.set_process_mode(0)
            Current_Tower = null
    elif Raycast.is_colliding():
            Current_Tower.global_position = Collision_Point

func Check_Mode():
    if Building_Mode and Current_Tower == null and Raycast.is_colliding():
        var Instance = Basic_Tower.instantiate()
        Current_Tower = Instance
        Instance.process_mode = 4
        get_tree().get_root().add_child(Instance)
        
    elif not Raycast.is_colliding() and Current_Tower != null:
        Current_Tower.queue_free()
        Current_Tower = null
    elif not Building_Mode and Current_Tower != null:
        Current_Tower.queue_free()
        Current_Tower = null

请问如何让每个塔实例的Resource资源不共享?


解决方案

在Godot中,Resource默认是引用类型,多个实例会共享同一个Resource对象,要实现每个塔实例独立拥有Resource,核心是为每个实例创建Resource的副本,以下是两种可行方案:

方案1:实例化塔时复制Upgrade资源

修改塔实例化逻辑,在创建塔实例后,遍历并复制其Upgrade数组中的每个资源:

# 修改Check_Mode函数中的实例化代码
if Building_Mode and Current_Tower == null and Raycast.is_colliding():
    var Instance = Basic_Tower.instantiate()
    # 假设塔节点有一个名为upgrades的Upgrade数组变量
    if Instance.has_variable("upgrades"):
        var new_upgrades = []
        for upgrade in Instance.upgrades:
            # 复制Resource实例,确保每个塔拥有独立副本
            var upgrade_copy = upgrade.duplicate()
            new_upgrades.append(upgrade_copy)
        Instance.upgrades = new_upgrades
    Current_Tower = Instance
    Instance.process_mode = 4
    get_tree().get_root().add_child(Instance)

方案2:在塔的脚本中初始化独立资源

在塔的脚本中,通过基础配置资源生成实例独立的Upgrade资源,避免直接共享预制体中的资源:

# 塔的核心脚本示例
extends Node3D

@export var base_upgrades : Array[Upgrade] # 预制体中配置的基础参数模板
var upgrades : Array[Upgrade] # 实例专属的升级资源

func _ready():
    upgrades = []
    for base_upgrade in base_upgrades:
        var new_upgrade = base_upgrade.duplicate()
        new_upgrade.Calculate_Cost() # 初始化实例的初始成本
        upgrades.append(new_upgrade)

关于Collision Shape共享问题

Collision Shape共享的原因和Resource一致——多个实例引用了同一个Shape资源,解决思路相同:

# 在塔的_ready函数中复制Shape资源
func _ready():
    var collision_shape_node = $CollisionShape3D
    # 创建Shape副本,确保每个塔的碰撞形状独立
    collision_shape_node.shape = collision_shape_node.shape.duplicate()

内容的提问来源于stack exchange,提问作者Dragon20C

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 06:23:19