3D Switches

This commit is contained in:
Marco 2025-06-13 17:46:44 +02:00
commit cb60226ced
20 changed files with 267 additions and 14 deletions

View file

@ -1,4 +1,4 @@
[gd_scene load_steps=490 format=4 uid="uid://c8gtrjf2xeue7"] [gd_scene load_steps=491 format=4 uid="uid://c8gtrjf2xeue7"]
[ext_resource type="Script" uid="uid://kno58homctew" path="res://addons/func_godot/src/map/func_godot_map.gd" id="1_n6h0p"] [ext_resource type="Script" uid="uid://kno58homctew" path="res://addons/func_godot/src/map/func_godot_map.gd" id="1_n6h0p"]
[ext_resource type="Resource" uid="uid://cx41lsryg5wpm" path="res://3D/TrenchBroom/map_settings.tres" id="2_i0sba"] [ext_resource type="Resource" uid="uid://cx41lsryg5wpm" path="res://3D/TrenchBroom/map_settings.tres" id="2_i0sba"]
@ -37,6 +37,7 @@
[ext_resource type="Script" uid="uid://crjplbs250g75" path="res://3D/TrenchBroom/EntityScripts/Lights/light_spot.gd" id="31_c2mph"] [ext_resource type="Script" uid="uid://crjplbs250g75" path="res://3D/TrenchBroom/EntityScripts/Lights/light_spot.gd" id="31_c2mph"]
[ext_resource type="Material" uid="uid://l3g1l0y47c7r" path="res://textures/Manual/Electric_Panel_Wall.tres" id="32_k4tgc"] [ext_resource type="Material" uid="uid://l3g1l0y47c7r" path="res://textures/Manual/Electric_Panel_Wall.tres" id="32_k4tgc"]
[ext_resource type="PackedScene" uid="uid://c2enjjxlfb5or" path="res://3D/Scenes/Props/barrel_3d.tscn" id="33_8pgky"] [ext_resource type="PackedScene" uid="uid://c2enjjxlfb5or" path="res://3D/Scenes/Props/barrel_3d.tscn" id="33_8pgky"]
[ext_resource type="PackedScene" uid="uid://du6hlcoq0iip4" path="res://3D/Scenes/Props/control_pad_3d.tscn" id="35_c4mw0"]
[ext_resource type="Script" uid="uid://cyr7ypanl8drq" path="res://Scripts/Actors/Elevator3D.cs" id="36_3x0wn"] [ext_resource type="Script" uid="uid://cyr7ypanl8drq" path="res://Scripts/Actors/Elevator3D.cs" id="36_3x0wn"]
[ext_resource type="PackedScene" uid="uid://cq6tw87ei4by3" path="res://3D/Scenes/Props/elevator_3d.tscn" id="36_b3evc"] [ext_resource type="PackedScene" uid="uid://cq6tw87ei4by3" path="res://3D/Scenes/Props/elevator_3d.tscn" id="36_b3evc"]
[ext_resource type="PackedScene" uid="uid://bhh7qq1plw53i" path="res://Scenes/Interactable/AreaTrigger3D.tscn" id="38_vqonp"] [ext_resource type="PackedScene" uid="uid://bhh7qq1plw53i" path="res://Scenes/Interactable/AreaTrigger3D.tscn" id="38_vqonp"]
@ -3180,6 +3181,10 @@ transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 28.5, 1.5, 17.5)
[node name="Props" type="Node3D" parent="."] [node name="Props" type="Node3D" parent="."]
[node name="ControlPad" parent="Props" node_paths=PackedStringArray("Target") instance=ExtResource("35_c4mw0")]
transform = Transform3D(0.175436, 0, 0.178108, 0, 0.25, 0, -0.178108, 0, 0.175436, 5.36001, 1.84412, 22.5297)
Target = NodePath("../TestElevator/Path3D/PathFollow3D")
[node name="Mainframe3d" parent="Props" instance=ExtResource("16_u5cc4")] [node name="Mainframe3d" parent="Props" instance=ExtResource("16_u5cc4")]
transform = Transform3D(0.25, 0, 0, 0, 0.25, 0, 0, 0, 0.25, 22.6824, 1.30461, 12.0268) transform = Transform3D(0.25, 0, 0, 0, 0.25, 0, 0, 0, 0.25, 22.6824, 1.30461, 12.0268)

