godotengine / godot-proposals

Godot Improvement Proposals (GIPs)
MIT License
1.12k stars 69 forks source link

Implement scripts for individual GridMap tiles #673

Open CaveJohnson376 opened 4 years ago

CaveJohnson376 commented 4 years ago

Describe the project you are working on: Some kind of Minecraft clone

Describe the problem or limitation you are having in your project: Limited functional of gridmap tiles

Describe the feature / enhancement and how it helps to overcome the problem or limitation: You can add script to tile in meshlib, and control this specific tile without changing tile type, position and orientation.

Describe how your proposal will work, with code, pseudocode, mockups, and/or diagrams: GridmapTile class with properties: Position (readonly) - position of tile in gridmap's space Tile ID (readonly) - ID of tile in meshlib Orientation Model Material Script (readonly) Gridmap (readonly) - gridmap this tile part of

If this enhancement will not be used often, can it be worked around with a few lines of script?: It can't be worked around, as if my game will have either much more tiles for each state of it, or static tiles only

Is there a reason why this should be core and not an add-on in the asset library?: I'm not sure it is possible to do that as an addon.

RichardEllicott commented 3 years ago

doesn't this fundamentally defeat the purpose of the GridMap?

the GridMap is using instances i thought, so they have to all be the same and that's fundamental to how Godot is saving memory with a GridMap

me2beats commented 3 years ago

Is this even possible 🤔

aclave1 commented 3 years ago

Adding a script per tile instance wouldn't really be possible. I think currently a more reasonable approach from a performance perspective would be to to attach a script to the gridmap and build an abstraction layer to implement this logic.

Here's how I handle this currently - I lookup the mesh name of a tile using the meshlib and then I have a mapping from mesh name -> mesh type. This allows me to attach one script per gridmap and have logic per tile type.

# Terrain types
const TYPE_GRASS = "grass"
const TYPE_DIRT = "dirt"
const TYPE_PLANTED = "planted"
const TYPE_CONCRETE = "concrete"

var type_to_resource = {
    TYPE_GRASS: TYPE_GRASS,
    TYPE_DIRT: TYPE_DIRT,
    TYPE_PLANTED: "dirt_planted",
    TYPE_CONCRETE: TYPE_CONCRETE,
}
var _resource_to_type = invert_dict(_type_to_resource)
export(NodePath)var GRIDMAP_PATH = NodePath()
onready var gridmap:GridMap = get_node(GRIDMAP_PATH)
onready var meshlib:MeshLibrary = gridmap.mesh_library

# Get the terrain type of a cell in the gridmap
func get_terrain_type(grid_coords:Vector3):
    var mesh_item_id = gridmap.get_cell_item(grid_coords.x, grid_coords.y, grid_coords.z)
    var mesh = meshlib.get_item_mesh(mesh_item_id)
    if !mesh:
        return null
    return get_type_name(mesh.resource_name)

# Mapping from terrain type to .mesh filename in assets/3D/terrain
func get_resource_name(type_name:String):
    return _type_to_resource.get(type_name, TYPE_DIRT)

# Mapping from .mesh filename to terrain type
func get_type_name(resource_name:String):
    return _resource_to_type.get(resource_name, TYPE_DIRT)  

I've also built gridmap based navigation using AStar with this approach. Water tiles are non navigable, dirt is 1 movement cost and grass is 2 movement cost.

One thing that's frustrating with this approach is using the name of the mesh to determine the terrain type.

What I propose to be included into Godot instead is to be able to attach custom properties to the meshes in the gridmap and lookup those. That way when I lookup a certain coordinate's properties and determine if it's a grass tile instead of comparing the name.

eimfach commented 11 months ago

But what if I want to have navigation per only one vector (in the center of a tile) per tile ? At the moment I am not using GridMap and my tiles use RayCasts for navigation and detecting objects/subjects occupying the tile. I can't wrap my head around GridMap, as I have no idea how it works internally (not scene tree based) but I want to create dungeons procedurally...