// https://forum.unity.com/threads/clean-est-way-to-find-nearest-object-of-many-c.44315/ ObjRing FindClosestTarget(bool inital = false, float distanceLimit = 4F) { ObjRing bestTarget = null; float closestDistanceSqr = Mathf.Infinity; foreach (ObjRing target in GameObject.FindObjectsOfType <ObjRing>()) { ObjRing potentialTarget = target; if (!potentialTarget.gameObject.activeSelf) { continue; } if (!target.enabled) { continue; } if (target.collected) { continue; } if (target.falling) { continue; } float angleDiff = Mathf.Abs(Mathf.DeltaAngle( character.position.AngleTowards(potentialTarget.transform.position), character.forwardAngle )); if ((angleDiff > 45) && (angleDiff < 135)) { continue; } else if (inital) { if ((angleDiff > 45) && character.facingRight) { continue; } else if ((angleDiff < 135) && !character.facingRight) { continue; } } Vector3 directionToTarget = potentialTarget.transform.position - character.position; float dSqrToTarget = directionToTarget.sqrMagnitude; if (!(dSqrToTarget < closestDistanceSqr)) { continue; } closestDistanceSqr = dSqrToTarget; bestTarget = potentialTarget; } if (closestDistanceSqr > distanceLimit) { return(null); } return(bestTarget); }
// Shamelessly taken line-for-line from https://info.sonicretro.org/SPG:Ring_Loss public static void ExplodeRings(Vector2 origin, int count) { count = Mathf.Min(count, 256); float angle = 101.25F + 90F; // assuming 0=right, 90=up, 180=left, 270=down bool flipHSpeed = false; float speed = 0F; for (int t = 0; t < count; t++) { if (t % 16 == 0) { switch (speed) { case 0F: speed = 4F; break; case 4F: speed = 2F; break; case 2F: speed = 6F; break; default: speed += 2F; break; } angle = 101.25F + 90F; // and reset the angle } // create a bouncing ring object ObjRing ring = Instantiate( Constants.Get <GameObject>("prefabRing"), origin, Quaternion.identity ).GetComponent <ObjRing>(); ring.InitReferences(); ring.falling = true; // set the ring's vertical speed to sine(angle)*speed // set the ring's horizontal speed to -cosine(angle)*speed ring.initialVelocity = new Vector2( Mathf.Sin(angle * Mathf.Deg2Rad) * speed, -Mathf.Cos(angle * Mathf.Deg2Rad) * speed ) * Utils.physicsScale; if (flipHSpeed) { // multiply the ring's horizontal speed by -1 ring.initialVelocity.x *= -1; // increase angle by 22.5 angle += 22.5F; } flipHSpeed = !flipHSpeed; // if n is false, n becomes true and vice versa } }
// 3D-Ready: NO public void Hurt(bool moveLeft = true, bool spikes = false) { if (isInvulnerable) { return; } if (shield != null) { SFX.Play(audioSource, "sfxHurt"); RemoveShield(); } else if (rings == 0) { if (spikes) { SFX.Play(audioSource, "sfxDieSpikes"); } else { SFX.Play(audioSource, "sfxDie"); } stateCurrent = "dying"; return; } else { ObjRing.ExplodeRings(transform.position, Mathf.Min(rings, 32)); rings = 0; SFX.Play(audioSource, "sfxHurtRings"); } stateCurrent = "hurt"; velocity = new Vector3( // TODO: 3D 2 * (moveLeft ? -1 : 1) * physicsScale, 4 * physicsScale, velocity.z ); position += velocity / 30F; // HACK }
public override void Update(float deltaTime) { if (character.stateCurrent != "lightDash") { if (!character.input.GetButtonDownPreventRepeat("Primary")) { return; } target = FindClosestTarget(true); if (target != null) { character.stateCurrent = "lightDash"; } return; } ; if ((target == null) || (target.collected)) { target = FindClosestTarget(); if (target != null) { character.stateCurrent = "lightDash"; } else { character.velocity = (character.position - positionPrev) * (60F * 0.75F); if (character.velocity.magnitude > character.stats.Get("terminalSpeed")) { character.velocity = character.stats.Get("terminalSpeed") * character.velocity.normalized; } character.stateCurrent = "air"; character.AnimatorPlay("Fast"); } } else { positionPrev = character.position; character.forwardAngle = character.position.AngleTowards(target.transform.position); if (character.flipX) { character.forwardAngle += 180F; } Vector3 newPos = Vector3.MoveTowards( character.position, target.transform.position, character.stats.Get("lightDashSpeed") * deltaTime * 2 ); newPos.z = character.position.z; character.position = newPos; character.spriteContainer.transform.eulerAngles = character.GetSpriteRotation(deltaTime); failsafeTimer -= deltaTime; if (failsafeTimer <= 0) { character.stateCurrent = "rollingAir"; } } }