/// <summary> /// Advance the life cycles of all clouds and possibly add a new cloud. /// Rotate the given angle by 45° before creating clouds. /// </summary> /// <param name="dt">how far to advance the lifecycle</param> /// <param name="currentPosition">the position at which to add a possible new cloud</param> /// <param name="decayOnly">if true, no new clouds are added (i.e. this just advances the cloud life cycles)</param> internal override void Advance(float dt, CCPoint currentPosition, float currentCCRotation, bool decayOnly = false) { // advance the lifecycle of each cloud foreach (var cloud in clouds) { cloud.LifeTime += dt; cloud.MatchLifeCycle(); } CCPoint pos; if (AddRing) // add a special ring cloud, only one { pos = CCPoint.RotateByAngle(RelativePosition, CCPoint.Zero, Constants.CCDegreesToMathRadians(currentCCRotation)); pos += currentPosition; AddRing = false; clouds.Add(new RingCloud(pos, 0, CCColor4B.White, DrawLow, 100f, 1f)); } // check if it is time for a new cloud float timePlusDt = TimeSinceLastCloud + dt; if (AutoAddClouds && timePlusDt > CloudDelay) { // reset the timer to 0 + overshoot TimeSinceLastCloud = timePlusDt % CloudDelay; // add a new cloud if (!decayOnly) { // calculate the total position based on the saved relative position, the currentPosition and the current CCrotation pos = CCPoint.RotateByAngle(RelativePosition, CCPoint.Zero, Constants.CCDegreesToMathRadians(currentCCRotation)); pos += currentPosition; // move the spawn of the cloud a little in a random direction for a nice little bonus effect // also make the cloud size a bit random var cloud = new Cloud(Constants.RandomPointNear(pos, ReferenceSize), currentCCRotation + 45f, CloudColor, DrawLow, ReferenceSize + (float)(new Random()).NextDouble() * ReferenceSize * 2, CloudLifeTime); //var cloud = new DamageCloud(Constants.RandomPointNear(pos, ReferenceSize), currentCCRotation+45f, CloudColor, ReferenceSize + (float)(new Random()).NextDouble() * ReferenceSize, CloudLifeTime); //cloud.FireColor = FireColor; clouds.Add(cloud); } } else { // let the timer run TimeSinceLastCloud = timePlusDt; } // remove all clouds that have gone beyond their lifecycle for (int i = 0; i < clouds.Count; i++) { if (clouds[i].LifeTime > clouds[i].TotalLifeTime) { clouds.RemoveAt(i--); } } }
private void WasteCurrentWreck() { GUILayer.AddScreenShake(50f, 50f); var mAircraft = MiddleAircraft; float startP = GetWreckPercentile(mAircraft); var percentLabel = GetPercentLabel(mAircraft); const float DURATION = 1.5f; AddAction(new CCSequence(new CCEaseIn(new CCCallFiniteTimeFunc(DURATION, (progress, duration) => { SetWreckPercentile(mAircraft, startP * (1 - progress)); }), 4f), new CCCallFunc(() => { EndRepair(true); }))); // let the aircraft visually crumble to pieces var totalParts = mAircraft.TotalParts; var currentConf = new Dictionary <Part, Tuple <CCPoint, float, float> >(); foreach (var part in totalParts) { currentConf[part] = new Tuple <CCPoint, float, float>(part.PositionWorldspace, part.MyRotation, part.GetTotalScale()); } mAircraft.Body.Disassemble(); mAircraft.Body = null; var rng = new Random(); foreach (var part in totalParts) { AddChild(part, 99999); // place them so that the position is (visually) the same var config = currentConf[part]; part.Position = config.Item1; part.Rotation = config.Item2; part.Scale = config.Item3; // add an action to let it spin around a bit randomly part.AddAction(new CCSpawn(new CCEaseOut(new CCMoveTo(DURATION * 2, Constants.RandomPointNear(part.Position, 600f, rng)), 2f), new CCFadeOut(DURATION * 2))); part.AddAction(new CCRepeatForever(new CCRotateBy(1f, (rng.NextBoolean() ? -1 : 1) * (50f + (float)rng.NextDouble() * 100f)))); part.AddAction(new CCSequence(new CCDelayTime(DURATION * 2 + 0.1f), new CCRemoveSelf())); } }
internal void ReactToHit(float damage, CCPoint collisionPos) { const float MAX_DISTANCE_FROM_COLLISION = 200f; float maxDistanceFromCollision = ((ContentSize.Width + ContentSize.Height) / 4) * GetTotalScale(); if (maxDistanceFromCollision > MAX_DISTANCE_FROM_COLLISION) { maxDistanceFromCollision = MAX_DISTANCE_FROM_COLLISION; } // generate a random point near the collisionPos // and show an effect there Random rng = new Random(); for (int tries = 0; tries < 5; tries++) { CCPoint randomPoint = Constants.RandomPointNear(collisionPos, maxDistanceFromCollision, rng); //CCPoint randomPoint = collisionPos; if (Collisions.CollidePositionPolygon(randomPoint, this) || tries == 4) // check whether the random point is inside the collision polygon { CCPoint relativePosition = randomPoint - PositionWorldspace; relativePosition = CCPoint.RotateByAngle(relativePosition, CCPoint.Zero, -Constants.CCDegreesToMathRadians(TotalRotation)); // react differently depending upon how damaged you now are float refSize = DamageToReferenceSize(damage); var damageTail = new DamageCloudTailNode(refSize, relativePosition); if (Aircraft.SelectedPower != PowerUp.PowerType.SHIELD) { if (Health / MaxHealth > 0.7f) { damageTail.AutoAddClouds = false; } if (Health / MaxHealth < 0.5f) { var planeColor = ((PlayLayer)Layer).CurrentPlaneColor; var baseFlameColor = new CCColor4B((byte)rng.Next(0, 256), 0, 0); var h = (new SKColor(planeColor.R, planeColor.G, planeColor.B)).Hue; damageTail.CloudColor = Constants.MoveHue(baseFlameColor, h); } damageTail.CloudLifeTime += (refSize - 8f) * 0.1f; } else { damageTail.AutoAddClouds = false; } DamageCloudTailNodes.Add(damageTail); break; } } // shake! if (Aircraft.ControlledByPlayer && Aircraft.SelectedPower != PowerUp.PowerType.SHIELD) { // the shake amount depends on the damage, but mostly on how the damage relates to the max health float baseRefSize = DamageToReferenceSize(damage, 10f); float specialBonus = 0f; float healthFactor = damage / MaxHealth; if (healthFactor > 1) { healthFactor = 1; } if (Health <= 0) { baseRefSize *= (1 + TotalParts.Count()) * 0.8f; specialBonus += (float)Math.Sqrt(TotalMaxHealth) * 3; } float shakeAmount = baseRefSize * 10 * healthFactor + specialBonus; ((PlayLayer)Layer).AddScreenShake(shakeAmount, shakeAmount); } }