View file

@ -0,0 +1,29 @@
[gd_scene load_steps=5 format=3 uid="uid://du6hlcoq0iip4"]
[ext_resource type="Script" uid="uid://qxh76ahgexqa" path="res://Scripts/Interactables/Switch3D.cs" id="1_papkq"]
[ext_resource type="Texture2D" uid="uid://d24g1qb40t72l" path="res://Sprites/Button_Small.png" id="2_ldivl"]
[ext_resource type="AudioStream" uid="uid://bjvklk7qmlivd" path="res://SFX/288963__littlerobotsoundfactory__click_electronic_14.wav" id="3_ldivl"]
[sub_resource type="SphereShape3D" id="SphereShape3D_itd0i"]
radius = 0.868968
[node name="ControlPad" type="Area3D" groups=["Interactable"]]
transform = Transform3D(0.701743, 0, 0.71243, 0, 1, 0, -0.71243, 0, 0.701743, 0, 0, 0)
collision_layer = 32
collision_mask = 0
script = ExtResource("1_papkq")
metadata/_edit_group_ = true
[node name="Sprite3D" type="Sprite3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 0.707107, 0.707107, 0, -0.707107, 0.707107, 0, 0, 0)
pixel_size = 0.1
texture_filter = 0
texture = ExtResource("2_ldivl")
hframes = 4
[node name="CollisionShape3D" type="CollisionShape3D" parent="."]
shape = SubResource("SphereShape3D_itd0i")
[node name="ActivationSound" type="AudioStreamPlayer3D" parent="."]
stream = ExtResource("3_ldivl")
bus = &"Effects"

View file

@ -117,3 +117,6 @@ script = ExtResource("11_4cdxq")
[node name="AudioStreamPlayer" type="AudioStreamPlayer" parent="ActivationProvider"] [node name="AudioStreamPlayer" type="AudioStreamPlayer" parent="ActivationProvider"]
stream = ExtResource("13_2ffwi") stream = ExtResource("13_2ffwi")
bus = &"Effects" bus = &"Effects"
[node name="AudioListener3D" type="AudioListener3D" parent="."]
current = true

View file

@ -1,6 +1,7 @@
[gd_scene load_steps=37 format=3 uid="uid://dkwi1hu1bixoe"] [gd_scene load_steps=38 format=3 uid="uid://dkwi1hu1bixoe"]
[ext_resource type="Script" uid="uid://baf6pxbvhqmjk" path="res://Scripts/Hud.cs" id="1_m0hb0"] [ext_resource type="Script" uid="uid://baf6pxbvhqmjk" path="res://Scripts/Hud.cs" id="1_m0hb0"]
[ext_resource type="PackedScene" uid="uid://dsaj5dx82brsg" path="res://Scenes/HUD/UiSelector.tscn" id="2_jidad"]
[ext_resource type="PackedScene" uid="uid://cd3ee1adstcrw" path="res://Scenes/HUD/HudItemContainer.tscn" id="2_mattb"] [ext_resource type="PackedScene" uid="uid://cd3ee1adstcrw" path="res://Scenes/HUD/HudItemContainer.tscn" id="2_mattb"]
[ext_resource type="LabelSettings" uid="uid://buk3e7bbwmnv1" path="res://Resources/Styles/Hud_Text_Style.tres" id="2_x7kl7"] [ext_resource type="LabelSettings" uid="uid://buk3e7bbwmnv1" path="res://Resources/Styles/Hud_Text_Style.tres" id="2_x7kl7"]
[ext_resource type="Texture2D" uid="uid://dde36pgb8fbwc" path="res://Sprites/selector_big.png" id="3_hee3i"] [ext_resource type="Texture2D" uid="uid://dde36pgb8fbwc" path="res://Sprites/selector_big.png" id="3_hee3i"]
@ -90,6 +91,7 @@ font_color = Color(0, 0.737255, 0.113725, 1)
[node name="HUD" type="CanvasLayer" node_paths=PackedStringArray("_healthLabel", "_healthBar", "_shieldLabel", "_shieldBar", "_motivationLabel", "_itemsContainer", "_gameOverPanel", "_fairyTerminatedPanel", "_hudInfoPanel", "NotificationsContainer", "WeaponContainer", "PauseMenuContainer", "DebugMenuHolder")] [node name="HUD" type="CanvasLayer" node_paths=PackedStringArray("_healthLabel", "_healthBar", "_shieldLabel", "_shieldBar", "_motivationLabel", "_itemsContainer", "_gameOverPanel", "_fairyTerminatedPanel", "_hudInfoPanel", "NotificationsContainer", "WeaponContainer", "PauseMenuContainer", "DebugMenuHolder")]
process_mode = 3 process_mode = 3
script = ExtResource("1_m0hb0") script = ExtResource("1_m0hb0")
SelectorScene = ExtResource("2_jidad")
WeaponContainerTemplate = ExtResource("2_mattb") WeaponContainerTemplate = ExtResource("2_mattb")
ItemNotificationTemplate = ExtResource("3_mw35l") ItemNotificationTemplate = ExtResource("3_mw35l")
_healthLabel = NodePath("HudInfo/HealthBarContainer/HealthLabel") _healthLabel = NodePath("HudInfo/HealthBarContainer/HealthLabel")

View file

@ -0,0 +1,45 @@
[gd_scene load_steps=6 format=3 uid="uid://dsaj5dx82brsg"]
[ext_resource type="Texture2D" uid="uid://dde36pgb8fbwc" path="res://Sprites/selector_big.png" id="1_undfg"]
[ext_resource type="Script" uid="uid://w85hem1ec8cq" path="res://Scripts/Tools/AnimatedTextureRect.gd" id="2_cjotf"]
[sub_resource type="AtlasTexture" id="AtlasTexture_vxp1j"]
atlas = ExtResource("1_undfg")
region = Rect2(0, 0, 16, 16)
[sub_resource type="AtlasTexture" id="AtlasTexture_bnh43"]
atlas = ExtResource("1_undfg")
region = Rect2(16, 0, 16, 16)
[sub_resource type="SpriteFrames" id="SpriteFrames_0vbph"]
animations = [{
"frames": [{
"duration": 1.0,
"texture": SubResource("AtlasTexture_vxp1j")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_bnh43")
}],
"loop": true,
"name": &"default",
"speed": 5.0
}]
[node name="UiSelector" type="Control"]
layout_mode = 3
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
[node name="TextureRect" type="TextureRect" parent="."]
layout_mode = 0
offset_left = -8.0
offset_top = -8.0
offset_right = 8.0
offset_bottom = 8.0
texture = SubResource("AtlasTexture_vxp1j")
stretch_mode = 2
script = ExtResource("2_cjotf")
Frames = SubResource("SpriteFrames_0vbph")

View file

@ -4,6 +4,7 @@ using System.Diagnostics;
using System.Linq; using System.Linq;
using Cirno.Scripts; using Cirno.Scripts;
using Cirno.Scripts.Interactables; using Cirno.Scripts.Interactables;
using Cirno.Scripts.Misc;
using Cirno.Scripts.Resources; using Cirno.Scripts.Resources;
using Godot.Collections; using Godot.Collections;
@ -53,4 +54,20 @@ public partial class Interactable : Area2D, IInteractable
{ {
return true; return true;
} }
public Vector2 GetScreenPosition()
{
if (CameraController.Instance is null)
{
return this.GlobalPosition;
}
return this.GlobalPosition - CameraController.Instance.GlobalPosition +
(GetViewport().GetVisibleRect().Size / 2);
}
public Vector2 GetGlobalPosition2D()
{
return GetGlobalPosition();
}
} }

