first commit

This commit is contained in:
2024-10-22 16:15:56 +08:00
commit 6b9360d4dc
44 changed files with 2235 additions and 0 deletions
+45
View File
@@ -0,0 +1,45 @@
[gd_scene load_steps=8 format=3 uid="uid://dxn87yj8qnfpp"]
[ext_resource type="MeshLibrary" uid="uid://54tpx8cmksfc" path="res://addons/enhanced_gridmap/meshlibrary/default.tres" id="1_110wo"]
[ext_resource type="Script" path="res://addons/enhanced_gridmap/enhanced_gridmap.gd" id="2_hbe1v"]
[ext_resource type="Script" path="res://scenes/player.gd" id="3_4ksq5"]
[ext_resource type="PackedScene" uid="uid://faku1hodioqu" path="res://assets/character.glb" id="4_0d1yx"]
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_xqgey"]
albedo_color = Color(0.85, 0.085, 0.238, 1)
[sub_resource type="CapsuleMesh" id="CapsuleMesh_l8ldl"]
material = SubResource("StandardMaterial3D_xqgey")
[sub_resource type="SphereShape3D" id="SphereShape3D_3oo5r"]
[node name="Main" type="Node3D"]
[node name="EnhancedGridMap" type="GridMap" parent="."]
mesh_library = ExtResource("1_110wo")
data = {
"cells": PackedInt32Array(0, 0, 0, 0, 1, 0, 0, 2, 4, 0, 3, 0, 0, 4, 4, 0, 5, 0, 0, 6, 0, 0, 7, 0, 0, 8, 4, 0, 9, 0, 1, 0, 0, 1, 1, 0, 1, 2, 0, 1, 3, 0, 1, 4, 0, 1, 5, 4, 1, 6, 0, 1, 7, 0, 1, 8, 4, 1, 9, 4, 2, 0, 0, 2, 1, 0, 2, 2, 4, 2, 3, 0, 2, 4, 0, 2, 5, 4, 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, 4, 3, 9, 0, 4, 0, 0, 4, 1, 4, 4, 2, 0, 4, 3, 0, 4, 4, 4, 4, 5, 0, 4, 6, 0, 4, 7, 0, 4, 8, 0, 4, 9, 4, 5, 0, 4, 5, 1, 0, 5, 2, 0, 5, 3, 4, 5, 4, 0, 5, 5, 4, 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, 4, 7, 0, 0, 7, 1, 0, 7, 2, 4, 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, 4, 8, 9, 0, 9, 0, 0, 9, 1, 0, 9, 2, 4, 9, 3, 0, 9, 4, 4, 9, 5, 0, 9, 6, 4, 9, 7, 0, 9, 8, 0, 9, 9, 0)
}
script = ExtResource("2_hbe1v")
[node name="CharacterBody3D" type="CharacterBody3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 2.5, 0)
script = ExtResource("3_4ksq5")
enhanced_gridmap_path = NodePath("../EnhancedGridMap")
player_path = NodePath(".")
[node name="MeshInstance3D" type="MeshInstance3D" parent="CharacterBody3D"]
visible = false
mesh = SubResource("CapsuleMesh_l8ldl")
[node name="CollisionShape3D" type="CollisionShape3D" parent="CharacterBody3D"]
shape = SubResource("SphereShape3D_3oo5r")
[node name="character2" parent="CharacterBody3D" instance=ExtResource("4_0d1yx")]
[node name="Camera3D" type="Camera3D" parent="."]
transform = Transform3D(1, 0, 0, 0, -4.37114e-08, 1, 0, -1, -4.37114e-08, 10, 30, 10)
fov = 55.0
[node name="DirectionalLight3D" type="DirectionalLight3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 5, 10, 5)
+133
View File
@@ -0,0 +1,133 @@
extends Node3D # This script is attached to a Node3D (main scene)
var multiplayer_peer = ENetMultiplayerPeer.new() # Create a new ENet multiplayer peer
const PORT = 9999 # Define the port for multiplayer
const ADDRESS = "127.0.0.1" # Define the IP address for multiplayer
var connected_peer_ids = [] # List of connected peer IDs
var local_player_character : CharacterBody3D # Reference to the local player character
var player_scene = preload("res://scenes/player.tscn") # Preload the player scene
var current_turn_index = 0 # Index of the current turn
@export var players = [] # List of player IDs
var game_started = false # Flag to track if the game has started
var max_message_input_char = 51 # Maximum characters allowed in a message
func _on_host_pressed(): # Called when the host button is pressed
$NetworkInfo/NetworkSideDisplay.text = "Server"
$Menu.visible = false
multiplayer_peer.create_server(PORT) # Create a multiplayer server
multiplayer.multiplayer_peer = multiplayer_peer
$NetworkInfo/UniquePeerID.text = str(multiplayer.get_unique_id())
add_player_character(1) # Add host player character
players.append(1) # Add host to players list
if players.size() == 2:
start_game() # Start game if two players are connected
multiplayer_peer.peer_connected.connect(_on_peer_connected) # Connect peer connected signal
func _on_join_pressed(): # Called when the join button is pressed
$NetworkInfo/NetworkSideDisplay.text = "Client"
$Menu.visible = false
multiplayer_peer.create_client(ADDRESS, PORT) # Create a multiplayer client
multiplayer.multiplayer_peer = multiplayer_peer
$NetworkInfo/UniquePeerID.text = str(multiplayer.get_unique_id())
func _on_peer_connected(new_peer_id): # Called when a new peer connects
if multiplayer.is_server():
await get_tree().create_timer(1).timeout
rpc("add_newly_connected_player_character", new_peer_id) # RPC call to add new player
rpc_id(new_peer_id, "add_previously_connected_player_characters", connected_peer_ids) # RPC call to sync existing players
add_player_character(new_peer_id)
players.append(new_peer_id)
if players.size() == 2 and not game_started:
start_game() # Start game if two players are connected
func _on_peer_disconnected(peer_id): # Called when a peer disconnects
if multiplayer.is_server():
connected_peer_ids.erase(peer_id)
players.erase(peer_id)
if players.size() < 2:
game_started = false
func add_player_character(peer_id): # Add a player character to the game
connected_peer_ids.append(peer_id)
var player_character = player_scene.instantiate()
player_character.set_multiplayer_authority(peer_id)
add_child(player_character)
player_character.add_to_group("Players",true)
if peer_id == multiplayer.get_unique_id():
local_player_character = player_character
@rpc
func add_newly_connected_player_character(new_peer_id): # RPC function to add a new player character
add_player_character(new_peer_id)
@rpc
func add_previously_connected_player_characters(peer_ids): # RPC function to add existing player characters
for peer_id in peer_ids:
add_player_character(peer_id)
func _process(_delta): # Called every frame
if multiplayer.is_server() and game_started:
rpc("sync_turn_index", current_turn_index) # RPC call to sync turn index
func start_game(): # Start the game
if multiplayer.is_server():
game_started = true
connected_peer_ids.sort()
rpc("sync_game_start", connected_peer_ids) # RPC call to sync game start
current_turn_index = -1
next_turn()
@rpc
func sync_game_start(peer_ids): # RPC function to sync game start
connected_peer_ids = peer_ids
game_started = true
@rpc("reliable")
func sync_turn_index(index): # RPC function to sync turn index
current_turn_index = index
func next_turn(): # Move to the next turn
if multiplayer.is_server():
current_turn_index += 1
if current_turn_index >= connected_peer_ids.size():
current_turn_index = -1
next_turn()
else:
rpc("set_current_turn", connected_peer_ids[current_turn_index]) # RPC call to set current turn
func request_next_turn(): # Request to move to the next turn
if multiplayer.is_server():
end_current_turn()
else:
rpc_id(1, "server_end_current_turn") # RPC call to end turn on server
@rpc("any_peer")
func server_end_current_turn(): # RPC function to end current turn on server
if multiplayer.is_server():
end_current_turn()
@rpc("any_peer", "call_local")
func set_current_turn(player_id): # RPC function to set the current turn
var players = get_tree().get_nodes_in_group("Players")
for player in players:
player.is_my_turn = (player.name == str(player_id))
if player.is_my_turn:
player.start_turn()
func end_current_turn(): # End the current turns
if multiplayer.is_server():
next_turn()
rpc("sync_turn_index", current_turn_index) # RPC call to sync turn index
func _on_message_input_text_submitted(new_text): # Handle message input
if new_text.length() > max_message_input_char:
new_text = new_text.substr(0, max_message_input_char) + " ... "
local_player_character.rpc("display_message", new_text) # RPC call to display message
$MessageInput.text = ""
$MessageInput.release_focus()
+103
View File
@@ -0,0 +1,103 @@
[gd_scene load_steps=5 format=3 uid="uid://dxn87yj8qnfpp"]
[ext_resource type="MeshLibrary" uid="uid://54tpx8cmksfc" path="res://addons/enhanced_gridmap/meshlibrary/default.tres" id="1_110wo"]
[ext_resource type="Script" path="res://scenes/main.gd" id="1_xcpe3"]
[ext_resource type="Script" path="res://addons/enhanced_gridmap/enhanced_gridmap.gd" id="2_hbe1v"]
[ext_resource type="Environment" uid="uid://jbptgqvstei3" path="res://assets/main-environment.tres" id="4_ky38j"]
[node name="Main" type="Node3D"]
script = ExtResource("1_xcpe3")
[node name="EnhancedGridMap" type="GridMap" parent="."]
mesh_library = ExtResource("1_110wo")
cell_size = Vector3(1, 1, 1)
data = {
"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, 4, 1, 8, 0, 1, 9, 4, 2, 0, 4, 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, 4, 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, 4, 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, 4, 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, 4, 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, 4, 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])
[node name="Camera3D" type="Camera3D" parent="."]
transform = Transform3D(1, 0, 0, 0, -4.37114e-08, 1, 0, -1, -4.37114e-08, 5, 30, 5)
visible = false
environment = ExtResource("4_ky38j")
fov = 35.5
[node name="Camera3D2" type="Camera3D" parent="."]
transform = Transform3D(1, 0, 0, 0, -4.37114e-08, 1, 0, -1, -4.37114e-08, 5, 30, 5)
environment = ExtResource("4_ky38j")
fov = 35.5
[node name="Panel" type="Panel" parent="."]
anchors_preset = 5
anchor_left = 0.5
anchor_right = 0.5
offset_left = -77.0
offset_top = 6.0
offset_right = 77.0
offset_bottom = 59.0
grow_horizontal = 2
[node name="NetworkInfo" type="VBoxContainer" parent="."]
anchors_preset = 5
anchor_left = 0.5
anchor_right = 0.5
offset_left = -58.0
offset_top = 7.0
offset_right = 58.0
offset_bottom = 57.0
grow_horizontal = 2
[node name="NetworkSideDisplay" type="Label" parent="NetworkInfo"]
layout_mode = 2
text = "Network Side"
horizontal_alignment = 1
[node name="UniquePeerID" type="Label" parent="NetworkInfo"]
layout_mode = 2
text = "Unique Peer ID"
horizontal_alignment = 1
vertical_alignment = 1
[node name="Menu" type="VBoxContainer" parent="."]
anchors_preset = 8
anchor_left = 0.5
anchor_top = 0.5
anchor_right = 0.5
anchor_bottom = 0.5
offset_left = -85.0
offset_top = -33.0
offset_right = 85.0
offset_bottom = 33.0
grow_horizontal = 2
grow_vertical = 2
[node name="Host" type="Button" parent="Menu"]
layout_mode = 2
text = "Host"
[node name="Join" type="Button" parent="Menu"]
layout_mode = 2
text = "Join"
[node name="MessageInput" type="LineEdit" parent="."]
anchors_preset = 7
anchor_left = 0.5
anchor_top = 1.0
anchor_right = 0.5
anchor_bottom = 1.0
offset_left = -210.0
offset_top = -46.0
offset_right = 210.0
offset_bottom = -15.0
grow_horizontal = 2
grow_vertical = 0
placeholder_text = "Chat"
alignment = 1
[node name="WorldEnvironment" type="WorldEnvironment" parent="."]
environment = ExtResource("4_ky38j")
[connection signal="pressed" from="Menu/Host" to="." method="_on_host_pressed"]
[connection signal="pressed" from="Menu/Join" to="." method="_on_join_pressed"]
[connection signal="text_submitted" from="MessageInput" to="." method="_on_message_input_text_submitted"]
+187
View File
@@ -0,0 +1,187 @@
extends Node3D # This script is attached to a Node3D
# Export variables for inspector configuration
@export var enhanced_gridmap_path: NodePath = "/root/Main/EnhancedGridMap" # Path to the EnhancedGridMap node
var enhanced_gridmap: EnhancedGridMap # References to the EnhancedGridMap node
@export var current_position: Vector2i # Current grid position of the player
var is_player_moving: bool = false # Flag to prevent movement while already moving
# Customizable cell size and offset
@export var cell_size: Vector3 = Vector3(2, 2, 2) # Size of each grid cell
@export var cell_offset: Vector3 = Vector3(0, 0, 0) # Offset for the grid
# Center offset flags
@export var center_x: bool = false # Center the player on X axis
@export var center_y: bool = false # Center the player on Y axis
@export var center_z: bool = false # Center the player on Z axis
# Diagonal movement flag
@export var use_diagonal_movement: bool = false: # Allow diagonal movement
set(value):
use_diagonal_movement = value
if enhanced_gridmap:
enhanced_gridmap.set_diagonal_movement(value)
# Turn management variables
@export var is_my_turn: bool = false: # Flag to indicate if it's this player's turn
set(value):
is_my_turn = value
if is_my_turn and is_multiplayer_authority():
rpc("display_message", "It's your turn!") # RPC call to display turn message
@export var has_moved_this_turn = false # Flag to track if player has moved this turn
@onready var main_scene = get_tree().current_scene # Reference to the main scene
func _ready(): # Called when the node enters the scene tree
name = str(get_multiplayer_authority()) # Set the node name to the multiplayer authority ID
$Name.text = str(name) # Set the displayed name
enhanced_gridmap = get_node(enhanced_gridmap_path) # Get the EnhancedGridMap node
if main_scene:
enhanced_gridmap = main_scene.get_node("EnhancedGridMap") # Get EnhancedGridMap from main scene
else:
push_error("Main scene not found") # Error if main scene not found
if not enhanced_gridmap:
push_error("EnhancedGridMap node not found. Please set the correct path in the inspector.")
return
enhanced_gridmap.initialize_astar() # Initialize A* pathfinding
enhanced_gridmap.set_diagonal_movement(use_diagonal_movement) # Set diagonal movement option
current_position = find_valid_starting_position() # Find a valid starting position
update_player_position(current_position) # Update player's position
set_process_unhandled_input(is_multiplayer_authority()) # Only process input for the authority
func find_valid_starting_position() -> Vector2i: # Find a valid starting position
var rng = RandomNumberGenerator.new()
rng.randomize()
var max_attempts = 100
var attempts = 0
while attempts < max_attempts:
current_position = Vector2i(0, rng.randi_range(0, 9)) # Generate random position
var cell_item = enhanced_gridmap.get_cell_item(Vector3i(current_position.x, 0, current_position.y))
if cell_item not in enhanced_gridmap.non_walkable_items:
return current_position # Return valid position
attempts += 1
return Vector2i(0, 0) # Default position if no valid position found
func _physics_process(_delta): # Called every physics frame
if is_multiplayer_authority():
rpc("remote_set_position", global_position) # RPC call to sync position
func _unhandled_input(event): # Handle input events
if not is_multiplayer_authority() or not is_my_turn or is_player_moving:
return
if event is InputEventMouseButton and event.pressed and event.button_index == MOUSE_BUTTON_LEFT:
var camera = get_viewport().get_camera_3d()
var from = camera.project_ray_origin(event.position)
var to = from + camera.project_ray_normal(event.position) * 1000
var click_position = raycast_to_grid(from, to)
if click_position != Vector2i(-1, -1):
move_player_to_clicked_position(click_position)
func raycast_to_grid(from: Vector3, to: Vector3) -> Vector2i: # Convert 3D raycast to grid position
var plane = Plane(Vector3.UP, cell_offset.y)
var intersection = plane.intersects_ray(from, to - from)
if intersection:
var adjusted_intersection = intersection - cell_offset
var grid_position = Vector2i(
floor(adjusted_intersection.x / cell_size.x),
floor(adjusted_intersection.z / cell_size.z)
)
if grid_position.x >= 0 and grid_position.x < enhanced_gridmap.columns and \
grid_position.y >= 0 and grid_position.y < enhanced_gridmap.rows:
return grid_position
return Vector2i(-1, -1) # Invalid position
func move_player_to_clicked_position(grid_position: Vector2i): # Move player to clicked position
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:
print("Cannot move to non-walkable cell")
return
var path = enhanced_gridmap.find_path(Vector2(current_position), Vector2(grid_position))
if path.size() > 1:
path.pop_front()
move_player_along_path(path)
else:
print("No valid path found")
func move_player_along_path(path: Array): # Move player along calculated path
is_player_moving = true
var tween = create_tween()
tween.set_trans(Tween.TRANS_CUBIC)
tween.set_ease(Tween.EASE_IN_OUT)
for point in path:
var target_position = grid_to_world(Vector2i(point.x, point.y))
tween.tween_property(self, "position", target_position, 0.5)
tween.tween_callback(func():
current_position = Vector2i(path[-1].x, path[-1].y)
is_player_moving = false
enhanced_gridmap.clear_path_visualization()
has_moved_this_turn = true
end_turn()
)
func update_player_position(grid_position: Vector2i): # Update player's position
position = grid_to_world(grid_position)
func grid_to_world(grid_position: Vector2i) -> Vector3: # Convert grid position to world position
var world_position = Vector3(
grid_position.x * cell_size.x,
cell_size.y,
grid_position.y * cell_size.z
)
world_position.x += cell_size.x * 0.5
world_position.z += cell_size.z * 0.5
if center_x:
world_position.x += cell_size.x * 0.5
if center_y:
world_position.y += cell_size.y * 0.5
if center_z:
world_position.z += cell_size.z * 0.5
return world_position + cell_offset
func start_turn(): # Start player's turn
has_moved_this_turn = false
is_my_turn = true
if is_multiplayer_authority():
rpc("display_message", "It's your turn!") # RPC call to display turn message
func end_turn(): # End player's turn
is_my_turn = false
has_moved_this_turn = false
if is_multiplayer_authority():
get_node("/root/Main").request_next_turn() # Request next turn from main scene
@rpc("any_peer", "call_local", "unreliable")
func remote_set_position(authority_position): # RPC function to sync position
global_position = authority_position
@rpc("any_peer", "call_local")
func display_message(message): # RPC function to display messages
$Bubble.show()
$Bubble/Message.show()
$Bubble/Message.text = str(message)
await get_tree().create_timer(3).timeout
$Bubble.hide()
$Bubble/Message.hide()
+58
View File
@@ -0,0 +1,58 @@
[gd_scene load_steps=7 format=3 uid="uid://1dbdbg3q5778"]
[ext_resource type="Script" path="res://scenes/player.gd" id="1_qecr4"]
[ext_resource type="Texture2D" uid="uid://b4y41h16q6m34" path="res://assets/textures/bub.png" id="2_5w327"]
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_xqgey"]
albedo_color = Color(0.85, 0.085, 0.238, 1)
[sub_resource type="CapsuleMesh" id="CapsuleMesh_l8ldl"]
material = SubResource("StandardMaterial3D_xqgey")
[sub_resource type="SphereShape3D" id="SphereShape3D_3oo5r"]
[sub_resource type="FontVariation" id="FontVariation_q2tkp"]
spacing_glyph = 5
[node name="CharacterBody3D" type="CharacterBody3D"]
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)
[node name="MeshInstance3D" type="MeshInstance3D" parent="."]
mesh = SubResource("CapsuleMesh_l8ldl")
[node name="CollisionShape3D" type="CollisionShape3D" parent="."]
shape = SubResource("SphereShape3D_3oo5r")
[node name="Name" type="Label3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.47085, 0)
billboard = 1
modulate = Color(0.32, 0.614667, 1, 1)
text = "username"
font = SubResource("FontVariation_q2tkp")
font_size = 48
outline_size = 26
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)
visible = false
billboard = 1
texture = ExtResource("2_5w327")
[node name="Message" type="Label3D" parent="Bubble"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.00144005, 0)
billboard = 1
double_sided = false
no_depth_test = true
render_priority = 1
text = ". . ."
font = SubResource("FontVariation_q2tkp")
font_size = 48
outline_size = 26
uppercase = true
autowrap_mode = 3
justification_flags = 171
width = 700.0