diff --git a/addons/enhanced_gridmap/meshlibrary/default.tres b/addons/enhanced_gridmap/meshlibrary/default.tres index 2d6bba4..1c34963 100644 --- a/addons/enhanced_gridmap/meshlibrary/default.tres +++ b/addons/enhanced_gridmap/meshlibrary/default.tres @@ -47,3 +47,8 @@ item/6/mesh_transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0) item/6/shapes = [] item/6/navigation_mesh_transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0) item/6/navigation_layers = 1 +item/7/name = "tile_1" +item/7/mesh_transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0) +item/7/shapes = [] +item/7/navigation_mesh_transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0) +item/7/navigation_layers = 1 diff --git a/assets/models/meshes/tile.glb b/assets/models/meshes/tile.glb new file mode 100644 index 0000000..bb02b33 Binary files /dev/null and b/assets/models/meshes/tile.glb differ diff --git a/assets/models/meshes/tile.glb.import b/assets/models/meshes/tile.glb.import new file mode 100644 index 0000000..7469372 --- /dev/null +++ b/assets/models/meshes/tile.glb.import @@ -0,0 +1,36 @@ +[remap] + +importer="scene" +importer_version=1 +type="PackedScene" +uid="uid://dj8luyfylee6h" +path="res://.godot/imported/tile.glb-a2c57836b49962e6adb25601bd8d4a59.scn" + +[deps] + +source_file="res://assets/models/meshes/tile.glb" +dest_files=["res://.godot/imported/tile.glb-a2c57836b49962e6adb25601bd8d4a59.scn"] + +[params] + +nodes/root_type="" +nodes/root_name="" +nodes/apply_root_scale=true +nodes/root_scale=1.0 +nodes/import_as_skeleton_bones=false +meshes/ensure_tangents=true +meshes/generate_lods=true +meshes/create_shadow_meshes=true +meshes/light_baking=1 +meshes/lightmap_texel_size=0.2 +meshes/force_disable_compression=false +skins/use_named_skins=true +animation/import=true +animation/fps=30 +animation/trimming=false +animation/remove_immutable_tracks=true +animation/import_rest_as_RESET=false +import_script/path="" +_subresources={} +gltf/naming_version=1 +gltf/embedded_image_handling=1 diff --git a/scenes/main.gd b/scenes/main.gd index 001e768..14f286b 100644 --- a/scenes/main.gd +++ b/scenes/main.gd @@ -14,10 +14,31 @@ var max_message_input_char = 51 var max_players = 4 var bots = [] +@export var turn_based_mode: bool = true # Toggle between turn-based and realtime modes +var bot_move_timer: float = 0.0 # Timer for bot movement in realtime mode +const BOT_MOVE_INTERVAL: float = 2.0 # Time between bot movements in realtime mode + +# Bot movement state tracking +var moving_bots = {} # Dictionary to track which bots are currently moving + func _ready(): multiplayer_peer.peer_connected.connect(_on_peer_connected) multiplayer_peer.peer_disconnected.connect(_on_peer_disconnected) +func _process(delta): + if multiplayer.is_server(): + if game_started: + if turn_based_mode: + rpc("sync_turn_index", current_turn_index) + else: + # Handle realtime bot movement + bot_move_timer += delta + if bot_move_timer >= BOT_MOVE_INTERVAL: + bot_move_timer = 0.0 + for bot_id in bots: + if not moving_bots.get(bot_id, false): # Only move if bot isn't already moving + move_bot(bot_id) + func _on_host_pressed(): $NetworkInfo/NetworkSideDisplay.text = "Server" $Menu.visible = false @@ -46,7 +67,7 @@ func _on_peer_connected(new_peer_id): await get_tree().create_timer(1).timeout rpc("add_newly_connected_player_character", new_peer_id) rpc_id(new_peer_id, "add_previously_connected_player_characters", connected_peer_ids) - rpc_id(new_peer_id, "sync_game_state", players, bots, game_started) + rpc_id(new_peer_id, "sync_game_state", players, bots, game_started, turn_based_mode) add_player_character(new_peer_id) replace_bot_with_player(new_peer_id) @@ -68,6 +89,7 @@ func add_player_character(peer_id): func add_bot(bot_id): if multiplayer.is_server(): rpc("create_bot", bot_id) + moving_bots[bot_id] = false @rpc("call_local") func create_bot(bot_id): @@ -80,12 +102,14 @@ func create_bot(bot_id): if multiplayer.is_server(): bots.append(bot_id) players.append(bot_id) + moving_bots[bot_id] = false func replace_bot_with_player(player_id): if multiplayer.is_server() and bots.size() > 0: var bot_id = bots.pop_front() players.erase(bot_id) players.append(player_id) + moving_bots.erase(bot_id) # Remove bot from moving tracking rpc("remove_bot", bot_id) rpc("sync_players", players) @@ -111,33 +135,32 @@ func add_previously_connected_player_characters(peer_ids): add_player_character(peer_id) @rpc("call_local") -func sync_game_state(current_players, current_bots, is_game_started): +func sync_game_state(current_players, current_bots, is_game_started, is_turn_based): players = current_players bots = current_bots game_started = is_game_started + turn_based_mode = is_turn_based # Create bot characters for existing bots for bot_id in bots: if not has_node(str(bot_id)): create_bot(bot_id) -func _process(_delta): - if multiplayer.is_server() and game_started: - rpc("sync_turn_index", current_turn_index) - func start_game(): if multiplayer.is_server(): game_started = true connected_peer_ids.sort() - rpc("sync_game_start", connected_peer_ids, players, bots) - current_turn_index = -1 - next_turn() + rpc("sync_game_start", connected_peer_ids, players, bots, turn_based_mode) + if turn_based_mode: + current_turn_index = -1 + next_turn() @rpc("call_local") -func sync_game_start(peer_ids, current_players, current_bots): +func sync_game_start(peer_ids, current_players, current_bots, is_turn_based): connected_peer_ids = peer_ids players = current_players bots = current_bots + turn_based_mode = is_turn_based game_started = true @rpc("reliable") @@ -149,7 +172,7 @@ func sync_players(new_players): players = new_players func next_turn(): - if multiplayer.is_server(): + if multiplayer.is_server() and turn_based_mode: current_turn_index += 1 if current_turn_index >= players.size(): current_turn_index = 0 @@ -170,6 +193,9 @@ func server_end_current_turn(): @rpc("any_peer", "call_local") func set_current_turn(player_id): + if not turn_based_mode: + return + var players = get_tree().get_nodes_in_group("Players") for player in players: player.is_my_turn = (player.name == str(player_id)) @@ -190,21 +216,37 @@ func _on_message_input_text_submitted(new_text): func move_bot(bot_id): if multiplayer.is_server(): + if moving_bots.get(bot_id, false): + return # Skip if bot is already moving + var bot = get_node(str(bot_id)) - if bot: - var target_position = bot.find_random_valid_position() + if bot and (turn_based_mode or not bot.is_player_moving): + moving_bots[bot_id] = true # Mark bot as moving + var target_position = bot.find_random_valid_position_in_range() # Use the new function if target_position != bot.current_position: var path = bot.enhanced_gridmap.find_path(Vector2(bot.current_position), Vector2(target_position)) if path.size() > 1: - path.pop_front() # Remove the starting position - bot.move_bot_along_path(path) + path.pop_front() + # Trim path to respect movement range + var trimmed_path = path.slice(0, bot.movement_range) + bot.move_bot_along_path(trimmed_path, bot_id) else: print("No valid path found for bot") - end_current_turn() + moving_bots[bot_id] = false + if turn_based_mode: + end_current_turn() else: print("No new valid position found for bot") - end_current_turn() + moving_bots[bot_id] = false + if turn_based_mode: + end_current_turn() else: - print("Bot not found") - end_current_turn() + print("Bot not found or is moving") + if turn_based_mode: + end_current_turn() + +# Called when a bot finishes moving +func bot_movement_completed(bot_id): + if multiplayer.is_server(): + moving_bots[bot_id] = false diff --git a/scenes/main.tscn b/scenes/main.tscn index acc0c15..995d969 100644 --- a/scenes/main.tscn +++ b/scenes/main.tscn @@ -7,18 +7,20 @@ [node name="Main" type="Node3D"] script = ExtResource("1_xcpe3") +turn_based_mode = false [node name="EnhancedGridMap" type="GridMap" parent="."] mesh_library = ExtResource("1_110wo") cell_size = Vector3(1, 1, 1) data = { -"cells": PackedInt32Array(0, 0, 4, 0, 1, 0, 0, 2, 4, 0, 3, 0, 0, 4, 0, 0, 5, 0, 0, 6, 4, 0, 7, 0, 0, 8, 0, 0, 9, 0, 1, 0, 0, 1, 1, 0, 1, 2, 0, 1, 3, 0, 1, 4, 0, 1, 5, 4, 1, 6, 4, 1, 7, 4, 1, 8, 0, 1, 9, 4, 2, 0, 0, 2, 1, 0, 2, 2, 0, 2, 3, 0, 2, 4, 0, 2, 5, 0, 2, 6, 4, 2, 7, 4, 2, 8, 0, 2, 9, 4, 3, 0, 4, 3, 1, 0, 3, 2, 0, 3, 3, 0, 3, 4, 4, 3, 5, 0, 3, 6, 4, 3, 7, 0, 3, 8, 0, 3, 9, 0, 4, 0, 4, 4, 1, 0, 4, 2, 0, 4, 3, 0, 4, 4, 4, 4, 5, 0, 4, 6, 0, 4, 7, 0, 4, 8, 0, 4, 9, 0, 5, 0, 0, 5, 1, 4, 5, 2, 0, 5, 3, 0, 5, 4, 4, 5, 5, 0, 5, 6, 0, 5, 7, 4, 5, 8, 4, 5, 9, 0, 6, 0, 4, 6, 1, 0, 6, 2, 4, 6, 3, 4, 6, 4, 4, 6, 5, 0, 6, 6, 4, 6, 7, 4, 6, 8, 0, 6, 9, 0, 7, 0, 4, 7, 1, 0, 7, 2, 4, 7, 3, 0, 7, 4, 0, 7, 5, 0, 7, 6, 0, 7, 7, 4, 7, 8, 4, 7, 9, 4, 8, 0, 4, 8, 1, 0, 8, 2, 0, 8, 3, 0, 8, 4, 4, 8, 5, 4, 8, 6, 0, 8, 7, 0, 8, 8, 0, 8, 9, 0, 9, 0, 0, 9, 1, 4, 9, 2, 4, 9, 3, 0, 9, 4, 0, 9, 5, 0, 9, 6, 0, 9, 7, 0, 9, 8, 0, 9, 9, 0) +"cells": PackedInt32Array(0, 0, 0, 0, 1, 0, 0, 2, 0, 0, 3, 0, 0, 4, 0, 0, 5, 0, 0, 6, 0, 0, 7, 0, 0, 8, 0, 0, 9, 0, 1, 0, 0, 1, 1, 0, 1, 2, 0, 1, 3, 0, 1, 4, 0, 1, 5, 0, 1, 6, 0, 1, 7, 0, 1, 8, 0, 1, 9, 0, 2, 0, 0, 2, 1, 0, 2, 2, 0, 2, 3, 0, 2, 4, 0, 2, 5, 0, 2, 6, 0, 2, 7, 0, 2, 8, 0, 2, 9, 0, 3, 0, 0, 3, 1, 0, 3, 2, 0, 3, 3, 0, 3, 4, 0, 3, 5, 0, 3, 6, 0, 3, 7, 0, 3, 8, 0, 3, 9, 0, 4, 0, 0, 4, 1, 0, 4, 2, 0, 4, 3, 0, 4, 4, 0, 4, 5, 0, 4, 6, 0, 4, 7, 0, 4, 8, 0, 4, 9, 0, 5, 0, 0, 5, 1, 0, 5, 2, 0, 5, 3, 0, 5, 4, 0, 5, 5, 0, 5, 6, 0, 5, 7, 0, 5, 8, 0, 5, 9, 0, 6, 0, 0, 6, 1, 0, 6, 2, 0, 6, 3, 0, 6, 4, 0, 6, 5, 0, 6, 6, 0, 6, 7, 0, 6, 8, 0, 6, 9, 0, 7, 0, 0, 7, 1, 0, 7, 2, 0, 7, 3, 0, 7, 4, 0, 7, 5, 0, 7, 6, 0, 7, 7, 0, 7, 8, 0, 7, 9, 0, 8, 0, 0, 8, 1, 0, 8, 2, 0, 8, 3, 0, 8, 4, 0, 8, 5, 0, 8, 6, 0, 8, 7, 0, 8, 8, 0, 8, 9, 0, 9, 0, 0, 9, 1, 0, 9, 2, 0, 9, 3, 0, 9, 4, 0, 9, 5, 0, 9, 6, 0, 9, 7, 0, 9, 8, 0, 9, 9, 0) } script = ExtResource("2_hbe1v") non_walkable_items = Array[int]([4, 5]) +metadata/_editor_floor_ = Vector3(0, 0, 0) [node name="Camera3D" type="Camera3D" parent="."] -transform = Transform3D(-1, 0, -8.74228e-08, -6.2963e-08, 0.693754, 0.720212, 6.06499e-08, 0.720212, -0.693754, 5, 15, -10) +transform = Transform3D(-1, -7.92319e-08, 3.69465e-08, 0, 0.422618, 0.906308, -8.74228e-08, 0.906308, -0.422618, 5, 15, -2.5) environment = ExtResource("4_ky38j") fov = 35.5 diff --git a/scenes/player.gd b/scenes/player.gd index b13c66d..938ec2d 100644 --- a/scenes/player.gd +++ b/scenes/player.gd @@ -12,7 +12,8 @@ var is_player_moving: bool = false @export var center_y: bool = false @export var center_z: bool = false -@export var use_diagonal_movement: bool = false: +@export var movement_range: int = 1 # How many blocks can be moved at once +@export var use_diagonal_movement: bool = false: # Allow diagonal movement set(value): use_diagonal_movement = value if enhanced_gridmap: @@ -67,7 +68,7 @@ func find_valid_starting_position() -> Vector2i: return Vector2i(0, 0) -func find_random_valid_position() -> Vector2i: +func find_random_valid_position_in_range() -> Vector2i: var rng = RandomNumberGenerator.new() rng.randomize() @@ -75,8 +76,23 @@ func find_random_valid_position() -> Vector2i: var attempts = 0 while attempts < max_attempts: - var random_position = Vector2i(rng.randi_range(0, enhanced_gridmap.columns - 1), - rng.randi_range(0, enhanced_gridmap.rows - 1)) + var range_x = min(enhanced_gridmap.columns - 1, movement_range) + var range_y = min(enhanced_gridmap.rows - 1, movement_range) + + # Generate position within movement range of current position + var offset_x = rng.randi_range(-range_x, range_x) + var offset_y = rng.randi_range(-range_y, range_y) + + var random_position = Vector2i( + clamp(current_position.x + offset_x, 0, enhanced_gridmap.columns - 1), + clamp(current_position.y + offset_y, 0, enhanced_gridmap.rows - 1) + ) + + # Check if the position is within movement range + if not is_within_movement_range(random_position): + attempts += 1 + continue + var cell_item = enhanced_gridmap.get_cell_item(Vector3i(random_position.x, 0, random_position.y)) if cell_item not in enhanced_gridmap.non_walkable_items and random_position != current_position: @@ -91,7 +107,8 @@ func _physics_process(_delta): rpc("remote_set_position", global_position) func _unhandled_input(event): - if not is_multiplayer_authority() or not is_my_turn or is_player_moving: + var main = get_node("/root/Main") + if not is_multiplayer_authority() or (main.turn_based_mode and (not is_my_turn or is_player_moving)): return if event is InputEventMouseButton and event.pressed and event.button_index == MOUSE_BUTTON_LEFT: @@ -120,7 +137,30 @@ func raycast_to_grid(from: Vector3, to: Vector3) -> Vector2i: return Vector2i(-1, -1) +func is_within_movement_range(target_position: Vector2i) -> bool: + var distance = 0 + if use_diagonal_movement: + # For diagonal movement, use max of x and y differences + distance = max(abs(target_position.x - current_position.x), + abs(target_position.y - current_position.y)) + else: + # For orthogonal movement, use Manhattan distance + distance = abs(target_position.x - current_position.x) + \ + abs(target_position.y - current_position.y) + return distance <= movement_range + func move_player_to_clicked_position(grid_position: Vector2i): + if not is_multiplayer_authority(): + return + + if is_player_moving: + return + + # Check if the movement is within range + if not is_within_movement_range(grid_position): + print("Movement out of range") + return + var cell_item = enhanced_gridmap.get_cell_item(Vector3i(grid_position.x, 0, grid_position.y)) if cell_item in enhanced_gridmap.non_walkable_items: @@ -131,11 +171,12 @@ func move_player_to_clicked_position(grid_position: Vector2i): if path.size() > 1: path.pop_front() - move_player_along_path(path) + rpc("start_movement_along_path", path) else: print("No valid path found") -func move_player_along_path(path: Array): +@rpc("any_peer", "call_local") +func start_movement_along_path(path: Array): is_player_moving = true var tween = create_tween() tween.set_trans(Tween.TRANS_CUBIC) @@ -150,10 +191,19 @@ func move_player_along_path(path: Array): is_player_moving = false enhanced_gridmap.clear_path_visualization() has_moved_this_turn = true - end_turn() + var main = get_node("/root/Main") + if main.turn_based_mode: + end_turn() ) -func move_bot_along_path(path: Array): +func move_bot_along_path(path: Array, bot_id: int): + if not is_multiplayer_authority(): + return + + rpc("start_bot_movement_along_path", path, bot_id) + +@rpc("any_peer", "call_local") +func start_bot_movement_along_path(path: Array, bot_id: int): is_player_moving = true var tween = create_tween() tween.set_trans(Tween.TRANS_CUBIC) @@ -168,7 +218,12 @@ func move_bot_along_path(path: Array): is_player_moving = false enhanced_gridmap.clear_path_visualization() has_moved_this_turn = true - end_turn() + var main = get_node("/root/Main") + if main.turn_based_mode: + end_turn() + # Notify main that bot movement is complete + if multiplayer.is_server(): + main.bot_movement_completed(bot_id) ) func update_player_position(grid_position: Vector2i): diff --git a/scenes/player.tscn b/scenes/player.tscn index 70a0e4e..e2ad91b 100644 --- a/scenes/player.tscn +++ b/scenes/player.tscn @@ -23,6 +23,7 @@ spacing_glyph = 5 transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 2.5, 0) script = ExtResource("1_qecr4") cell_size = Vector3(1, 1, 1) +use_diagonal_movement = true [node name="Masbro" parent="." instance=ExtResource("2_mjsl8")] transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -0.485, 0) @@ -64,7 +65,7 @@ uppercase = true autowrap_mode = 2 [node name="Bubble" type="Sprite3D" parent="."] -transform = Transform3D(1.4, 0, 0, 0, 1.4, 0, 0, 0, 1.4, 0, 7.5, 0) +transform = Transform3D(0.625, 0, 0, 0, 0.625, 0, 0, 0, 0.625, 0, 2.63593, 0) visible = false billboard = 1 texture = ExtResource("2_5w327") @@ -75,10 +76,10 @@ billboard = 1 double_sided = false no_depth_test = true render_priority = 1 -text = ". . ." +text = ". . . ." font = SubResource("FontVariation_q2tkp") font_size = 48 -outline_size = 26 +outline_size = 24 uppercase = true autowrap_mode = 3 justification_flags = 171