protected void ReturnNode(Pool <ProjectileData> .Node node) { if (node.Active) { node.Item.TimeToLive = -1; if (node.Item.Outline.Item != null) { ProjectileOutlines.Return(node.Item.Outline.NodeIndex); node.Item.Outline.Item = null; } Projectiles.Return(node.NodeIndex); node.Active = false; } }
private void UpdateProjectiles(float tick) { ActiveProjectileCount = 0; ContactFilter2D contactFilter = new ContactFilter2D { layerMask = LayerMask, useTriggers = true, }; ProjectileManager projectileManager = ProjectileManager.Instance; //Update camera planes if needed if (CullProjectilesOutsideCameraBounds) { GeometryUtility.CalculateFrustumPlanes(Camera, Planes); } // loop through all active projectile data for (int i = 0; i < Projectiles.Nodes.Length; i++) { if (Projectiles.Nodes[i].Active) { Projectiles.Nodes[i].Item.TimeToLive -= tick; // Projectile is active if (Projectiles.Nodes[i].Item.TimeToLive > 0) { // apply acceleration Projectiles.Nodes[i].Item.Velocity *= (1 + Projectiles.Nodes[i].Item.Acceleration * tick); // apply gravity Projectiles.Nodes[i].Item.Velocity += Projectiles.Nodes[i].Item.Gravity * tick; // calculate where projectile will be at the end of this frame Vector2 deltaPosition = Projectiles.Nodes[i].Item.Velocity * tick; float distance = deltaPosition.magnitude; // If flag set - return projectiles that are no longer in view if (CullProjectilesOutsideCameraBounds) { Bounds bounds = new Bounds(Projectiles.Nodes[i].Item.Position, new Vector3(Projectiles.Nodes[i].Item.Scale, Projectiles.Nodes[i].Item.Scale, Projectiles.Nodes[i].Item.Scale)); if (!GeometryUtility.TestPlanesAABB(Planes, bounds)) { Projectiles.Nodes[i].Item.TimeToLive = -1; Projectiles.Return(Projectiles.Nodes[i].NodeIndex); } } int result = -1; if (CollisionDetection == CollisionDetectionType.Raycast) { result = Physics2D.Raycast(Projectiles.Nodes[i].Item.Position, deltaPosition, contactFilter, RaycastHitBuffer, distance); } else if (CollisionDetection == CollisionDetectionType.CircleCast) { result = Physics2D.CircleCast(Projectiles.Nodes[i].Item.Position, Projectiles.Nodes[i].Item.Scale / 2f, Projectiles.Nodes[i].Item.Velocity, contactFilter, RaycastHitBuffer, distance); if (result > 0 && RaycastHitBuffer[0].distance == 0) { result = -1; } } if (result > 0) { if (RaycastHitBuffer.Length == 1) { if (RaycastHitBuffer[0].collider.gameObject.tag == "NotForBullet" || RaycastHitBuffer[0].collider.gameObject.tag == shooterTag) { result = -1; } } } if (result > 0) { // Put whatever hit code you want here such as damage events if (RaycastHitBuffer.Length > 1) { Debug.LogWarning("[彈幕系統]超過一個Raycast目標!"); } if (RaycastHitBuffer[0].collider.GetComponent <LivingObject>()) { RaycastHitBuffer[0].collider.GetComponent <LivingObject>().GetHurt(atk); } // Collision was detected, should we bounce off or destroy the projectile? if (BounceOffSurfaces) { // rudementary bounce -- will work well on static surfaces Projectiles.Nodes[i].Item.Velocity = Vector2.Reflect(Projectiles.Nodes[i].Item.Velocity, RaycastHitBuffer[0].normal); // what fraction of the distance do we still have to move this frame? float leakedFraction = 1f - RaycastHitBuffer[0].distance / distance; deltaPosition = Projectiles.Nodes[i].Item.Velocity * tick * leakedFraction; Projectiles.Nodes[i].Item.Position = RaycastHitBuffer[0].centroid + deltaPosition; Projectiles.Nodes[i].Item.Color = Color.Evaluate(1 - Projectiles.Nodes[i].Item.TimeToLive / TimeToLive); // Absorbs energy from bounce Projectiles.Nodes[i].Item.Velocity = new Vector2(Mathf.Lerp(Projectiles.Nodes[i].Item.Velocity.x, 0, BounceAbsorbtion.x), Mathf.Lerp(Projectiles.Nodes[i].Item.Velocity.y, 0, BounceAbsorbtion.y)); projectileManager.UpdateBufferData(ActiveProjectileCount, ProjectileType, Projectiles.Nodes[i].Item); ActiveProjectileCount++; } else { Projectiles.Nodes[i].Item.TimeToLive = -1; Projectiles.Return(Projectiles.Nodes[i].NodeIndex); } } else { //No collision -move projectile Projectiles.Nodes[i].Item.Position += deltaPosition; Projectiles.Nodes[i].Item.Color = Color.Evaluate(1 - Projectiles.Nodes[i].Item.TimeToLive / TimeToLive); projectileManager.UpdateBufferData(ActiveProjectileCount, ProjectileType, Projectiles.Nodes[i].Item); ActiveProjectileCount++; } } else { // End of life - return to pool Projectiles.Return(Projectiles.Nodes[i].NodeIndex); } } } }