View file

@ -1,4 +1,5 @@
using Cirno.Scripts.Interactables; using Cirno.Scripts.Interactables;
using Cirno.Scripts.Misc;
using Cirno.Scripts.Resources.Events; using Cirno.Scripts.Resources.Events;
using Godot; using Godot;
using Godot.Collections; using Godot.Collections;
@ -32,4 +33,20 @@ public partial class NPC : Area2D, IInteractable
{ {
return true; return true;
} }
public Vector2 GetScreenPosition()
{
if (CameraController.Instance is null)
{
return this.GlobalPosition;
}
return this.GlobalPosition - CameraController.Instance.GlobalPosition +
(GetViewport().GetVisibleRect().Size / 2);
}
public Vector2 GetGlobalPosition2D()
{
return GetGlobalPosition();
}
} }

View file

@ -48,8 +48,12 @@ public partial class IsoActivationProvider: Area3D, IModule<PlayerState, Charact
StateMachine = machine; StateMachine = machine;
_selectorController.Hide(); _selectorController.Hide();
// TODO: Create selector UI element and link the signals
if (Hud.Instance is not null)
{
Hud.Instance.CreateSelector(_selectorController);
}
// if (SelectorScene is not null && _selector is null) // if (SelectorScene is not null && _selector is null)
// { // {
@ -65,7 +69,9 @@ public partial class IsoActivationProvider: Area3D, IModule<PlayerState, Charact
public void PhysicsProcess(double delta) public void PhysicsProcess(double delta)
{ {
_selectorController.PhysicsProcess(delta);
HandleInteraction();
} }
public void HandleInteraction() public void HandleInteraction()

