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

Godot 4中基于相邻实例修改纹理的2D农场模拟器问题

2D农场模拟器相邻地块纹理融合问题

我正在制作一款2D农场模拟器,实例化植物时初始采用1格纹理;当在某地块相邻位置创建新的植物实例时,希望切换该地块的Atlas Texture图集纹理,让两者视觉融合更自然。我尝试遍历"Dirt"组内的所有实例,检测周边位置后按需修改纹理,但用var instances = get_tree().get_nodes_in_group("Dirt")循环检测的方法没成功。

以下是我的"Dirt"实例代码:

extends Area2D
const Corn = preload("res://assets/Objects/Farming/Corn/corn_growth2.tscn")
var timer = Timer.new()
var has_seed = false

func _on_input_event(viewport, event, shape_idx):
    if !has_seed:
        if Input.is_action_pressed("plant_action"):
            var Corn1 = Corn.instantiate()
            Corn1.position = Vector2(0,0)
            self.add_child(Corn1)
            has_seed = true

func cambiarRegion(x: float, y: float) -> void:
    var texture_atlas: AtlasTexture = $Sprite2D.texture
    var region_size: Vector2 = Vector2(16, 16)
    var new_region_rect = Rect2(Vector2(x, y), region_size)
    texture_atlas.region = new_region_rect
    $Sprite2D.texture = texture_atlas

(注:附有循环逻辑及实例状态的截图)


问题排查与解决方案

1. 核心问题分析

你当前的代码缺少种植完成后的相邻地块检测逻辑,且直接修改共享的AtlasTexture会导致所有使用该图集的地块纹理同步变化,这是循环检测失效的主要原因。

2. 完整修改方案

步骤1:添加网格坐标属性

给Dirt实例添加网格坐标,用于精准定位相邻地块(假设每个地块尺寸为16x16像素):

extends Area2D
const Corn = preload("res://assets/Objects/Farming/Corn/corn_growth2.tscn")
var timer = Timer.new()
var has_seed = false
# 记录当前地块的网格坐标(实例化时自动计算)
var grid_pos: Vector2

func _ready():
    # 通过全局位置转换为网格坐标
    grid_pos = global_position / 16
    add_to_group("Dirt")

步骤2:修复种植触发逻辑

避免长按重复种植,改为检测鼠标点击事件:

func _on_input_event(viewport, event, shape_idx):
    # 仅在鼠标左键按下且未种植时触发
    if !has_seed and event is InputEventMouseButton and event.pressed and event.button_index == BUTTON_LEFT:
        if Input.is_action_pressed("plant_action"):
            var Corn1 = Corn.instantiate()
            Corn1.position = Vector2(0,0)
            self.add_child(Corn1)
            has_seed = true
            # 种植完成后立即更新当前及周边地块纹理
            update_surrounding_textures()

步骤3:实现相邻检测与纹理更新

添加检测周边地块并更新纹理的逻辑:

func update_surrounding_textures():
    # 先更新当前地块纹理
    update_self_texture()
    # 遍历上下左右四个相邻方向
    var directions = [Vector2(0, -1), Vector2(0, 1), Vector2(-1, 0), Vector2(1, 0)]
    for dir in directions:
        var target_grid = grid_pos + dir
        # 查找对应网格位置的Dirt实例
        for dirt in get_tree().get_nodes_in_group("Dirt"):
            if dirt.grid_pos == target_grid and dirt.has_seed:
                dirt.update_self_texture()

func update_self_texture():
    # 检测四个方向是否有已种植的地块
    var left_has = check_neighbor(Vector2(-1, 0))
    var right_has = check_neighbor(Vector2(1, 0))
    var up_has = check_neighbor(Vector2(0, -1))
    var down_has = check_neighbor(Vector2(0, 1))

    # 根据相邻情况选择Atlas纹理区域(需根据你的图集排版调整坐标)
    var atlas_x = 0
    var atlas_y = 0
    # 示例逻辑:单独地块用(0,0),左右都有则用(1,0),仅左边有则用(2,0),仅右边有则用(3,0)
    if left_has and right_has:
        atlas_x = 1
    elif left_has:
        atlas_x = 2
    elif right_has:
        atlas_x = 3
    # 上下方向的纹理逻辑可按需扩展
    cambiarRegion(atlas_x * 16, atlas_y * 16)

func check_neighbor(dir: Vector2) -> bool:
    # 检测指定方向是否有已种植的Dirt实例
    var target_grid = grid_pos + dir
    for dirt in get_tree().get_nodes_in_group("Dirt"):
        if dirt.grid_pos == target_grid and dirt.has_seed:
            return true
    return false

步骤4:修复AtlasTexture修改逻辑

直接修改原图集会影响所有共享实例,需创建副本后再修改:

func cambiarRegion(x: float, y: float) -> void:
    var texture_atlas: AtlasTexture = $Sprite2D.texture
    var region_size: Vector2 = Vector2(16, 16)
    var new_region_rect = Rect2(Vector2(x, y), region_size)
    # 创建图集副本避免影响其他实例
    var new_atlas = texture_atlas.duplicate()
    new_atlas.region = new_region_rect
    $Sprite2D.texture = new_atlas

关键修复点

  • 避免共享图集污染:必须使用duplicate()创建AtlasTexture副本,否则修改会同步到所有使用该图集的地块。
  • 精准网格定位:用网格坐标替代全局位置比较,避免浮点误差导致的相邻检测失败。
  • 主动触发更新:种植完成后立即触发纹理更新,无需被动等待循环检测。

内容的提问来源于stack exchange,提问作者Ricardo Arcesio Villanueva

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 23:55:17