Compare commits
8 Commits
83404d031e
...
3d6c4e5356
| Author | SHA1 | Date | |
|---|---|---|---|
| 3d6c4e5356 | |||
| c621d70475 | |||
| f527fa3c38 | |||
| e9fa21280e | |||
| a3d384d39d | |||
| ced69fd4b6 | |||
| 7a6e5be4f8 | |||
| ba5b0daa13 |
@@ -51,6 +51,8 @@ const SCENE_DATA_TRANSFER = "scene_data_transfer"
|
|||||||
const TILEMAP_READY = "tilemap_ready"
|
const TILEMAP_READY = "tilemap_ready"
|
||||||
const COMPONENT_MESSAGE = "component_message"
|
const COMPONENT_MESSAGE = "component_message"
|
||||||
const POSITION_UPDATE = "position_update"
|
const POSITION_UPDATE = "position_update"
|
||||||
|
const GRID_POSITION_CHANGED = "grid_position_changed"
|
||||||
|
const GRID_SNAP_REQUESTED = "grid_snap_requested"
|
||||||
|
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
# 测试事件
|
# 测试事件
|
||||||
|
|||||||
@@ -19,6 +19,11 @@ const CORE_SYSTEMS = CORE_ROOT + "systems/"
|
|||||||
const CORE_COMPONENTS = CORE_ROOT + "components/"
|
const CORE_COMPONENTS = CORE_ROOT + "components/"
|
||||||
const CORE_UTILS = CORE_ROOT + "utils/"
|
const CORE_UTILS = CORE_ROOT + "utils/"
|
||||||
|
|
||||||
|
# 系统文件路径
|
||||||
|
const GRID_SYSTEM = CORE_SYSTEMS + "GridSystem.gd"
|
||||||
|
const EVENT_SYSTEM = CORE_SYSTEMS + "EventSystem.gd"
|
||||||
|
const TILE_SYSTEM = CORE_SYSTEMS + "TileSystem.gd"
|
||||||
|
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
# 场景路径
|
# 场景路径
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
@@ -46,6 +51,10 @@ const ASSETS_FONTS = ASSETS_ROOT + "fonts/"
|
|||||||
const ASSETS_MATERIALS = ASSETS_ROOT + "materials/"
|
const ASSETS_MATERIALS = ASSETS_ROOT + "materials/"
|
||||||
const ASSETS_SHADERS = ASSETS_ROOT + "shaders/"
|
const ASSETS_SHADERS = ASSETS_ROOT + "shaders/"
|
||||||
|
|
||||||
|
# 地形资源路径
|
||||||
|
const ASSETS_TERRAIN = ASSETS_SPRITES + "terrain/"
|
||||||
|
const ASSETS_GRASS = ASSETS_TERRAIN + "grass/"
|
||||||
|
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
# 数据路径
|
# 数据路径
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
|
|||||||
@@ -698,4 +698,4 @@ func get_request_info(request_id: String) -> Dictionary:
|
|||||||
func _notification(what):
|
func _notification(what):
|
||||||
if what == NOTIFICATION_WM_CLOSE_REQUEST:
|
if what == NOTIFICATION_WM_CLOSE_REQUEST:
|
||||||
# 应用关闭时取消所有请求
|
# 应用关闭时取消所有请求
|
||||||
cancel_all_requests()
|
cancel_all_requests()
|
||||||
|
|||||||
@@ -587,4 +587,4 @@ func handle_response(operation_type: String, success: bool, data: Dictionary, er
|
|||||||
result.success = false
|
result.success = false
|
||||||
result.message = _get_error_message(data.get("error_code", ""), data.get("message", "操作失败"), error_info)
|
result.message = _get_error_message(data.get("error_code", ""), data.get("message", "操作失败"), error_info)
|
||||||
result.toast_type = "error"
|
result.toast_type = "error"
|
||||||
return result
|
return result
|
||||||
|
|||||||
143
_Core/systems/GridSystem.gd
Normal file
@@ -0,0 +1,143 @@
|
|||||||
|
# ============================================================================
|
||||||
|
# 网格系统 - GridSystem.gd
|
||||||
|
#
|
||||||
|
# 提供32x32像素的最小网格单元控制,用于规范地图大小和位置计算
|
||||||
|
#
|
||||||
|
# 使用方式:
|
||||||
|
# var grid_pos = GridSystem.world_to_grid(world_position)
|
||||||
|
# var world_pos = GridSystem.grid_to_world(grid_position)
|
||||||
|
# var snapped_pos = GridSystem.snap_to_grid(position)
|
||||||
|
# ============================================================================
|
||||||
|
|
||||||
|
class_name GridSystem
|
||||||
|
extends RefCounted
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# 常量定义
|
||||||
|
# ============================================================================
|
||||||
|
const GRID_SIZE: int = 32 # 网格单元大小 32x32 像素
|
||||||
|
const HALF_GRID_SIZE: float = GRID_SIZE * 0.5 # 网格中心偏移
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# 坐标转换方法
|
||||||
|
# ============================================================================
|
||||||
|
|
||||||
|
# 世界坐标转换为网格坐标
|
||||||
|
static func world_to_grid(world_pos: Vector2) -> Vector2i:
|
||||||
|
return Vector2i(
|
||||||
|
int(world_pos.x / GRID_SIZE),
|
||||||
|
int(world_pos.y / GRID_SIZE)
|
||||||
|
)
|
||||||
|
|
||||||
|
# 网格坐标转换为世界坐标(返回网格左上角)
|
||||||
|
static func grid_to_world(grid_pos: Vector2i) -> Vector2:
|
||||||
|
return Vector2(
|
||||||
|
grid_pos.x * GRID_SIZE,
|
||||||
|
grid_pos.y * GRID_SIZE
|
||||||
|
)
|
||||||
|
|
||||||
|
# 网格坐标转换为世界坐标(返回网格中心)
|
||||||
|
static func grid_to_world_center(grid_pos: Vector2i) -> Vector2:
|
||||||
|
return Vector2(
|
||||||
|
grid_pos.x * GRID_SIZE + HALF_GRID_SIZE,
|
||||||
|
grid_pos.y * GRID_SIZE + HALF_GRID_SIZE
|
||||||
|
)
|
||||||
|
|
||||||
|
# 将位置吸附到最近的网格点(左上角)
|
||||||
|
static func snap_to_grid(position: Vector2) -> Vector2:
|
||||||
|
return Vector2(
|
||||||
|
floor(position.x / GRID_SIZE) * GRID_SIZE,
|
||||||
|
floor(position.y / GRID_SIZE) * GRID_SIZE
|
||||||
|
)
|
||||||
|
|
||||||
|
# 将位置吸附到最近的网格中心
|
||||||
|
static func snap_to_grid_center(position: Vector2) -> Vector2:
|
||||||
|
var grid_pos = world_to_grid(position)
|
||||||
|
return grid_to_world_center(grid_pos)
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# 距离和区域计算
|
||||||
|
# ============================================================================
|
||||||
|
|
||||||
|
# 计算两个网格坐标之间的曼哈顿距离
|
||||||
|
static func grid_distance_manhattan(grid_pos1: Vector2i, grid_pos2: Vector2i) -> int:
|
||||||
|
return abs(grid_pos1.x - grid_pos2.x) + abs(grid_pos1.y - grid_pos2.y)
|
||||||
|
|
||||||
|
# 计算两个网格坐标之间的欧几里得距离
|
||||||
|
static func grid_distance_euclidean(grid_pos1: Vector2i, grid_pos2: Vector2i) -> float:
|
||||||
|
var diff = grid_pos1 - grid_pos2
|
||||||
|
return sqrt(diff.x * diff.x + diff.y * diff.y)
|
||||||
|
|
||||||
|
# 获取指定网格坐标周围的邻居网格(4方向)
|
||||||
|
static func get_grid_neighbors_4(grid_pos: Vector2i) -> Array[Vector2i]:
|
||||||
|
return [
|
||||||
|
Vector2i(grid_pos.x, grid_pos.y - 1), # 上
|
||||||
|
Vector2i(grid_pos.x + 1, grid_pos.y), # 右
|
||||||
|
Vector2i(grid_pos.x, grid_pos.y + 1), # 下
|
||||||
|
Vector2i(grid_pos.x - 1, grid_pos.y) # 左
|
||||||
|
]
|
||||||
|
|
||||||
|
# 获取指定网格坐标周围的邻居网格(8方向)
|
||||||
|
static func get_grid_neighbors_8(grid_pos: Vector2i) -> Array[Vector2i]:
|
||||||
|
var neighbors: Array[Vector2i] = []
|
||||||
|
for x in range(-1, 2):
|
||||||
|
for y in range(-1, 2):
|
||||||
|
if x == 0 and y == 0:
|
||||||
|
continue
|
||||||
|
neighbors.append(Vector2i(grid_pos.x + x, grid_pos.y + y))
|
||||||
|
return neighbors
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# 区域和边界检查
|
||||||
|
# ============================================================================
|
||||||
|
|
||||||
|
# 检查网格坐标是否在指定矩形区域内
|
||||||
|
static func is_grid_in_bounds(grid_pos: Vector2i, min_grid: Vector2i, max_grid: Vector2i) -> bool:
|
||||||
|
return (grid_pos.x >= min_grid.x and grid_pos.x <= max_grid.x and
|
||||||
|
grid_pos.y >= min_grid.y and grid_pos.y <= max_grid.y)
|
||||||
|
|
||||||
|
# 获取矩形区域内的所有网格坐标
|
||||||
|
static func get_grids_in_rect(min_grid: Vector2i, max_grid: Vector2i) -> Array[Vector2i]:
|
||||||
|
var grids: Array[Vector2i] = []
|
||||||
|
for x in range(min_grid.x, max_grid.x + 1):
|
||||||
|
for y in range(min_grid.y, max_grid.y + 1):
|
||||||
|
grids.append(Vector2i(x, y))
|
||||||
|
return grids
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# 地图尺寸规范化
|
||||||
|
# ============================================================================
|
||||||
|
|
||||||
|
# 将像素尺寸规范化为网格尺寸的倍数
|
||||||
|
static func normalize_size_to_grid(pixel_size: Vector2i) -> Vector2i:
|
||||||
|
return Vector2i(
|
||||||
|
int(ceil(float(pixel_size.x) / GRID_SIZE)) * GRID_SIZE,
|
||||||
|
int(ceil(float(pixel_size.y) / GRID_SIZE)) * GRID_SIZE
|
||||||
|
)
|
||||||
|
|
||||||
|
# 计算指定像素尺寸需要多少个网格单元
|
||||||
|
static func get_grid_count(pixel_size: Vector2i) -> Vector2i:
|
||||||
|
return Vector2i(
|
||||||
|
int(ceil(float(pixel_size.x) / GRID_SIZE)),
|
||||||
|
int(ceil(float(pixel_size.y) / GRID_SIZE))
|
||||||
|
)
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# 调试和可视化辅助
|
||||||
|
# ============================================================================
|
||||||
|
|
||||||
|
# 获取网格的边界矩形(用于调试绘制)
|
||||||
|
static func get_grid_rect(grid_pos: Vector2i) -> Rect2:
|
||||||
|
var world_pos = grid_to_world(grid_pos)
|
||||||
|
return Rect2(world_pos, Vector2(GRID_SIZE, GRID_SIZE))
|
||||||
|
|
||||||
|
# 打印网格信息(调试用)
|
||||||
|
static func print_grid_info(world_pos: Vector2) -> void:
|
||||||
|
var grid_pos = world_to_grid(world_pos)
|
||||||
|
var snapped_pos = snap_to_grid(world_pos)
|
||||||
|
var center_pos = grid_to_world_center(grid_pos)
|
||||||
|
|
||||||
|
print("世界坐标: ", world_pos)
|
||||||
|
print("网格坐标: ", grid_pos)
|
||||||
|
print("吸附位置: ", snapped_pos)
|
||||||
|
print("网格中心: ", center_pos)
|
||||||
1
_Core/systems/GridSystem.gd.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://dceqpffgti4jb
|
||||||
BIN
assets/sprites/environment/curb.png
Normal file
|
After Width: | Height: | Size: 351 KiB |
40
assets/sprites/environment/curb.png.import
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://b2gci3tcylfiw"
|
||||||
|
path="res://.godot/imported/curb.png-aea973bea0e48d7135256b05941024a3.ctex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://assets/sprites/environment/curb.png"
|
||||||
|
dest_files=["res://.godot/imported/curb.png-aea973bea0e48d7135256b05941024a3.ctex"]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
compress/mode=0
|
||||||
|
compress/high_quality=false
|
||||||
|
compress/lossy_quality=0.7
|
||||||
|
compress/uastc_level=0
|
||||||
|
compress/rdo_quality_loss=0.0
|
||||||
|
compress/hdr_compression=1
|
||||||
|
compress/normal_map=0
|
||||||
|
compress/channel_pack=0
|
||||||
|
mipmaps/generate=false
|
||||||
|
mipmaps/limit=-1
|
||||||
|
roughness/mode=0
|
||||||
|
roughness/src_normal=""
|
||||||
|
process/channel_remap/red=0
|
||||||
|
process/channel_remap/green=1
|
||||||
|
process/channel_remap/blue=2
|
||||||
|
process/channel_remap/alpha=3
|
||||||
|
process/fix_alpha_border=true
|
||||||
|
process/premult_alpha=false
|
||||||
|
process/normal_map_invert_y=false
|
||||||
|
process/hdr_as_srgb=false
|
||||||
|
process/hdr_clamp_exposure=false
|
||||||
|
process/size_limit=0
|
||||||
|
detect_3d/compress_to=1
|
||||||
BIN
assets/sprites/environment/download_1767426187137.png
Normal file
|
After Width: | Height: | Size: 5.4 MiB |
40
assets/sprites/environment/download_1767426187137.png.import
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://djmpsp6t8vbra"
|
||||||
|
path="res://.godot/imported/download_1767426187137.png-a7252aa9f644c4f3ab14cefb1a59847c.ctex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://assets/sprites/environment/download_1767426187137.png"
|
||||||
|
dest_files=["res://.godot/imported/download_1767426187137.png-a7252aa9f644c4f3ab14cefb1a59847c.ctex"]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
compress/mode=0
|
||||||
|
compress/high_quality=false
|
||||||
|
compress/lossy_quality=0.7
|
||||||
|
compress/uastc_level=0
|
||||||
|
compress/rdo_quality_loss=0.0
|
||||||
|
compress/hdr_compression=1
|
||||||
|
compress/normal_map=0
|
||||||
|
compress/channel_pack=0
|
||||||
|
mipmaps/generate=false
|
||||||
|
mipmaps/limit=-1
|
||||||
|
roughness/mode=0
|
||||||
|
roughness/src_normal=""
|
||||||
|
process/channel_remap/red=0
|
||||||
|
process/channel_remap/green=1
|
||||||
|
process/channel_remap/blue=2
|
||||||
|
process/channel_remap/alpha=3
|
||||||
|
process/fix_alpha_border=true
|
||||||
|
process/premult_alpha=false
|
||||||
|
process/normal_map_invert_y=false
|
||||||
|
process/hdr_as_srgb=false
|
||||||
|
process/hdr_clamp_exposure=false
|
||||||
|
process/size_limit=0
|
||||||
|
detect_3d/compress_to=1
|
||||||
BIN
assets/sprites/environment/floor_tile.png
Normal file
|
After Width: | Height: | Size: 137 KiB |
40
assets/sprites/environment/floor_tile.png.import
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://c3yr7cietnip3"
|
||||||
|
path="res://.godot/imported/floor_tile.png-922ec9c726f71491a3ebe25e6696192d.ctex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://assets/sprites/environment/floor_tile.png"
|
||||||
|
dest_files=["res://.godot/imported/floor_tile.png-922ec9c726f71491a3ebe25e6696192d.ctex"]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
compress/mode=0
|
||||||
|
compress/high_quality=false
|
||||||
|
compress/lossy_quality=0.7
|
||||||
|
compress/uastc_level=0
|
||||||
|
compress/rdo_quality_loss=0.0
|
||||||
|
compress/hdr_compression=1
|
||||||
|
compress/normal_map=0
|
||||||
|
compress/channel_pack=0
|
||||||
|
mipmaps/generate=false
|
||||||
|
mipmaps/limit=-1
|
||||||
|
roughness/mode=0
|
||||||
|
roughness/src_normal=""
|
||||||
|
process/channel_remap/red=0
|
||||||
|
process/channel_remap/green=1
|
||||||
|
process/channel_remap/blue=2
|
||||||
|
process/channel_remap/alpha=3
|
||||||
|
process/fix_alpha_border=true
|
||||||
|
process/premult_alpha=false
|
||||||
|
process/normal_map_invert_y=false
|
||||||
|
process/hdr_as_srgb=false
|
||||||
|
process/hdr_clamp_exposure=false
|
||||||
|
process/size_limit=0
|
||||||
|
detect_3d/compress_to=1
|
||||||
BIN
assets/sprites/environment/square.png
Normal file
|
After Width: | Height: | Size: 475 KiB |
40
assets/sprites/environment/square.png.import
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://7o0xyqmqbvov"
|
||||||
|
path="res://.godot/imported/square.png-f3b8edd32d9382a7b98d24fd60e1b771.ctex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://assets/sprites/environment/square.png"
|
||||||
|
dest_files=["res://.godot/imported/square.png-f3b8edd32d9382a7b98d24fd60e1b771.ctex"]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
compress/mode=0
|
||||||
|
compress/high_quality=false
|
||||||
|
compress/lossy_quality=0.7
|
||||||
|
compress/uastc_level=0
|
||||||
|
compress/rdo_quality_loss=0.0
|
||||||
|
compress/hdr_compression=1
|
||||||
|
compress/normal_map=0
|
||||||
|
compress/channel_pack=0
|
||||||
|
mipmaps/generate=false
|
||||||
|
mipmaps/limit=-1
|
||||||
|
roughness/mode=0
|
||||||
|
roughness/src_normal=""
|
||||||
|
process/channel_remap/red=0
|
||||||
|
process/channel_remap/green=1
|
||||||
|
process/channel_remap/blue=2
|
||||||
|
process/channel_remap/alpha=3
|
||||||
|
process/fix_alpha_border=true
|
||||||
|
process/premult_alpha=false
|
||||||
|
process/normal_map_invert_y=false
|
||||||
|
process/hdr_as_srgb=false
|
||||||
|
process/hdr_clamp_exposure=false
|
||||||
|
process/size_limit=0
|
||||||
|
detect_3d/compress_to=1
|
||||||
BIN
assets/sprites/environment/square1.png
Normal file
|
After Width: | Height: | Size: 523 KiB |
40
assets/sprites/environment/square1.png.import
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://dt33hewme0p1k"
|
||||||
|
path="res://.godot/imported/square1.png-5d845f041b32e4a2880ddc03c7e210e2.ctex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://assets/sprites/environment/square1.png"
|
||||||
|
dest_files=["res://.godot/imported/square1.png-5d845f041b32e4a2880ddc03c7e210e2.ctex"]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
compress/mode=0
|
||||||
|
compress/high_quality=false
|
||||||
|
compress/lossy_quality=0.7
|
||||||
|
compress/uastc_level=0
|
||||||
|
compress/rdo_quality_loss=0.0
|
||||||
|
compress/hdr_compression=1
|
||||||
|
compress/normal_map=0
|
||||||
|
compress/channel_pack=0
|
||||||
|
mipmaps/generate=false
|
||||||
|
mipmaps/limit=-1
|
||||||
|
roughness/mode=0
|
||||||
|
roughness/src_normal=""
|
||||||
|
process/channel_remap/red=0
|
||||||
|
process/channel_remap/green=1
|
||||||
|
process/channel_remap/blue=2
|
||||||
|
process/channel_remap/alpha=3
|
||||||
|
process/fix_alpha_border=true
|
||||||
|
process/premult_alpha=false
|
||||||
|
process/normal_map_invert_y=false
|
||||||
|
process/hdr_as_srgb=false
|
||||||
|
process/hdr_clamp_exposure=false
|
||||||
|
process/size_limit=0
|
||||||
|
detect_3d/compress_to=1
|
||||||
BIN
assets/sprites/environment/广场瓦片集.png
Normal file
|
After Width: | Height: | Size: 3.8 KiB |
40
assets/sprites/environment/广场瓦片集.png.import
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://ignbtjvnp5k7"
|
||||||
|
path="res://.godot/imported/广场瓦片集.png-b224b40553b9f690e690f67a89e2b520.ctex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://assets/sprites/environment/广场瓦片集.png"
|
||||||
|
dest_files=["res://.godot/imported/广场瓦片集.png-b224b40553b9f690e690f67a89e2b520.ctex"]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
compress/mode=0
|
||||||
|
compress/high_quality=false
|
||||||
|
compress/lossy_quality=0.7
|
||||||
|
compress/uastc_level=0
|
||||||
|
compress/rdo_quality_loss=0.0
|
||||||
|
compress/hdr_compression=1
|
||||||
|
compress/normal_map=0
|
||||||
|
compress/channel_pack=0
|
||||||
|
mipmaps/generate=false
|
||||||
|
mipmaps/limit=-1
|
||||||
|
roughness/mode=0
|
||||||
|
roughness/src_normal=""
|
||||||
|
process/channel_remap/red=0
|
||||||
|
process/channel_remap/green=1
|
||||||
|
process/channel_remap/blue=2
|
||||||
|
process/channel_remap/alpha=3
|
||||||
|
process/fix_alpha_border=true
|
||||||
|
process/premult_alpha=false
|
||||||
|
process/normal_map_invert_y=false
|
||||||
|
process/hdr_as_srgb=false
|
||||||
|
process/hdr_clamp_exposure=false
|
||||||
|
process/size_limit=0
|
||||||
|
detect_3d/compress_to=1
|
||||||
BIN
assets/sprites/environment/草地.png
Normal file
|
After Width: | Height: | Size: 2.6 KiB |
40
assets/sprites/environment/草地.png.import
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://dvsb51jintro"
|
||||||
|
path="res://.godot/imported/草地.png-2fa7f2346d7dc837788dd21e5693cec7.ctex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://assets/sprites/environment/草地.png"
|
||||||
|
dest_files=["res://.godot/imported/草地.png-2fa7f2346d7dc837788dd21e5693cec7.ctex"]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
compress/mode=0
|
||||||
|
compress/high_quality=false
|
||||||
|
compress/lossy_quality=0.7
|
||||||
|
compress/uastc_level=0
|
||||||
|
compress/rdo_quality_loss=0.0
|
||||||
|
compress/hdr_compression=1
|
||||||
|
compress/normal_map=0
|
||||||
|
compress/channel_pack=0
|
||||||
|
mipmaps/generate=false
|
||||||
|
mipmaps/limit=-1
|
||||||
|
roughness/mode=0
|
||||||
|
roughness/src_normal=""
|
||||||
|
process/channel_remap/red=0
|
||||||
|
process/channel_remap/green=1
|
||||||
|
process/channel_remap/blue=2
|
||||||
|
process/channel_remap/alpha=3
|
||||||
|
process/fix_alpha_border=true
|
||||||
|
process/premult_alpha=false
|
||||||
|
process/normal_map_invert_y=false
|
||||||
|
process/hdr_as_srgb=false
|
||||||
|
process/hdr_clamp_exposure=false
|
||||||
|
process/size_limit=0
|
||||||
|
detect_3d/compress_to=1
|
||||||
@@ -1 +0,0 @@
|
|||||||
# 保持目录结构 - 角色精灵资源目录
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
# 保持目录结构 - 特效精灵资源目录
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
# 保持目录结构 - 环境精灵资源目录
|
|
||||||
59
docs/06-功能模块/网格瓦片系统.md
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
# 网格瓦片系统
|
||||||
|
|
||||||
|
## 概述
|
||||||
|
|
||||||
|
网格瓦片系统提供32x32像素的标准化网格管理,用于规范地图元素的位置和大小。
|
||||||
|
|
||||||
|
## 核心组件
|
||||||
|
|
||||||
|
### GridSystem (核心系统)
|
||||||
|
- **位置**: `_Core/systems/GridSystem.gd`
|
||||||
|
- **功能**: 提供网格坐标转换、位置计算等基础功能
|
||||||
|
- **类型**: 静态工具类
|
||||||
|
|
||||||
|
### GrassTile (瓦片组件)
|
||||||
|
- **脚本**: `scenes/prefabs/GrassTile.gd`
|
||||||
|
- **场景**: `scenes/prefabs/grass_tile_prefab.tscn`
|
||||||
|
- **功能**: 可视化的草地瓦片,自动对齐32x32网格
|
||||||
|
|
||||||
|
## 使用方法
|
||||||
|
|
||||||
|
### 在编辑器中使用
|
||||||
|
1. 拖拽 `scenes/prefabs/grass_tile_prefab.tscn` 到场景中
|
||||||
|
2. 在Inspector中设置Texture和Grid Position
|
||||||
|
3. 瓦片会自动对齐到网格
|
||||||
|
|
||||||
|
### 通过代码使用
|
||||||
|
```gdscript
|
||||||
|
# 预加载场景
|
||||||
|
const GrassTileScene = preload("res://scenes/prefabs/grass_tile_prefab.tscn")
|
||||||
|
|
||||||
|
# 创建瓦片
|
||||||
|
var grass = GrassTileScene.instantiate()
|
||||||
|
add_child(grass)
|
||||||
|
grass.set_grid_position(Vector2i(0, 0))
|
||||||
|
```
|
||||||
|
|
||||||
|
## 网格规范
|
||||||
|
|
||||||
|
### 基础规格
|
||||||
|
- **网格大小**: 32x32像素
|
||||||
|
- **坐标系**: 左上角为原点(0,0)
|
||||||
|
- **对齐方式**: 瓦片中心对齐到网格中心
|
||||||
|
|
||||||
|
### 纹理要求
|
||||||
|
- 尺寸必须是32的倍数
|
||||||
|
- 推荐格式: PNG
|
||||||
|
- 推荐尺寸: 32x32, 64x64, 96x96
|
||||||
|
|
||||||
|
## API参考
|
||||||
|
|
||||||
|
### GridSystem 方法
|
||||||
|
- `world_to_grid(world_pos: Vector2) -> Vector2i`
|
||||||
|
- `grid_to_world_center(grid_pos: Vector2i) -> Vector2`
|
||||||
|
- `snap_to_grid(position: Vector2) -> Vector2`
|
||||||
|
|
||||||
|
### GrassTile 属性和方法
|
||||||
|
- `grid_position: Vector2i` - 网格坐标
|
||||||
|
- `set_grid_position(pos: Vector2i)` - 设置网格位置
|
||||||
|
- `snap_to_grid()` - 对齐到网格
|
||||||
16
scenes/Maps/square.tscn
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
[gd_scene load_steps=4 format=3 uid="uid://5cc0c6cpnhe8"]
|
||||||
|
|
||||||
|
[ext_resource type="Texture2D" uid="uid://7o0xyqmqbvov" path="res://assets/sprites/environment/square.png" id="1_a2ug0"]
|
||||||
|
|
||||||
|
[sub_resource type="TileSetAtlasSource" id="TileSetAtlasSource_1t0sv"]
|
||||||
|
texture = ExtResource("1_a2ug0")
|
||||||
|
15:1/size_in_atlas = Vector2i(2, 2)
|
||||||
|
15:1/0 = 0
|
||||||
|
|
||||||
|
[sub_resource type="TileSet" id="TileSet_g3awv"]
|
||||||
|
sources/0 = SubResource("TileSetAtlasSource_1t0sv")
|
||||||
|
|
||||||
|
[node name="square" type="Node2D"]
|
||||||
|
|
||||||
|
[node name="TileMapLayer" type="TileMapLayer" parent="."]
|
||||||
|
tile_set = SubResource("TileSet_g3awv")
|
||||||
122
scenes/prefabs/GrassTile.gd
Normal file
@@ -0,0 +1,122 @@
|
|||||||
|
# ============================================================================
|
||||||
|
# 简单草地瓦片 - GrassTile.gd
|
||||||
|
#
|
||||||
|
# 一个简单的32x32草地瓦片,自动对齐网格
|
||||||
|
# 使用方法:
|
||||||
|
# 1. 在场景中实例化 grass_tile_prefab.tscn
|
||||||
|
# 2. 设置 texture 属性
|
||||||
|
# 3. 调用 set_grid_position() 设置网格位置
|
||||||
|
# ============================================================================
|
||||||
|
|
||||||
|
class_name GrassTile
|
||||||
|
extends Sprite2D
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# 导出属性
|
||||||
|
# ============================================================================
|
||||||
|
@export var grid_position: Vector2i = Vector2i.ZERO : set = set_grid_position
|
||||||
|
@export var auto_snap: bool = true # 是否自动对齐网格
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# 信号
|
||||||
|
# ============================================================================
|
||||||
|
signal position_changed(new_grid_pos: Vector2i)
|
||||||
|
|
||||||
|
func _ready():
|
||||||
|
# 如果没有纹理,创建一个默认的占位符
|
||||||
|
if not texture:
|
||||||
|
_create_placeholder_texture()
|
||||||
|
|
||||||
|
# 验证纹理尺寸
|
||||||
|
_validate_texture()
|
||||||
|
|
||||||
|
# 自动对齐到网格
|
||||||
|
if auto_snap:
|
||||||
|
snap_to_grid()
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# 公共方法
|
||||||
|
# ============================================================================
|
||||||
|
|
||||||
|
# 设置网格位置并自动对齐
|
||||||
|
func set_grid_position(new_pos: Vector2i):
|
||||||
|
if grid_position != new_pos:
|
||||||
|
grid_position = new_pos
|
||||||
|
if auto_snap:
|
||||||
|
snap_to_grid()
|
||||||
|
position_changed.emit(grid_position)
|
||||||
|
|
||||||
|
# 对齐到网格中心
|
||||||
|
func snap_to_grid():
|
||||||
|
position = Vector2(
|
||||||
|
grid_position.x * 32.0 + 16.0,
|
||||||
|
grid_position.y * 32.0 + 16.0
|
||||||
|
)
|
||||||
|
|
||||||
|
# 从世界坐标设置位置(会自动转换为网格坐标)
|
||||||
|
func set_world_position(world_pos: Vector2):
|
||||||
|
var new_grid_pos = Vector2i(
|
||||||
|
int(world_pos.x / 32.0),
|
||||||
|
int(world_pos.y / 32.0)
|
||||||
|
)
|
||||||
|
set_grid_position(new_grid_pos)
|
||||||
|
|
||||||
|
# 获取世界坐标
|
||||||
|
func get_world_position() -> Vector2:
|
||||||
|
return position
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# 私有方法
|
||||||
|
# ============================================================================
|
||||||
|
|
||||||
|
# 创建占位符纹理
|
||||||
|
func _create_placeholder_texture():
|
||||||
|
var image = Image.create(32, 32, false, Image.FORMAT_RGBA8)
|
||||||
|
|
||||||
|
# 创建简单的草地图案
|
||||||
|
var grass_color = Color(0.3, 0.8, 0.3, 1.0) # 亮绿色
|
||||||
|
var dark_color = Color(0.2, 0.6, 0.2, 1.0) # 深绿色
|
||||||
|
|
||||||
|
# 填充基础颜色
|
||||||
|
image.fill(grass_color)
|
||||||
|
|
||||||
|
# 添加简单的格子图案
|
||||||
|
for x in range(32):
|
||||||
|
for y in range(32):
|
||||||
|
if (x + y) % 8 < 4:
|
||||||
|
image.set_pixel(x, y, dark_color)
|
||||||
|
|
||||||
|
# 创建纹理
|
||||||
|
var placeholder_texture = ImageTexture.new()
|
||||||
|
placeholder_texture.set_image(image)
|
||||||
|
texture = placeholder_texture
|
||||||
|
|
||||||
|
# 验证纹理尺寸
|
||||||
|
func _validate_texture():
|
||||||
|
if texture:
|
||||||
|
var size = Vector2i(texture.get_width(), texture.get_height())
|
||||||
|
if size.x % 32 != 0 or size.y % 32 != 0:
|
||||||
|
push_warning("GrassTile: 纹理尺寸不是32的倍数: " + str(size))
|
||||||
|
return false
|
||||||
|
return true
|
||||||
|
return false
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# 调试方法
|
||||||
|
# ============================================================================
|
||||||
|
|
||||||
|
# 获取瓦片信息
|
||||||
|
func get_tile_info() -> Dictionary:
|
||||||
|
return {
|
||||||
|
"grid_position": grid_position,
|
||||||
|
"world_position": position,
|
||||||
|
"texture_size": texture.get_size() if texture else Vector2.ZERO,
|
||||||
|
"auto_snap": auto_snap
|
||||||
|
}
|
||||||
|
|
||||||
|
# 打印瓦片信息
|
||||||
|
func print_info():
|
||||||
|
var info = get_tile_info()
|
||||||
|
print("=== 草地瓦片信息 ===")
|
||||||
|
for key in info:
|
||||||
|
print(key, ": ", info[key])
|
||||||
10
scenes/prefabs/grass_tile_prefab.tscn
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
[gd_scene load_steps=3 format=3 uid="uid://bvxqm8n7qwqxe"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" path="res://scenes/prefabs/GrassTile.gd" id="1_0x8qm"]
|
||||||
|
|
||||||
|
[sub_resource type="PlaceholderTexture2D" id="PlaceholderTexture2D_1"]
|
||||||
|
size = Vector2(32, 32)
|
||||||
|
|
||||||
|
[node name="GrassTile" type="Sprite2D"]
|
||||||
|
texture = SubResource("PlaceholderTexture2D_1")
|
||||||
|
script = ExtResource("1_0x8qm")
|
||||||
191
tools/README.md
@@ -1,191 +0,0 @@
|
|||||||
# 🛠️ 构建和部署工具
|
|
||||||
|
|
||||||
本目录包含项目的构建和部署脚本。
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 📦 Web 构建工具
|
|
||||||
|
|
||||||
### build_web.sh (Linux/macOS)
|
|
||||||
### build_web.bat (Windows)
|
|
||||||
|
|
||||||
**功能**: 将 Godot 项目导出为 Web 版本
|
|
||||||
|
|
||||||
#### 使用方法
|
|
||||||
|
|
||||||
**macOS/Linux:**
|
|
||||||
```bash
|
|
||||||
chmod +x tools/build_web.sh
|
|
||||||
./tools/build_web.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
**Windows:**
|
|
||||||
```cmd
|
|
||||||
tools\build_web.bat
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 输出目录
|
|
||||||
- `build/web/` - 导出的 Web 游戏文件
|
|
||||||
|
|
||||||
#### 导出内容包括:
|
|
||||||
- `index.html` - Web 入口文件
|
|
||||||
- `index.js` - 游戏主逻辑
|
|
||||||
- `index.wasm` - WebAssembly 文件
|
|
||||||
- `index.pck` - 游戏资源包
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🌐 Web 测试服务器
|
|
||||||
|
|
||||||
### serve_web.sh (Linux/macOS)
|
|
||||||
### serve_web.bat (Windows)
|
|
||||||
|
|
||||||
**功能**: 启动本地 HTTP 服务器预览 Web 游戏
|
|
||||||
|
|
||||||
#### 使用方法
|
|
||||||
|
|
||||||
**macOS/Linux:**
|
|
||||||
```bash
|
|
||||||
chmod +x tools/serve_web.sh
|
|
||||||
./tools/serve_web.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
**Windows:**
|
|
||||||
```cmd
|
|
||||||
tools\serve_web.bat
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 访问地址
|
|
||||||
- 默认: `http://localhost:8000`
|
|
||||||
- 浏览器会自动打开
|
|
||||||
|
|
||||||
#### 注意事项
|
|
||||||
⚠️ **必须使用 HTTP 服务器**
|
|
||||||
- 不能直接用 `file://` 打开 `index.html`
|
|
||||||
- Godot Web 版本需要 HTTP 环境
|
|
||||||
- 本服务器已配置正确的 CORS 头
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🔧 配置说明
|
|
||||||
|
|
||||||
### 修改 Godot 路径
|
|
||||||
|
|
||||||
编辑脚本中的 `GODOT_PATH` 变量:
|
|
||||||
|
|
||||||
**macOS:**
|
|
||||||
```bash
|
|
||||||
GODOT_PATH="/usr/local/bin/godot" # Homebrew
|
|
||||||
# 或
|
|
||||||
GODOT_PATH="$HOME/Applications/Godot.app/Contents/MacOS/Godot" # 应用程序
|
|
||||||
```
|
|
||||||
|
|
||||||
**Windows:**
|
|
||||||
```batch
|
|
||||||
set GODOT_PATH=C:\Program Files\Godot\godot.exe
|
|
||||||
```
|
|
||||||
|
|
||||||
**Linux:**
|
|
||||||
```bash
|
|
||||||
GODOT_PATH="/usr/bin/godot" # 包管理器
|
|
||||||
# 或
|
|
||||||
GODOT_PATH="$HOME/bin/godot" # 手动安装
|
|
||||||
```
|
|
||||||
|
|
||||||
### 修改端口
|
|
||||||
|
|
||||||
编辑 `serve_web.sh` 或 `serve_web.bat` 中的端口配置:
|
|
||||||
```bash
|
|
||||||
PORT=8080 # 改为其他端口
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 📋 典型工作流程
|
|
||||||
|
|
||||||
### 1. 开发阶段
|
|
||||||
在 Godot 编辑器中开发和测试游戏
|
|
||||||
|
|
||||||
### 2. 导出 Web 版本
|
|
||||||
```bash
|
|
||||||
./tools/build_web.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
### 3. 本地测试
|
|
||||||
```bash
|
|
||||||
./tools/serve_web.sh
|
|
||||||
# 浏览器访问 http://localhost:8000
|
|
||||||
```
|
|
||||||
|
|
||||||
### 4. 部署到服务器
|
|
||||||
将 `build/web/` 目录的内容上传到你的 Web 服务器
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🌍 部署平台示例
|
|
||||||
|
|
||||||
### GitHub Pages
|
|
||||||
```bash
|
|
||||||
./tools/build_web.sh
|
|
||||||
# 将 build/web/ 推送到 gh-pages 分支
|
|
||||||
```
|
|
||||||
|
|
||||||
### Netlify
|
|
||||||
```bash
|
|
||||||
# 直接拖拽 build/web/ 目录到 Netlify
|
|
||||||
```
|
|
||||||
|
|
||||||
### Vercel
|
|
||||||
```bash
|
|
||||||
./tools/build_web.sh
|
|
||||||
vercel --prod build/web/
|
|
||||||
```
|
|
||||||
|
|
||||||
### 自己的服务器
|
|
||||||
```bash
|
|
||||||
scp -r build/web/* user@server:/var/www/html/
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ⚠️ 常见问题
|
|
||||||
|
|
||||||
### 问题 1: 找不到 Godot
|
|
||||||
**解决方案**: 修改脚本中的 `GODOT_PATH` 变量
|
|
||||||
|
|
||||||
### 问题 2: 权限不足 (macOS/Linux)
|
|
||||||
**解决方案**:
|
|
||||||
```bash
|
|
||||||
chmod +x tools/build_web.sh tools/serve_web.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
### 问题 3: 浏览器无法加载游戏
|
|
||||||
**原因**: 必须使用 HTTP 服务器,不能用 `file://`
|
|
||||||
**解决方案**: 使用 `serve_web.sh` 启动本地服务器
|
|
||||||
|
|
||||||
### 问题 4: 游戏黑屏
|
|
||||||
**检查**:
|
|
||||||
- 浏览器控制台是否有错误
|
|
||||||
- WebAssembly 是否启用
|
|
||||||
- 是否在 HTTPS 或 localhost 环境下运行
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 📚 相关文档
|
|
||||||
|
|
||||||
- [Godot Web 导出文档](https://docs.godotengine.org/en/stable/tutorials/export/exporting_for_web.html)
|
|
||||||
- [Web 服务器配置](https://docs.godotengine.org/en/stable/tutorials/export/binary_files_for_web_games.html)
|
|
||||||
- [项目 Web 部署指南](../docs/web_deployment_guide.md)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🎯 下一步
|
|
||||||
|
|
||||||
1. 确保安装了 Godot 4.5+
|
|
||||||
2. 运行 `./tools/build_web.sh` 测试导出
|
|
||||||
3. 运行 `./tools/serve_web.sh` 本地预览
|
|
||||||
4. 根据需要修改配置参数
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
**祝你发布顺利!** 🚀
|
|
||||||