View file

@ -118,7 +118,7 @@ public partial class SelectorController : Node
{ {
if (SelectedInteractable != null) if (SelectedInteractable != null)
{ {
EmitSignalChangePosition(SelectedInteractable.GetGlobalPosition()); EmitSignalChangePosition(SelectedInteractable.GetScreenPosition());
EmitSignalShowSelector(); EmitSignalShowSelector();
} }
else else
@ -136,4 +136,10 @@ public partial class SelectorController : Node
{ {
EmitSignalHideSelector(); EmitSignalHideSelector();
} }
public void PhysicsProcess(double delta)
{
if (SelectedInteractable is null) return;
EmitSignalChangePosition(SelectedInteractable.GetScreenPosition());
}
} }

View file

@ -3,6 +3,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using Cirno.Scripts; using Cirno.Scripts;
using Cirno.Scripts.Components.FSM._3DPlayer;
using Cirno.Scripts.Resources; using Cirno.Scripts.Resources;
using Cirno.Scripts.UI; using Cirno.Scripts.UI;
using Cirno.Scripts.Utils; using Cirno.Scripts.Utils;
@ -405,5 +406,25 @@ public partial class Hud : CanvasLayer
//AddInventoryItem(item.Item, item.Count); //AddInventoryItem(item.Item, item.Count);
} }
public void CreateSelector(SelectorController controller)
{
var instance = SelectorScene.Instantiate<Control>();
this.AddChild(instance);
controller.ShowSelector += () =>
{
instance.Show();
};
controller.HideSelector += () =>
{
instance.Hide();
};
controller.ChangePosition += position =>
{
instance.GlobalPosition = position;
};
}
} }

View file

@ -7,6 +7,8 @@ public interface IInteractable
public bool Activate(ActivationType activationType = ActivationType.Toggle); public bool Activate(ActivationType activationType = ActivationType.Toggle);
public bool CanActivate(); public bool CanActivate();
public Vector2 GetGlobalPosition(); public Vector2 GetGlobalPosition2D();
public Vector2 GetScreenPosition();
//protected bool MeetsRequirements(); //protected bool MeetsRequirements();
} }

View file

@ -0,0 +1,37 @@
using Cirno.Scripts.Misc;
using Godot;
namespace Cirno.Scripts.Interactables;
public partial class Interactable3D : Area3D, IInteractable
{
public virtual bool Activate(ActivationType activationType = ActivationType.Toggle)
{
return true;
}
protected virtual bool MeetsRequirements()
{
return true;
}
public virtual bool CanActivate()
{
return true;
}
public Vector2 GetGlobalPosition2D()
{
return new Vector2(this.GlobalPosition.X, this.GlobalPosition.Z);
}
public Vector2 GetScreenPosition()
{
if (CameraController3D.Instance is null)
{
return this.GetGlobalPosition2D();
}
return CameraController3D.Instance.UnprojectPosition(this.GlobalPosition);
}
}

View file

@ -0,0 +1 @@
uid://7rcv7ip052ug

View file

