Jittering, environment issue, camera angle fixed
This commit is contained in:
parent
6a58849922
commit
00a3aa93fa
File diff suppressed because it is too large
Load Diff
@ -3,33 +3,44 @@ using System.Collections;
|
|||||||
|
|
||||||
public class CubeClash_Blueberry : MonoBehaviour
|
public class CubeClash_Blueberry : MonoBehaviour
|
||||||
{
|
{
|
||||||
|
[Header("Buff Settings")]
|
||||||
public float buffDuration = 5f;
|
public float buffDuration = 5f;
|
||||||
public float distanceBoost = 1.5f; // increase dash distance
|
|
||||||
public float speedBoost = 1.5f; // increase dash speed
|
[Tooltip("Multiply forward dash impulse (e.g., 1.4 = +40%).")]
|
||||||
public float cooldownReduction = 0.5f;
|
public float impulseMultiplier = 1.4f;
|
||||||
|
|
||||||
|
[Tooltip("Multiply bump cooldown (e.g., 0.7 = 30% faster).")]
|
||||||
|
public float cooldownMultiplier = 0.7f;
|
||||||
|
|
||||||
|
[Tooltip("Optional: increase momentum transfer (e.g., +0.2 adds on top).")]
|
||||||
|
public float extraMomentumTransfer = 0.2f;
|
||||||
|
|
||||||
private void OnTriggerEnter(Collider other)
|
private void OnTriggerEnter(Collider other)
|
||||||
{
|
{
|
||||||
CubeClash_ZibuController zibu = other.GetComponent<CubeClash_ZibuController>();
|
var zibu = other.GetComponent<CubeClash_ZibuController>();
|
||||||
if (zibu)
|
if (zibu == null) return;
|
||||||
{
|
|
||||||
StartCoroutine(ApplyBuff(zibu));
|
StartCoroutine(ApplyBuff(zibu));
|
||||||
Destroy(gameObject);
|
Destroy(gameObject);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private IEnumerator ApplyBuff(CubeClash_ZibuController zibu)
|
private IEnumerator ApplyBuff(CubeClash_ZibuController zibu)
|
||||||
{
|
{
|
||||||
// Apply buffs
|
// cache old values
|
||||||
zibu.bumpDistance *= distanceBoost;
|
float oldImpulse = zibu.dashImpulse;
|
||||||
zibu.bumpSpeed *= speedBoost;
|
float oldCooldown = zibu.bumpCooldown;
|
||||||
zibu.cooldown *= cooldownReduction;
|
float oldTransfer = zibu.momentumTransferScale;
|
||||||
|
|
||||||
|
// apply buffs
|
||||||
|
zibu.dashImpulse = oldImpulse * impulseMultiplier;
|
||||||
|
zibu.bumpCooldown = oldCooldown * cooldownMultiplier;
|
||||||
|
zibu.momentumTransferScale = oldTransfer + extraMomentumTransfer;
|
||||||
|
|
||||||
yield return new WaitForSeconds(buffDuration);
|
yield return new WaitForSeconds(buffDuration);
|
||||||
|
|
||||||
// Revert buffs
|
// revert
|
||||||
zibu.bumpDistance /= distanceBoost;
|
zibu.dashImpulse = oldImpulse;
|
||||||
zibu.bumpSpeed /= speedBoost;
|
zibu.bumpCooldown = oldCooldown;
|
||||||
zibu.cooldown /= cooldownReduction;
|
zibu.momentumTransferScale = oldTransfer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,13 @@ using System.Collections.Generic;
|
|||||||
public class CubeClash_ZibuAI : MonoBehaviour
|
public class CubeClash_ZibuAI : MonoBehaviour
|
||||||
{
|
{
|
||||||
[Header("AI Settings")]
|
[Header("AI Settings")]
|
||||||
public float moveSpeed = 3f;
|
[Tooltip("Each NPC rolls a speed in this range so they don't mirror each other.")]
|
||||||
|
public Vector2 moveSpeedRange = new Vector2(2.5f, 4.5f);
|
||||||
|
[Tooltip("Small extra randomization applied when retargeting to keep desynced.")]
|
||||||
|
public float retargetSpeedJitter = 0.3f;
|
||||||
|
|
||||||
|
[HideInInspector] public float moveSpeed; // current per-agent speed (rolled at runtime)
|
||||||
|
|
||||||
public float decisionInterval = 2f;
|
public float decisionInterval = 2f;
|
||||||
public float bumpRange = 2.5f;
|
public float bumpRange = 2.5f;
|
||||||
public float roamRadius = 5f;
|
public float roamRadius = 5f;
|
||||||
@ -28,19 +34,24 @@ public class CubeClash_ZibuAI : MonoBehaviour
|
|||||||
{
|
{
|
||||||
zibuController = GetComponent<CubeClash_ZibuController>();
|
zibuController = GetComponent<CubeClash_ZibuController>();
|
||||||
rb = GetComponent<Rigidbody>();
|
rb = GetComponent<Rigidbody>();
|
||||||
|
|
||||||
zibuController.isPlayerControlled = false;
|
zibuController.isPlayerControlled = false;
|
||||||
|
|
||||||
if (arenaCube != null)
|
if (arenaCube != null)
|
||||||
{
|
|
||||||
arenaBounds = new Bounds(arenaCube.position, arenaCube.localScale);
|
arenaBounds = new Bounds(arenaCube.position, arenaCube.localScale);
|
||||||
}
|
|
||||||
|
// Roll an initial per-agent speed
|
||||||
|
moveSpeed = Random.Range(moveSpeedRange.x, moveSpeedRange.y);
|
||||||
|
|
||||||
|
// Randomize starting decision timer so AIs don’t sync up
|
||||||
|
decisionTimer = Random.Range(0f, decisionInterval);
|
||||||
|
|
||||||
PickRoamTarget();
|
PickRoamTarget();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Update()
|
void Update()
|
||||||
{
|
{
|
||||||
|
if (zibuController.ControlLocked) return; // don't fight pushes
|
||||||
|
|
||||||
decisionTimer += Time.deltaTime;
|
decisionTimer += Time.deltaTime;
|
||||||
if (decisionTimer >= decisionInterval)
|
if (decisionTimer >= decisionInterval)
|
||||||
{
|
{
|
||||||
@ -50,38 +61,37 @@ public class CubeClash_ZibuAI : MonoBehaviour
|
|||||||
|
|
||||||
if (target != null)
|
if (target != null)
|
||||||
{
|
{
|
||||||
// move generally towards target, but still bump direction is forward
|
|
||||||
MoveTowards(target.transform.position);
|
MoveTowards(target.transform.position);
|
||||||
TryBumpTarget();
|
TryBumpTarget();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
MoveTowards(roamTarget);
|
MoveTowards(roamTarget);
|
||||||
|
|
||||||
if (Vector3.Distance(transform.position, roamTarget) < 1f)
|
if (Vector3.Distance(transform.position, roamTarget) < 1f)
|
||||||
{
|
|
||||||
PickRoamTarget();
|
PickRoamTarget();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PickTargetOrRoam()
|
void PickTargetOrRoam()
|
||||||
{
|
{
|
||||||
List<CubeClash_ZibuController> allZibus = CubeClash_ZibuController.AllZibus;
|
List<CubeClash_ZibuController> allZibus = CubeClash_ZibuController.AllZibus;
|
||||||
|
|
||||||
if (allZibus.Count > 1)
|
if (allZibus.Count > 1)
|
||||||
{
|
{
|
||||||
List<CubeClash_ZibuController> candidates = new List<CubeClash_ZibuController>();
|
List<CubeClash_ZibuController> candidates = new List<CubeClash_ZibuController>();
|
||||||
foreach (var z in allZibus)
|
foreach (var z in allZibus)
|
||||||
{
|
if (z != zibuController)
|
||||||
if (z != zibuController && z != lastTarget)
|
|
||||||
candidates.Add(z);
|
candidates.Add(z);
|
||||||
}
|
|
||||||
|
|
||||||
if (candidates.Count > 0)
|
if (candidates.Count > 0)
|
||||||
{
|
{
|
||||||
|
if (candidates.Count > 1 && lastTarget != null)
|
||||||
|
candidates.Remove(lastTarget);
|
||||||
|
|
||||||
int index = Random.Range(0, candidates.Count);
|
int index = Random.Range(0, candidates.Count);
|
||||||
target = candidates[index];
|
target = candidates[index];
|
||||||
|
|
||||||
|
// Tiny re-roll of speed to avoid symmetric face-offs
|
||||||
|
ReRollSpeedSlightly();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -89,18 +99,18 @@ public class CubeClash_ZibuAI : MonoBehaviour
|
|||||||
target = null;
|
target = null;
|
||||||
PickRoamTarget();
|
PickRoamTarget();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MoveTowards(Vector3 destination)
|
void MoveTowards(Vector3 destination)
|
||||||
{
|
{
|
||||||
|
if (zibuController.ControlLocked) return; // skip if stunned
|
||||||
|
|
||||||
Vector3 dir = (destination - transform.position).normalized;
|
Vector3 dir = (destination - transform.position).normalized;
|
||||||
Vector3 move = new Vector3(dir.x, 0, dir.z) * moveSpeed;
|
Vector3 move = new Vector3(dir.x, 0, dir.z) * moveSpeed;
|
||||||
rb.velocity = new Vector3(move.x, rb.velocity.y, move.z);
|
rb.velocity = new Vector3(move.x, rb.velocity.y, move.z);
|
||||||
|
|
||||||
if (dir.magnitude > 0.1f)
|
if (dir.magnitude > 0.1f)
|
||||||
{
|
{
|
||||||
// flatten direction on Y axis
|
|
||||||
dir.y = 0;
|
dir.y = 0;
|
||||||
|
|
||||||
// smooth rotate only around Y
|
|
||||||
Quaternion targetRot = Quaternion.LookRotation(dir, Vector3.up);
|
Quaternion targetRot = Quaternion.LookRotation(dir, Vector3.up);
|
||||||
transform.rotation = Quaternion.Slerp(transform.rotation, targetRot, Time.deltaTime * 5f);
|
transform.rotation = Quaternion.Slerp(transform.rotation, targetRot, Time.deltaTime * 5f);
|
||||||
}
|
}
|
||||||
@ -108,17 +118,23 @@ public class CubeClash_ZibuAI : MonoBehaviour
|
|||||||
|
|
||||||
void PickRoamTarget()
|
void PickRoamTarget()
|
||||||
{
|
{
|
||||||
Vector3 randomOffset = new Vector3(Random.Range(-roamRadius, roamRadius), 0, Random.Range(-roamRadius, roamRadius));
|
// Pick anywhere in arena to spread agents out
|
||||||
roamTarget = transform.position + randomOffset;
|
|
||||||
|
|
||||||
if (arenaCube != null)
|
if (arenaCube != null)
|
||||||
{
|
{
|
||||||
arenaBounds = new Bounds(arenaCube.position, arenaCube.localScale);
|
arenaBounds = new Bounds(arenaCube.position, arenaCube.localScale);
|
||||||
|
float x = Random.Range(arenaBounds.min.x + 1f, arenaBounds.max.x - 1f);
|
||||||
roamTarget.x = Mathf.Clamp(roamTarget.x, arenaBounds.min.x + 1f, arenaBounds.max.x - 1f);
|
float z = Random.Range(arenaBounds.min.z + 1f, arenaBounds.max.z - 1f);
|
||||||
roamTarget.z = Mathf.Clamp(roamTarget.z, arenaBounds.min.z + 1f, arenaBounds.max.z - 1f);
|
roamTarget = new Vector3(x, transform.position.y, z);
|
||||||
roamTarget.y = transform.position.y;
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Fallback: local random offset if no arena assigned
|
||||||
|
Vector3 randomOffset = new Vector3(Random.Range(-roamRadius, roamRadius), 0, Random.Range(-roamRadius, roamRadius));
|
||||||
|
roamTarget = transform.position + randomOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Slight re-roll on roam choose too
|
||||||
|
ReRollSpeedSlightly();
|
||||||
}
|
}
|
||||||
|
|
||||||
void TryBumpTarget()
|
void TryBumpTarget()
|
||||||
@ -130,11 +146,8 @@ public class CubeClash_ZibuAI : MonoBehaviour
|
|||||||
{
|
{
|
||||||
Vector3 toTarget = (target.transform.position - transform.position).normalized;
|
Vector3 toTarget = (target.transform.position - transform.position).normalized;
|
||||||
float dot = Vector3.Dot(transform.forward, toTarget);
|
float dot = Vector3.Dot(transform.forward, toTarget);
|
||||||
|
|
||||||
if (dot > 0.7f)
|
if (dot > 0.7f)
|
||||||
{
|
|
||||||
StartCoroutine(BumpWithDelay());
|
StartCoroutine(BumpWithDelay());
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -142,16 +155,26 @@ public class CubeClash_ZibuAI : MonoBehaviour
|
|||||||
{
|
{
|
||||||
isBumpCooling = true;
|
isBumpCooling = true;
|
||||||
|
|
||||||
yield return new WaitForSeconds(Random.Range(0.1f, 0.4f));
|
// Extra jitter before bump to desync
|
||||||
|
yield return new WaitForSeconds(Random.Range(0.15f, 0.6f));
|
||||||
|
|
||||||
zibuController.PerformBump(transform.forward);
|
if (!zibuController.ControlLocked)
|
||||||
|
zibuController.PerformBump(transform.forward);
|
||||||
|
|
||||||
// after bump: forget target & roam somewhere else
|
|
||||||
lastTarget = target;
|
lastTarget = target;
|
||||||
target = null;
|
target = null;
|
||||||
PickRoamTarget();
|
PickRoamTarget();
|
||||||
|
|
||||||
yield return new WaitForSeconds(Random.Range(1f, 2f));
|
// Randomized cooldown so they don't re-sync
|
||||||
|
yield return new WaitForSeconds(Random.Range(1.2f, 2.5f));
|
||||||
isBumpCooling = false;
|
isBumpCooling = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --- Helpers ---
|
||||||
|
void ReRollSpeedSlightly()
|
||||||
|
{
|
||||||
|
float baseRoll = Random.Range(moveSpeedRange.x, moveSpeedRange.y);
|
||||||
|
float jitter = Random.Range(-retargetSpeedJitter, retargetSpeedJitter);
|
||||||
|
moveSpeed = Mathf.Clamp(baseRoll + jitter, moveSpeedRange.x, moveSpeedRange.y);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,31 +9,50 @@ public class CubeClash_ZibuController : MonoBehaviour
|
|||||||
|
|
||||||
[Header("Control")]
|
[Header("Control")]
|
||||||
public bool isPlayerControlled = true;
|
public bool isPlayerControlled = true;
|
||||||
|
|
||||||
[Header("Movement Settings")]
|
|
||||||
public float moveSpeed = 5f;
|
public float moveSpeed = 5f;
|
||||||
public Joystick joystick;
|
public Joystick joystick;
|
||||||
|
|
||||||
[Header("Bump Settings")]
|
[Header("Bump (Physics)")]
|
||||||
public float bumpDistance = 3f;
|
[Tooltip("Impulse strength added in forward direction when bump starts.")]
|
||||||
public float bumpSpeed = 20f;
|
public float dashImpulse = 12f;
|
||||||
public float returnSpeed = 10f;
|
|
||||||
public float cooldown = 2f;
|
[Tooltip("How long collisions count as 'bumping' (hit-active window).")]
|
||||||
public float knockbackForce = 15f;
|
public float hitWindow = 0.22f;
|
||||||
|
|
||||||
|
[Tooltip("Cooldown after bump sequence finishes.")]
|
||||||
|
public float bumpCooldown = 1.0f;
|
||||||
|
|
||||||
|
[Header("Momentum Transfer")]
|
||||||
|
[Tooltip("Scales impulse delivered to the other Zibu on hit.")]
|
||||||
|
public float momentumTransferScale = 0.9f;
|
||||||
|
|
||||||
|
[Tooltip("Extra kick added to the victim on hit.")]
|
||||||
|
public float bonusKnockImpulse = 2f;
|
||||||
|
|
||||||
|
[Tooltip("How much of our forward momentum we lose on hit (0..1).")]
|
||||||
|
public float selfMomentumLoss = 0.25f;
|
||||||
|
|
||||||
|
[Header("Hit Reaction")]
|
||||||
|
[Tooltip("Time (sec) the victim loses control after being pushed.")]
|
||||||
|
public float pushStunTime = 0.25f;
|
||||||
|
|
||||||
[Header("Animation")]
|
[Header("Animation")]
|
||||||
public Animator animator; // assign in Inspector
|
public Animator animator; // optional
|
||||||
|
|
||||||
|
// --- runtime
|
||||||
private Rigidbody rb;
|
private Rigidbody rb;
|
||||||
private bool canBump = true;
|
private bool canBump = true;
|
||||||
[HideInInspector] public bool isBumping = false;
|
|
||||||
|
[HideInInspector] public bool isBumping = false; // only during dash + hit window
|
||||||
|
[HideInInspector] public bool isHitActive = false;
|
||||||
|
|
||||||
|
private float stunUntilTime = -999f;
|
||||||
|
public bool ControlLocked => isBumping || Time.time < stunUntilTime;
|
||||||
|
|
||||||
void OnEnable()
|
void OnEnable()
|
||||||
{
|
{
|
||||||
if (!AllZibus.Contains(this))
|
if (!AllZibus.Contains(this)) AllZibus.Add(this);
|
||||||
AllZibus.Add(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void OnDisable()
|
void OnDisable()
|
||||||
{
|
{
|
||||||
AllZibus.Remove(this);
|
AllZibus.Remove(this);
|
||||||
@ -43,105 +62,151 @@ public class CubeClash_ZibuController : MonoBehaviour
|
|||||||
{
|
{
|
||||||
rb = GetComponent<Rigidbody>();
|
rb = GetComponent<Rigidbody>();
|
||||||
if (animator == null) animator = GetComponentInChildren<Animator>();
|
if (animator == null) animator = GetComponentInChildren<Animator>();
|
||||||
|
|
||||||
|
// Physics stability
|
||||||
|
rb.collisionDetectionMode = CollisionDetectionMode.Continuous;
|
||||||
|
rb.interpolation = RigidbodyInterpolation.Interpolate;
|
||||||
|
rb.solverIterations = Mathf.Max(rb.solverIterations, 12);
|
||||||
|
rb.solverVelocityIterations = Mathf.Max(rb.solverVelocityIterations, 12);
|
||||||
|
|
||||||
|
// freeze tilt rotations
|
||||||
|
rb.constraints |= RigidbodyConstraints.FreezeRotationX | RigidbodyConstraints.FreezeRotationZ;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Update()
|
void Update()
|
||||||
{
|
{
|
||||||
if (isPlayerControlled && !isBumping)
|
if (isPlayerControlled && !ControlLocked)
|
||||||
{
|
|
||||||
HandleMovement();
|
HandleMovement();
|
||||||
}
|
|
||||||
|
|
||||||
UpdateAnimations();
|
UpdateAnimations();
|
||||||
|
FaceVelocity(); // always face movement
|
||||||
}
|
}
|
||||||
|
|
||||||
private void HandleMovement()
|
private void HandleMovement()
|
||||||
{
|
{
|
||||||
if (joystick != null)
|
if (joystick == null) return;
|
||||||
{
|
|
||||||
Vector3 move = new Vector3(joystick.Horizontal, 0, joystick.Vertical);
|
|
||||||
if (move.magnitude > 0.1f)
|
|
||||||
{
|
|
||||||
Vector3 targetVelocity = move.normalized * moveSpeed;
|
|
||||||
rb.velocity = new Vector3(targetVelocity.x, rb.velocity.y, targetVelocity.z);
|
|
||||||
|
|
||||||
// face only in Y-axis
|
Vector3 move = new Vector3(joystick.Horizontal, 0, joystick.Vertical);
|
||||||
Quaternion targetRot = Quaternion.LookRotation(new Vector3(move.x, 0, move.z));
|
if (move.sqrMagnitude > 0.01f)
|
||||||
transform.rotation = Quaternion.Slerp(transform.rotation, targetRot, Time.deltaTime * 10f);
|
{
|
||||||
}
|
Vector3 targetVel = move.normalized * moveSpeed;
|
||||||
else
|
rb.velocity = new Vector3(targetVel.x, rb.velocity.y, targetVel.z);
|
||||||
{
|
|
||||||
rb.velocity = new Vector3(0, rb.velocity.y, 0);
|
// smooth yaw-only rotation
|
||||||
}
|
Quaternion targetRot = Quaternion.LookRotation(new Vector3(move.x, 0, move.z), Vector3.up);
|
||||||
|
transform.rotation = Quaternion.Slerp(transform.rotation, targetRot, Time.deltaTime * 10f);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rb.velocity = new Vector3(0f, rb.velocity.y, 0f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void FaceVelocity()
|
||||||
|
{
|
||||||
|
Vector3 v = rb.velocity;
|
||||||
|
v.y = 0;
|
||||||
|
if (v.sqrMagnitude > 0.05f) // ignore tiny jitter
|
||||||
|
{
|
||||||
|
Quaternion targetRot = Quaternion.LookRotation(v.normalized, Vector3.up);
|
||||||
|
transform.rotation = Quaternion.Slerp(transform.rotation, targetRot, Time.deltaTime * 10f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateAnimations()
|
private void UpdateAnimations()
|
||||||
{
|
{
|
||||||
if (animator != null)
|
if (!animator) return;
|
||||||
{
|
Vector3 horiz = new Vector3(rb.velocity.x, 0, rb.velocity.z);
|
||||||
// Use velocity magnitude (XZ only) to set "Speed"
|
animator.SetFloat("Speed", horiz.magnitude);
|
||||||
Vector3 horizontalVel = new Vector3(rb.velocity.x, 0, rb.velocity.z);
|
|
||||||
float speed = horizontalVel.magnitude;
|
|
||||||
|
|
||||||
animator.SetFloat("Speed", speed);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Player UI
|
||||||
public void PerformBump()
|
public void PerformBump()
|
||||||
{
|
{
|
||||||
if (!canBump || isBumping) return;
|
if (!canBump || ControlLocked) return;
|
||||||
StartCoroutine(BumpRoutine(transform.forward));
|
StartCoroutine(BumpSequence(transform.forward));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AI
|
||||||
public void PerformBump(Vector3 direction)
|
public void PerformBump(Vector3 direction)
|
||||||
{
|
{
|
||||||
if (!canBump || isBumping) return;
|
if (!canBump || ControlLocked) return;
|
||||||
StartCoroutine(BumpRoutine(direction));
|
StartCoroutine(BumpSequence(direction));
|
||||||
}
|
}
|
||||||
|
|
||||||
private IEnumerator BumpRoutine(Vector3 direction)
|
private IEnumerator BumpSequence(Vector3 direction)
|
||||||
{
|
{
|
||||||
canBump = false;
|
canBump = false;
|
||||||
isBumping = true;
|
isBumping = true;
|
||||||
|
|
||||||
Vector3 startPos = transform.position;
|
// Clean start (optional): limit drift so dash reads crisp
|
||||||
Vector3 targetPos = startPos + direction.normalized * bumpDistance;
|
Vector3 horiz = new Vector3(rb.velocity.x, 0f, rb.velocity.z);
|
||||||
|
rb.velocity = new Vector3(0f, rb.velocity.y, 0f) + horiz * 0.25f;
|
||||||
|
|
||||||
float t = 0f;
|
// --- Dash forward impulse (pure physics) ---
|
||||||
while (t < 1f)
|
Vector3 fwd = new Vector3(direction.x, 0, direction.z);
|
||||||
{
|
if (fwd.sqrMagnitude < 0.001f) fwd = transform.forward;
|
||||||
t += Time.deltaTime * bumpSpeed;
|
fwd.Normalize();
|
||||||
rb.MovePosition(Vector3.Lerp(startPos, targetPos, t));
|
rb.AddForce(fwd * dashImpulse, ForceMode.Impulse);
|
||||||
yield return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
t = 0f;
|
// Collisions are “hot” only during this window
|
||||||
while (t < 1f)
|
isHitActive = true;
|
||||||
{
|
yield return new WaitForSeconds(hitWindow);
|
||||||
t += Time.deltaTime * returnSpeed;
|
isHitActive = false;
|
||||||
rb.MovePosition(Vector3.Lerp(targetPos, startPos, t));
|
|
||||||
yield return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// End bump; control resumes, velocity continues naturally
|
||||||
isBumping = false;
|
isBumping = false;
|
||||||
|
|
||||||
yield return new WaitForSeconds(cooldown);
|
// Cooldown before next bump
|
||||||
|
yield return new WaitForSeconds(bumpCooldown);
|
||||||
canBump = true;
|
canBump = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnCollisionEnter(Collision collision)
|
// External: short lock so physics can show the shove
|
||||||
|
public void ApplyPushStun(float seconds)
|
||||||
{
|
{
|
||||||
CubeClash_ZibuController other = collision.gameObject.GetComponent<CubeClash_ZibuController>();
|
float until = Time.time + Mathf.Max(0f, seconds);
|
||||||
if (other != null)
|
if (until > stunUntilTime) stunUntilTime = until;
|
||||||
{
|
}
|
||||||
if (isBumping && other.isBumping) return;
|
|
||||||
|
|
||||||
if (isBumping && !other.isBumping && other.rb != null)
|
private void OnCollisionEnter(Collision c) => HandleBumpCollision(c);
|
||||||
{
|
private void OnCollisionStay(Collision c) => HandleBumpCollision(c);
|
||||||
Vector3 pushDir = transform.forward.normalized;
|
|
||||||
other.rb.AddForce(pushDir * knockbackForce, ForceMode.Impulse);
|
private void HandleBumpCollision(Collision c)
|
||||||
}
|
{
|
||||||
|
if (!isHitActive) return;
|
||||||
|
|
||||||
|
var other = c.collider.GetComponent<CubeClash_ZibuController>();
|
||||||
|
if (other == null) return;
|
||||||
|
|
||||||
|
// If both are in hit window, let raw physics resolve
|
||||||
|
if (other.isHitActive) return;
|
||||||
|
|
||||||
|
var otherRb = other.GetComponent<Rigidbody>();
|
||||||
|
if (otherRb == null) return;
|
||||||
|
|
||||||
|
// Push direction = our forward
|
||||||
|
Vector3 pushDir = transform.forward;
|
||||||
|
pushDir.y = 0;
|
||||||
|
pushDir.Normalize();
|
||||||
|
|
||||||
|
Vector3 relVel = rb.velocity - otherRb.velocity;
|
||||||
|
float approach = Vector3.Dot(relVel, pushDir);
|
||||||
|
if (approach <= 0f) return;
|
||||||
|
|
||||||
|
float impulseMag = (rb.mass * approach * momentumTransferScale) + bonusKnockImpulse;
|
||||||
|
Vector3 impulse = pushDir * impulseMag;
|
||||||
|
|
||||||
|
// pure shove, no torque
|
||||||
|
otherRb.AddForce(impulse, ForceMode.Impulse);
|
||||||
|
|
||||||
|
// Lock their movement briefly so they don't cancel the shove
|
||||||
|
other.ApplyPushStun(pushStunTime);
|
||||||
|
|
||||||
|
if (selfMomentumLoss > 0f)
|
||||||
|
{
|
||||||
|
Vector3 ourForward = Vector3.Project(rb.velocity, pushDir);
|
||||||
|
rb.AddForce(-ourForward * selfMomentumLoss * rb.mass, ForceMode.Impulse);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user