Initial commit
This commit is contained in:
@@ -0,0 +1,218 @@
|
||||
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
|
||||
}
|
||||
Reference in New Issue
Block a user