Files
2026-07-21 08:56:10 +03:00

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
}