Add placement preview

main
copygirl 5 months ago
parent 29f4eb35cd
commit 585768e48e
  1. 4
      objects/Item.cs
  2. 2
      objects/crate.tscn
  3. 62
      player/PickupController.cs
  4. 2
      player/player.tscn
  5. 10
      scenes/workshop.tscn

@ -2,6 +2,6 @@ public partial class Item : StaticBody3D
{
[Export] public Vector3I Size { get; set; }
public virtual MeshInstance3D Mesh
=> GetNode<MeshInstance3D>("MeshInstance3D");
public virtual Node3D Model
=> GetNode<Node3D>("Model");
}

@ -15,5 +15,5 @@ Palette = ExtResource("2_n415g")
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -0.125, 0)
shape = SubResource("BoxShape3D_to3fn")
[node name="blockbench_export" parent="." instance=ExtResource("3_tncd6")]
[node name="Model" parent="." instance=ExtResource("3_tncd6")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -0.5, 0)

@ -2,7 +2,7 @@ public partial class PickupController : Node3D
{
public Item CurrentItem { get; private set; }
public bool HasItemsHeld => GetChildCount() > 0;
MeshInstance3D _placementPreview;
Node3D _placementPreview;
[Export] public Camera3D Camera { get; set; }
[Export] public float PickupDistance { get; set; } = 2.0f;
@ -24,11 +24,19 @@ public partial class PickupController : Node3D
if (@event.IsActionPressed("interact_pickup")) {
if (!HasItemsHeld) {
// Create clone of the item's model, use it as placement preview.
_placementPreview = (Node3D)CurrentItem.Model.Duplicate(0);
_placementPreview.Name = "PlacementPreview";
_placementPreview.TopLevel = true;
_placementPreview.Visible = false;
SetMeshLayerOutline(_placementPreview, OutlineMode.Exclusive);
AddChild(_placementPreview);
// Parent item to the `PickupController`.
var prevRot = CurrentItem.GlobalRotation;
CurrentItem.GetParent().RemoveChild(CurrentItem);
AddChild(CurrentItem);
CurrentItem.Mesh.Layers &= (uint)~RenderLayer.Outline;
SetMeshLayerOutline(CurrentItem.Model, OutlineMode.Disable);
CurrentItem.Position = Vector3.Zero;
CurrentItem.GlobalRotation = prevRot;
CurrentItem.CollisionLayer &= (uint)~PhysicsLayer.Static;
@ -44,7 +52,14 @@ public partial class PickupController : Node3D
// CurrentItem.Freeze = false;
RemoveChild(CurrentItem);
_world.AddChild(CurrentItem);
CurrentItem.GlobalTransform = prevTransform;
CurrentItem.GlobalTransform = _placementPreview.Visible
? _placementPreview.GlobalTransform
: prevTransform;
RemoveChild(_placementPreview);
_placementPreview.QueueFree();
_placementPreview = null;
GetViewport().SetInputAsHandled();
}
@ -59,28 +74,31 @@ public partial class PickupController : Node3D
if (HasItemsHeld) {
if ((RayToMouseCursor() is RayResult ray) && (ray.Collider is Grid)) {
// Snao rotation to nearest axis.
// FIXME: This needs to snap to the
// var globalRot = CurrentItem.GlobalRotation;
// globalRot.X = Snapped(globalRot.X, Tau / 4);
// globalRot.Y = Snapped(globalRot.Y, Tau / 4);
// globalRot.Z = Snapped(globalRot.Z, Tau / 4);
// CurrentItem.GlobalRotation = globalRot;
// FIXME: This needs to snap relative to the grid rotation.
var globalRot = CurrentItem.GlobalRotation;
globalRot.X = Snapped(globalRot.X, Tau / 4);
globalRot.Y = Snapped(globalRot.Y, Tau / 4);
globalRot.Z = Snapped(globalRot.Z, Tau / 4);
_placementPreview.GlobalRotation = globalRot;
// Snap the position to the grid.
var halfSize = (Vector3)CurrentItem.Size * Grid.StepSize / 2;
var pos = ray.Position + halfSize * (ray.Normal * CurrentItem.GlobalTransform.Basis);
var pos = ray.Position + halfSize * (ray.Normal * _placementPreview.GlobalTransform.Basis);
pos = pos.Snapped(Grid.StepSize * Vector3.One); // FIXME: This does global snapping only
CurrentItem.GlobalPosition = pos;
_placementPreview.GlobalPosition = pos;
_placementPreview.Visible = true;
} else {
_placementPreview.Visible = false;
}
} else {
var interactable = RayToMouseCursor()?.Collider;
// Remove the outline from the previously looked-at item.
if (CurrentItem != null) CurrentItem.Mesh.Layers &= (uint)~RenderLayer.Outline;
if (CurrentItem != null) SetMeshLayerOutline(CurrentItem.Model, OutlineMode.Disable);
// If the ray hits anything and the object hit is an item, set it as current.
CurrentItem = interactable as Item;
// Add the outline to the currently looked-at item.
if (CurrentItem != null) CurrentItem.Mesh.Layers |= (uint)RenderLayer.Outline;
if (CurrentItem != null) SetMeshLayerOutline(CurrentItem.Model, OutlineMode.Enable);
}
}
@ -89,7 +107,11 @@ public partial class PickupController : Node3D
if (CurrentItem == null) return;
if (!IsInstanceValid(CurrentItem)) {
CurrentItem = null;
_placementPreview?.QueueFree();
if (_placementPreview != null) {
RemoveChild(_placementPreview);
_placementPreview.QueueFree();
_placementPreview = null;
}
}
}
@ -115,4 +137,16 @@ public partial class PickupController : Node3D
public Vector3 Position { get; } = (Vector3)dict["position"];
public Vector3 Normal { get; } = (Vector3)dict["normal"];
}
enum OutlineMode { Disable, Enable, Exclusive }
static void SetMeshLayerOutline(Node3D parent, OutlineMode mode)
{
var children = parent.FindChildren("*", "MeshInstance3D", owned: false);
foreach (var mesh in children.Cast<MeshInstance3D>())
switch (mode) {
case OutlineMode.Disable: mesh.Layers &= ~(uint)RenderLayer.Outline; break;
case OutlineMode.Enable: mesh.Layers |= (uint)RenderLayer.Outline; break;
case OutlineMode.Exclusive: mesh.Layers = (uint)RenderLayer.Outline; break;
}
}
}

