218 lines
7.2 KiB
C#
218 lines
7.2 KiB
C#
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
|
|
public class JointBlock : MonoBehaviour
|
|
{
|
|
[Header("Joint Configuration")]
|
|
[SerializeField] private JointBlockType jointType = JointBlockType.FixedPivot;
|
|
[SerializeField] private float jointLength = 1f;
|
|
|
|
[Header("Joint Ends")]
|
|
[SerializeField] private SocketPoint socketEnd1; // One end of the pivot
|
|
[SerializeField] private SocketPoint socketEnd2; // Other end of the pivot
|
|
|
|
[Header("Physics")]
|
|
[SerializeField] private bool usePhysics = true;
|
|
[SerializeField] private float jointBreakForce = Mathf.Infinity;
|
|
[SerializeField] private float jointBreakTorque = Mathf.Infinity;
|
|
|
|
public List<AttachableBlock> connectedBlocks = new List<AttachableBlock>();
|
|
private List<Joint> createdJoints = new List<Joint>();
|
|
private bool isPlaced = false;
|
|
private JointPlacementHandler jointPlacementHandler;
|
|
|
|
void Awake()
|
|
{
|
|
jointPlacementHandler = JointPlacementHandler.getInstance();
|
|
// Auto-find socket ends if not assigned
|
|
if (socketEnd1 == null || socketEnd2 == null)
|
|
{
|
|
SocketPoint[] sockets = GetComponentsInChildren<SocketPoint>();
|
|
if (sockets.Length >= 2)
|
|
{
|
|
socketEnd2 = sockets[0];
|
|
socketEnd1 = sockets[sockets.Length - 1];
|
|
}
|
|
}
|
|
|
|
// Configure socket types
|
|
if (socketEnd1 != null) socketEnd1.GetType(); // Should be JointEnd type
|
|
if (socketEnd2 != null) socketEnd2.GetType();
|
|
}
|
|
|
|
public bool TryPlaceJoint(List<SocketPoint> targetSockets, bool isGhost = false)
|
|
{
|
|
if (isPlaced)
|
|
{
|
|
Debug.LogWarning("Joint already placed!");
|
|
return false;
|
|
}
|
|
|
|
// Validate we have compatible sockets
|
|
if (targetSockets.Count < 1)
|
|
{
|
|
Debug.LogWarning("Need at least 1 target socket");
|
|
return false;
|
|
}
|
|
|
|
// For a pivot with 2 ends, we need 2 target sockets (one for each end)
|
|
if (socketEnd1 == null && socketEnd2 == null)
|
|
{
|
|
Debug.LogWarning("Pivot needs at least 2 target sockets");
|
|
return false;
|
|
}
|
|
|
|
// Snap position and rotation
|
|
AlignToSockets(targetSockets, isGhost);
|
|
|
|
// Create physics joints if needed
|
|
if (usePhysics && !isGhost)
|
|
{
|
|
CreatePhysicsJoints(targetSockets);
|
|
}
|
|
|
|
// Mark as placed and occupied
|
|
if (!isGhost)
|
|
{
|
|
isPlaced = true;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
private void AlignToSockets(List<SocketPoint> targetSockets, bool isGhost = false)
|
|
{
|
|
List<SocketPoint> alignedSockets = jointPlacementHandler.FindAllSocketsAlignedBetween(targetSockets[0], targetSockets[targetSockets.Count - 1]);
|
|
if (alignedSockets.Count > 0 && !isGhost)
|
|
{
|
|
CreatePhysicsJoints(alignedSockets);
|
|
// MarkSocketsOccupied(alignedSockets);
|
|
}
|
|
}
|
|
|
|
public void CreatePhysicsJoint(GameObject targetObj, SocketPoint socket)
|
|
{
|
|
AttachableBlock targetBlock = targetObj.GetComponent<AttachableBlock>();
|
|
if (connectedBlocks.Contains(targetBlock) || targetBlock == null) return;
|
|
|
|
Rigidbody jointRb = GetComponent<Rigidbody>();
|
|
if (jointRb == null) jointRb = gameObject.AddComponent<Rigidbody>();
|
|
|
|
Rigidbody targetRb = targetObj.GetComponent<Rigidbody>();
|
|
if (targetRb == null) targetRb = targetObj.AddComponent<Rigidbody>();
|
|
|
|
// Create appropriate joint type
|
|
Joint joint = CreateJointByType(targetRb, socket);
|
|
if (joint != null)
|
|
{
|
|
createdJoints.Add(joint);
|
|
connectedBlocks.Add(targetBlock);
|
|
targetBlock.RegisterJoint(this);
|
|
}
|
|
}
|
|
|
|
private void CreatePhysicsJoints(List<SocketPoint> targetSockets)
|
|
{
|
|
foreach (SocketPoint socket in targetSockets)
|
|
{
|
|
GameObject targetObj = socket.transform.root.gameObject;
|
|
CreatePhysicsJoint(targetObj, socket);
|
|
}
|
|
}
|
|
|
|
private Joint CreateJointByType(Rigidbody connectedBody, SocketPoint socket)
|
|
{
|
|
switch (jointType)
|
|
{
|
|
case JointBlockType.FixedPivot:
|
|
return CreateFixedJoint(connectedBody);
|
|
|
|
case JointBlockType.HingePivot:
|
|
return CreateHingeJoint(connectedBody, socket);
|
|
|
|
case JointBlockType.ConfigurablePivot:
|
|
return CreateConfigurableJoint(connectedBody, socket);
|
|
|
|
default:
|
|
return CreateFixedJoint(connectedBody);
|
|
}
|
|
}
|
|
|
|
private FixedJoint CreateFixedJoint(Rigidbody connectedBody)
|
|
{
|
|
FixedJoint joint = gameObject.AddComponent<FixedJoint>();
|
|
joint.connectedBody = connectedBody;
|
|
joint.breakForce = jointBreakForce;
|
|
joint.breakTorque = jointBreakTorque;
|
|
return joint;
|
|
}
|
|
|
|
private HingeJoint CreateHingeJoint(Rigidbody connectedBody, SocketPoint socket)
|
|
{
|
|
HingeJoint joint = gameObject.AddComponent<HingeJoint>();
|
|
joint.connectedBody = connectedBody;
|
|
joint.axis = transform.InverseTransformDirection(transform.forward); // Rotate around pivot axis
|
|
joint.anchor = transform.InverseTransformPoint(socket.GetTransform().position);
|
|
joint.breakForce = jointBreakForce;
|
|
joint.breakTorque = jointBreakTorque;
|
|
return joint;
|
|
}
|
|
|
|
private ConfigurableJoint CreateConfigurableJoint(Rigidbody connectedBody, SocketPoint socket)
|
|
{
|
|
ConfigurableJoint joint = gameObject.AddComponent<ConfigurableJoint>();
|
|
joint.connectedBody = connectedBody;
|
|
joint.anchor = transform.InverseTransformPoint(socket.GetTransform().position);
|
|
joint.breakForce = jointBreakForce;
|
|
joint.breakTorque = jointBreakTorque;
|
|
|
|
// Configure as needed (this is customizable)
|
|
joint.xMotion = ConfigurableJointMotion.Locked;
|
|
joint.yMotion = ConfigurableJointMotion.Locked;
|
|
joint.zMotion = ConfigurableJointMotion.Locked;
|
|
joint.angularXMotion = ConfigurableJointMotion.Free;
|
|
joint.angularYMotion = ConfigurableJointMotion.Locked;
|
|
joint.angularZMotion = ConfigurableJointMotion.Locked;
|
|
|
|
return joint;
|
|
}
|
|
|
|
private void MarkSocketsOccupied(List<SocketPoint> targetSockets)
|
|
{
|
|
foreach (SocketPoint socket in targetSockets)
|
|
{
|
|
socket.SetJointOccupied(this.gameObject);
|
|
}
|
|
}
|
|
|
|
public void RemoveJoint()
|
|
{
|
|
// Destroy all created joints
|
|
foreach (Joint joint in createdJoints)
|
|
{
|
|
if (joint != null) Destroy(joint);
|
|
}
|
|
createdJoints.Clear();
|
|
|
|
// Unregister from blocks
|
|
foreach (AttachableBlock block in connectedBlocks)
|
|
{
|
|
if (block != null) block.UnregisterJoint(this);
|
|
}
|
|
connectedBlocks.Clear();
|
|
|
|
isPlaced = false;
|
|
}
|
|
|
|
public JointBlockType GetJointType() => jointType;
|
|
public SocketPoint GetSocketEnd1() => socketEnd1;
|
|
public SocketPoint GetSocketEnd2() => socketEnd2;
|
|
public bool IsPlaced() => isPlaced;
|
|
}
|
|
|
|
public enum JointBlockType
|
|
{
|
|
FixedPivot, // Rigid connection (like a fixed axle)
|
|
HingePivot, // Rotating connection (like a door hinge)
|
|
ConfigurablePivot // Custom configurable joint
|
|
} |