A dungeon delver roguelike using Pathfinder 2nd edition rules

Adding in support to select different characters

+114 -49
+24 -13
camera/camera.gd
··· 28 var rotate_direction: float = 0.0 29 var zoom_percent: float = 0.5 30 31 - @onready var fighter: CharacterBody3D = $"../FighterCharacter" 32 33 func _physics_process(delta: float) -> void: 34 if Input.is_action_just_pressed("Right") or Input.is_action_just_pressed("Left"): ··· 99 rotate_direction = 0.0 100 101 if Input.is_action_just_pressed("Select"): 102 - if $"../FighterCharacter".marker: 103 - $"../FighterCharacter".marker.queue_free() 104 105 var mouse_pos = get_viewport().get_mouse_position() 106 var from = $"Path3D/PathFollow3D/SpringArm3D/Camera3D".project_ray_origin(mouse_pos) 107 var to = from + $"Path3D/PathFollow3D/SpringArm3D/Camera3D".project_ray_normal(mouse_pos) * 1000.0 108 var space_state = get_world_3d().direct_space_state 109 var query = PhysicsRayQueryParameters3D.create(from, to) 110 - query.exclude = [$"../FighterCharacter"] 111 var result = space_state.intersect_ray(query) 112 113 if result: 114 - $"../FighterCharacter".target_position = result.position 115 - $"../FighterCharacter".state = $"../FighterCharacter".State.STATE_TARGET 116 - var char_marker: Node3D = load("res://CharacterMarker.tscn").instantiate() 117 - var marker_position: Vector3 = result.position 118 - marker_position.y = 0.0 119 - $"..".add_child(char_marker) 120 - char_marker.global_scale(Vector3(0.61, 0.61, 0.61)) 121 - char_marker.global_translate(marker_position) 122 - $"../FighterCharacter".marker = char_marker 123 124 $Path3D/PathFollow3D.progress = zoom_percent 125 ··· 168 return sustain * (1.0 - t / release) 169 else: 170 return 0.0
··· 28 var rotate_direction: float = 0.0 29 var zoom_percent: float = 0.5 30 31 + var selected_character: GameCharacter 32 + var character_marker: Node3D 33 34 func _physics_process(delta: float) -> void: 35 if Input.is_action_just_pressed("Right") or Input.is_action_just_pressed("Left"): ··· 100 rotate_direction = 0.0 101 102 if Input.is_action_just_pressed("Select"): 103 + if character_marker: 104 + character_marker.queue_free() 105 106 var mouse_pos = get_viewport().get_mouse_position() 107 var from = $"Path3D/PathFollow3D/SpringArm3D/Camera3D".project_ray_origin(mouse_pos) 108 var to = from + $"Path3D/PathFollow3D/SpringArm3D/Camera3D".project_ray_normal(mouse_pos) * 1000.0 109 var space_state = get_world_3d().direct_space_state 110 var query = PhysicsRayQueryParameters3D.create(from, to) 111 var result = space_state.intersect_ray(query) 112 113 if result: 114 + if result.collider is GameCharacter: 115 + if selected_character: 116 + selected_character.is_selected = false 117 + 118 + selected_character = result.collider 119 + selected_character.is_selected = true 120 + else: 121 + if selected_character: 122 + selected_character.target_position = result.position 123 + selected_character.state = GameCharacter.State.STATE_TARGET 124 + character_marker = load("res://CharacterMarker.tscn").instantiate() 125 + var marker_position: Vector3 = result.position 126 + marker_position.y = 0.0 127 + $"..".add_child(character_marker) 128 + character_marker.global_scale(Vector3(0.61, 0.61, 0.61)) 129 + character_marker.global_translate(marker_position) 130 131 $Path3D/PathFollow3D.progress = zoom_percent 132 ··· 175 return sustain * (1.0 - t / release) 176 else: 177 return 0.0 178 + 179 + 180 + func _on_character_done_moving() -> void: 181 + character_marker.queue_free()
+41 -27
characters/character.gd
··· 1 extends CharacterBody3D 2 3 - var is_selected: bool = true 4 @export var speed: float = 5.0 5 var target_position: Vector3 = Vector3.ZERO 6 var state: State = State.STATE_IDLE ··· 8 @export var rotation_speed: float = 0.3 9 var direction: Vector3 = Vector3.ZERO 10 var marker: Node3D 11 12 enum State {STATE_IDLE, STATE_TARGET, STATE_ROTATE, STATE_MOVE} 13 14 func _physics_process(delta: float) -> void: 15 if state == State.STATE_IDLE: 16 pass 17 elif state == State.STATE_TARGET: 18 - # Has target, calculate direction and check rotation 19 - direction = target_position - global_transform.origin 20 - direction.y = 0.0 21 - direction = direction.normalized() 22 - target_rotation = atan2(direction.x, direction.z) 23 - 24 - if is_equal_approx(global_rotation.y, target_rotation): 25 - state = State.STATE_MOVE 26 - else: 27 - state = State.STATE_ROTATE 28 elif state == State.STATE_ROTATE: 29 - global_rotate(Vector3.UP, (target_rotation - global_rotation.y) * rotation_speed) 30 - 31 - if is_equal_approx(global_rotation.y, target_rotation): 32 - target_rotation = global_rotation.y 33 - state = State.STATE_MOVE 34 elif state == State.STATE_MOVE: 35 - direction = target_position - global_transform.origin 36 - direction.y = 0.0 37 - 38 - if direction.length() < 0.1: 39 - velocity = Vector3.ZERO 40 - marker.queue_free() 41 - state = State.STATE_IDLE 42 - else: 43 - var norm_dir = direction.normalized() 44 - velocity = direction * speed 45 46 - move_and_slide()
··· 1 extends CharacterBody3D 2 3 + class_name GameCharacter 4 + 5 + var is_selected: bool = false 6 @export var speed: float = 5.0 7 var target_position: Vector3 = Vector3.ZERO 8 var state: State = State.STATE_IDLE ··· 10 @export var rotation_speed: float = 0.3 11 var direction: Vector3 = Vector3.ZERO 12 var marker: Node3D 13 + @export var model: MeshInstance3D 14 + @export var model_scene: ModelScene 15 16 enum State {STATE_IDLE, STATE_TARGET, STATE_ROTATE, STATE_MOVE} 17 18 func _physics_process(delta: float) -> void: 19 + if model: 20 + model.set_instance_shader_parameter("outline", is_selected) 21 + elif model_scene: 22 + model_scene.set_shader_parameter("outline", is_selected) 23 + 24 if state == State.STATE_IDLE: 25 pass 26 elif state == State.STATE_TARGET: 27 + if is_selected: 28 + # Has target, calculate direction and check rotation 29 + direction = target_position - global_transform.origin 30 + direction.y = 0.0 31 + direction = direction.normalized() 32 + target_rotation = atan2(direction.x, direction.z) 33 + 34 + if is_equal_approx(global_rotation.y, target_rotation): 35 + state = State.STATE_MOVE 36 + else: 37 + state = State.STATE_ROTATE 38 elif state == State.STATE_ROTATE: 39 + if is_selected: 40 + global_rotate(Vector3.UP, (target_rotation - global_rotation.y) * rotation_speed) 41 + 42 + if is_equal_approx(global_rotation.y, target_rotation): 43 + target_rotation = global_rotation.y 44 + state = State.STATE_MOVE 45 elif state == State.STATE_MOVE: 46 + if is_selected: 47 + direction = target_position - global_transform.origin 48 + direction.y = 0.0 49 + 50 + if direction.length() < 0.1: 51 + velocity = Vector3.ZERO 52 + done_moving.emit() 53 + state = State.STATE_IDLE 54 + else: 55 + var norm_dir = direction.normalized() 56 + velocity = direction * speed 57 58 + move_and_slide() 59 + 60 + signal done_moving
+3
characters/character_material.tres
··· 20 shader_parameter/uv2_offset = Vector3(0, 0, 0) 21 shader_parameter/color_gradient = ExtResource("2_ettja") 22 shader_parameter/color_ramp3 = ExtResource("3_bpphy")
··· 20 shader_parameter/uv2_offset = Vector3(0, 0, 0) 21 shader_parameter/color_gradient = ExtResource("2_ettja") 22 shader_parameter/color_ramp3 = ExtResource("3_bpphy") 23 + shader_parameter/outline = false 24 + shader_parameter/outline_color = Color(0, 1, 0, 1) 25 + shader_parameter/outline_factor = 0.315
+2 -1
characters/cleric/cleric_character.tscn
··· 38 blend_shape_mode = 0 39 shadow_mesh = SubResource("ArrayMesh_bontn") 40 41 - [node name="ClericCharacter" type="CharacterBody3D"] 42 script = ExtResource("1_68csu") 43 44 [node name="CollisionShape3D" type="CollisionShape3D" parent="."] 45 transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.408191, 0)
··· 38 blend_shape_mode = 0 39 shadow_mesh = SubResource("ArrayMesh_bontn") 40 41 + [node name="ClericCharacter" type="CharacterBody3D" node_paths=PackedStringArray("model")] 42 script = ExtResource("1_68csu") 43 + model = NodePath("life-cleric-generic") 44 45 [node name="CollisionShape3D" type="CollisionShape3D" parent="."] 46 transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.408191, 0)
+2 -1
characters/fighter/fighter_character.tscn
··· 38 radius = 0.297383 39 height = 1.08517 40 41 - [node name="FighterCharacter" type="CharacterBody3D"] 42 script = ExtResource("1_7dkdi") 43 speed = 3.0 44 45 [node name="human-fighter-swinging-sword" type="MeshInstance3D" parent="."] 46 transform = Transform3D(0.023, 0, 0, 0, 0.023, 0, 0, 0, 0.023, -0.0066942, 0.00537896, -0.000691414)
··· 38 radius = 0.297383 39 height = 1.08517 40 41 + [node name="FighterCharacter" type="CharacterBody3D" node_paths=PackedStringArray("model")] 42 script = ExtResource("1_7dkdi") 43 speed = 3.0 44 + model = NodePath("human-fighter-swinging-sword") 45 46 [node name="human-fighter-swinging-sword" type="MeshInstance3D" parent="."] 47 transform = Transform3D(0.023, 0, 0, 0, 0.023, 0, 0, 0, 0.023, -0.0066942, 0.00537896, -0.000691414)
+9
characters/model_scene.gd
···
··· 1 + extends Node3D 2 + 3 + class_name ModelScene 4 + 5 + @export var meshes: Array[MeshInstance3D] 6 + 7 + func set_shader_parameter(parameter: String, value: Variant) -> void: 8 + for mesh in meshes: 9 + mesh.set_instance_shader_parameter(parameter, value)
+1
characters/model_scene.gd.uid
···
··· 1 + uid://bdvl53c272xmt
+2 -1
characters/rogue/rogue_character.tscn
··· 7 radius = 0.403604 8 height = 0.816567 9 10 - [node name="RogueCharacter" type="CharacterBody3D"] 11 script = ExtResource("1_uhmuc") 12 13 [node name="CollisionShape3D" type="CollisionShape3D" parent="."] 14 transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.381376, 0)
··· 7 radius = 0.403604 8 height = 0.816567 9 10 + [node name="RogueCharacter" type="CharacterBody3D" node_paths=PackedStringArray("model_scene")] 11 script = ExtResource("1_uhmuc") 12 + model_scene = NodePath("RogueModel") 13 14 [node name="CollisionShape3D" type="CollisionShape3D" parent="."] 15 transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.381376, 0)
+6 -2
characters/rogue/rogue_model.tscn
··· 1 - [gd_scene load_steps=10 format=4 uid="uid://bokcp703oiqk8"] 2 3 [ext_resource type="Material" uid="uid://bps4iuygau6n3" path="res://characters/character_material.tres" id="1_3npe2"] 4 5 [sub_resource type="ArrayMesh" id="ArrayMesh_5m658"] 6 _surfaces = [{ ··· 127 blend_shape_mode = 0 128 shadow_mesh = SubResource("ArrayMesh_cr22a") 129 130 - [node name="RogueModel" type="Node3D"] 131 132 [node name="BasePlate" type="MeshInstance3D" parent="."] 133 transform = Transform3D(0.764938, 0, -0.644104, 0, 1, 0, 0.644104, 0, 0.764938, 2.11243, 0, 0.572008)
··· 1 + [gd_scene load_steps=11 format=4 uid="uid://bokcp703oiqk8"] 2 3 [ext_resource type="Material" uid="uid://bps4iuygau6n3" path="res://characters/character_material.tres" id="1_3npe2"] 4 + [ext_resource type="Script" uid="uid://bdvl53c272xmt" path="res://characters/model_scene.gd" id="1_7fbe8"] 5 6 [sub_resource type="ArrayMesh" id="ArrayMesh_5m658"] 7 _surfaces = [{ ··· 128 blend_shape_mode = 0 129 shadow_mesh = SubResource("ArrayMesh_cr22a") 130 131 + [node name="RogueModel" type="Node3D" node_paths=PackedStringArray("meshes")] 132 + script = ExtResource("1_7fbe8") 133 + meshes = [NodePath("BasePlate"), NodePath("Body"), NodePath("SwordRight"), NodePath("SwordLeft")] 134 + metadata/_custom_type_script = "uid://bdvl53c272xmt" 135 136 [node name="BasePlate" type="MeshInstance3D" parent="."] 137 transform = Transform3D(0.764938, 0, -0.644104, 0, 1, 0, 0.644104, 0, 0.764938, 2.11243, 0, 0.572008)
+2 -1
characters/wizard/wizard_character.tscn
··· 7 radius = 0.400701 8 height = 0.967233 9 10 - [node name="WizardCharacter" type="CharacterBody3D"] 11 script = ExtResource("1_vahtv") 12 13 [node name="CollisionShape3D" type="CollisionShape3D" parent="."] 14 transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.471839, 0)
··· 7 radius = 0.400701 8 height = 0.967233 9 10 + [node name="WizardCharacter" type="CharacterBody3D" node_paths=PackedStringArray("model_scene")] 11 script = ExtResource("1_vahtv") 12 + model_scene = NodePath("WizardModel") 13 14 [node name="CollisionShape3D" type="CollisionShape3D" parent="."] 15 transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.471839, 0)
+6 -2
characters/wizard/wizard_model.tscn
··· 1 - [gd_scene load_steps=8 format=4 uid="uid://bx7j7fjtj5lfo"] 2 3 [ext_resource type="Material" uid="uid://bps4iuygau6n3" path="res://characters/character_material.tres" id="1_koa57"] 4 5 [sub_resource type="ArrayMesh" id="ArrayMesh_lca5c"] 6 _surfaces = [{ ··· 95 blend_shape_mode = 0 96 shadow_mesh = SubResource("ArrayMesh_t23ju") 97 98 - [node name="WizardModel" type="Node3D"] 99 100 [node name="BasePlate" type="MeshInstance3D" parent="."] 101 transform = Transform3D(-0.920275, 0, -0.391273, 0, 1, 0, -0.391273, 0, 0.920275, -0.351186, 0, 0.915214)
··· 1 + [gd_scene load_steps=9 format=4 uid="uid://bx7j7fjtj5lfo"] 2 3 [ext_resource type="Material" uid="uid://bps4iuygau6n3" path="res://characters/character_material.tres" id="1_koa57"] 4 + [ext_resource type="Script" uid="uid://bdvl53c272xmt" path="res://characters/model_scene.gd" id="1_u6713"] 5 6 [sub_resource type="ArrayMesh" id="ArrayMesh_lca5c"] 7 _surfaces = [{ ··· 96 blend_shape_mode = 0 97 shadow_mesh = SubResource("ArrayMesh_t23ju") 98 99 + [node name="WizardModel" type="Node3D" node_paths=PackedStringArray("meshes")] 100 + script = ExtResource("1_u6713") 101 + meshes = [NodePath("BasePlate"), NodePath("Body"), NodePath("Weapon")] 102 + metadata/_custom_type_script = "uid://bdvl53c272xmt" 103 104 [node name="BasePlate" type="MeshInstance3D" parent="."] 105 transform = Transform3D(-0.920275, 0, -0.391273, 0, 1, 0, -0.391273, 0, 0.920275, -0.351186, 0, 0.915214)
+6 -1
dungeonRoom/dungeonRoom.tscn
··· 59 60 [node name="Camera" parent="." instance=ExtResource("14_cr8g4")] 61 transform = Transform3D(1, 0, 0, 0, 0.939693, 0.34202, 0, -0.34202, 0.939693, 0, 0.367939, -0.173382) 62 - move_speed = 0.3 63 rotate_speed = 0.05 64 65 [node name="DirectionalLight3D" type="DirectionalLight3D" parent="."] ··· 77 78 [node name="WizardCharacter" parent="." instance=ExtResource("12_lg62f")] 79 transform = Transform3D(-4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, -3.048, 0, 0.762)
··· 59 60 [node name="Camera" parent="." instance=ExtResource("14_cr8g4")] 61 transform = Transform3D(1, 0, 0, 0, 0.939693, 0.34202, 0, -0.34202, 0.939693, 0, 0.367939, -0.173382) 62 + move_speed = 0.1 63 rotate_speed = 0.05 64 65 [node name="DirectionalLight3D" type="DirectionalLight3D" parent="."] ··· 77 78 [node name="WizardCharacter" parent="." instance=ExtResource("12_lg62f")] 79 transform = Transform3D(-4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, -3.048, 0, 0.762) 80 + 81 + [connection signal="done_moving" from="FighterCharacter" to="Camera" method="_on_character_done_moving"] 82 + [connection signal="done_moving" from="RogueCharacter" to="Camera" method="_on_character_done_moving"] 83 + [connection signal="done_moving" from="ClericCharacter" to="Camera" method="_on_character_done_moving"] 84 + [connection signal="done_moving" from="WizardCharacter" to="Camera" method="_on_character_done_moving"]
+10
shader/toon.gdshader
··· 19 uniform sampler2D color_gradient; 20 uniform sampler2D color_ramp3; 21 22 float fresnel(float amount, vec3 normal, vec3 view) 23 { 24 return pow((1.0 - clamp(dot(normalize(normal), normalize(view)), 0.0, 1.0 )), amount); ··· 42 SPECULAR = 0.0; 43 NORMAL_MAP = texture(texture_normal,base_uv).rgb; 44 NORMAL_MAP_DEPTH = normal_scale; 45 } 46 47 void light() {
··· 19 uniform sampler2D color_gradient; 20 uniform sampler2D color_ramp3; 21 22 + instance uniform bool outline; 23 + uniform vec4 outline_color : source_color; 24 + uniform float outline_factor; 25 + 26 float fresnel(float amount, vec3 normal, vec3 view) 27 { 28 return pow((1.0 - clamp(dot(normalize(normal), normalize(view)), 0.0, 1.0 )), amount); ··· 46 SPECULAR = 0.0; 47 NORMAL_MAP = texture(texture_normal,base_uv).rgb; 48 NORMAL_MAP_DEPTH = normal_scale; 49 + 50 + if (outline) { 51 + float angle = dot(NORMAL, VIEW); 52 + float t = clamp(angle * angle, 0.0, 1.0); 53 + ALBEDO = mix(vec3(outline_color.r, outline_color.g, outline_color.b) * outline_factor, ALBEDO, t); 54 + } 55 } 56 57 void light() {