@ -1115,6 +1115,6 @@ use_external_skeleton = true
external_skeleton = NodePath("../../../../../../../Model/Skeleton/Skeleton3D")
[node name="PickupController" type="Node3D" parent="." node_paths=PackedStringArray("Camera")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.35, -0.45)
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.4, -0.45)
script = ExtResource("2_ns2pe")
Camera = NodePath("../AnimationController/Root/LowerBody/UpperBody/Neck/Head/Camera")

@ -72,8 +72,11 @@ Size = Vector3i(2, 2, 4)
[node name="CollisionShape3D" type="CollisionShape3D" parent="Table/SmallBox"]
shape = SubResource("BoxShape3D_hkc0l")
[node name="MeshInstance3D" type="MeshInstance3D" parent="Table/SmallBox"]
[node name="Model" type="Node3D" parent="Table/SmallBox"]
[node name="MeshInstance3D" type="MeshInstance3D" parent="Table/SmallBox/Model"]
mesh = SubResource("BoxMesh_3qwx3")
skeleton = NodePath("../..")
[node name="SmallBox2" type="StaticBody3D" parent="Table"]
transform = Transform3D(-4.37114e-08, 0, -1, 0, 1, 0, 1, 0, -4.37114e-08, 0.251316, 1.06737, 0.127615)
@ -85,8 +88,11 @@ Size = Vector3i(2, 2, 4)
[node name="CollisionShape3D" type="CollisionShape3D" parent="Table/SmallBox2"]
shape = SubResource("BoxShape3D_hkc0l")
[node name="MeshInstance3D" type="MeshInstance3D" parent="Table/SmallBox2"]
[node name="Model" type="Node3D" parent="Table/SmallBox2"]
[node name="MeshInstance3D" type="MeshInstance3D" parent="Table/SmallBox2/Model"]
mesh = SubResource("BoxMesh_3qwx3")
skeleton = NodePath("../..")
[node name="Grid" type="Area3D" parent="Table"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0)

Loading…
Cancel
Save