@ -0,0 +1,46 @@
using System.Linq;
using Godot;
using Godot.Collections;
namespace Cirno.Scripts.Interactables;
public partial class Switch3D : Interactable3D
{
[Export] public Node Target { get; set; }
[Export] public Array<Node> Targets { get; private set; } = [];
[Export] public ActivationType ActivationType { get; set; } = ActivationType.Toggle;
[Signal]
public delegate void OnActivatedEventHandler(ActivationType activationType);
private AudioStreamPlayer _activationSound;
private readonly string _activationSoundName = "ActivationSound";
public override void _Ready()
{
_activationSound = GetNodeOrNull<AudioStreamPlayer>(_activationSoundName);
}
public override bool Activate(ActivationType activationType = ActivationType.Toggle)
{
var activationTypeToUse = activationType is ActivationType.Use ? ActivationType : activationType;
if (!MeetsRequirements()) return false;
_activationSound?.Play();
EmitSignal(SignalName.OnActivated, (int)activationTypeToUse);
// Compatibility for old single system
bool success = ActivateTarget(Target, activationTypeToUse);
return Targets.Aggregate(success, (current, target) => ActivateTarget(target, activationTypeToUse) | success);
}
private bool ActivateTarget(Node target, ActivationType activationType = ActivationType.Toggle)
{
if (target is not IActivable activable) return false;
activable?.Activate(activationType);
return true;
}
}

View file

@ -0,0 +1 @@
uid://qxh76ahgexqa

View file

@ -6,6 +6,7 @@ namespace Cirno.Scripts.Misc;
public partial class CameraController : Camera2D public partial class CameraController : Camera2D
{ {
public static CameraController Instance { get; private set; }
[Export] public bool PixelSnap { get; set; } = true; [Export] public bool PixelSnap { get; set; } = true;
[Export] public bool EnableSmoothing { get; set; } = true; [Export] public bool EnableSmoothing { get; set; } = true;
@ -41,6 +42,7 @@ public partial class CameraController : Camera2D
public override void _Ready() public override void _Ready()
{ {
Instance = this;
AddToGroup(CameraControllersGroupName); AddToGroup(CameraControllersGroupName);
} }

View file

@ -4,6 +4,8 @@ namespace Cirno.Scripts.Misc;
public partial class CameraController3D : Camera3D public partial class CameraController3D : Camera3D
{ {
public static CameraController3D Instance { get; private set; }
[Export] public bool EnableSmoothing = true; [Export] public bool EnableSmoothing = true;
[Export] public bool FollowTargeting = true; [Export] public bool FollowTargeting = true;
@ -27,6 +29,7 @@ public partial class CameraController3D : Camera3D
public override void _Ready() public override void _Ready()
{ {
Instance = this;
_target = GetNode<Node3D>(TargetPath); _target = GetNode<Node3D>(TargetPath);
if (_target == null) if (_target == null)
{ {

View file

@ -138,7 +138,7 @@ public partial class Selector : Node2D
{ {
if (SelectedInteractable != null) if (SelectedInteractable != null)
{ {
this.GlobalPosition = SelectedInteractable.GetGlobalPosition(); this.GlobalPosition = SelectedInteractable.GetGlobalPosition2D();
this.Visible = true; this.Visible = true;
} }
else else

View file

@ -1,6 +1,16 @@
namespace Cirno.Scripts.UI; using Cirno.Scripts.Interactables;
using Godot;
public partial class Selector3D namespace Cirno.Scripts.UI;
public partial class Selector3D : Control
{ {
public IInteractable Target { get; set; }
public override void _Process(double delta)
{
if (Target is null) return;
this.GlobalPosition = Target.GetScreenPosition();
}
} }

View file

@ -15,13 +15,13 @@ dest_files=["res://.godot/imported/Button_Small.png-98a4c5460459fa0da24d50dc27d2
[params] [params]
compress/mode=0 compress/mode=3
compress/high_quality=false compress/high_quality=false
compress/lossy_quality=0.7 compress/lossy_quality=0.7
compress/hdr_compression=1 compress/hdr_compression=1
compress/normal_map=0 compress/normal_map=0
compress/channel_pack=0 compress/channel_pack=0
mipmaps/generate=false mipmaps/generate=true
mipmaps/limit=-1 mipmaps/limit=-1
roughness/mode=0 roughness/mode=0
roughness/src_normal="" roughness/src_normal=""
@ -31,4 +31,4 @@ process/normal_map_invert_y=false
process/hdr_as_srgb=false process/hdr_as_srgb=false
process/hdr_clamp_exposure=false process/hdr_clamp_exposure=false
process/size_limit=0 process/size_limit=0
detect_3d/compress_to=1 detect_3d/compress_to=0