public static void ClientAddHitSparks( IReadOnlyWeaponHitSparksPreset hitSparksPreset, WeaponHitData hitData, IWorldObject hitWorldObject, IProtoWorldObject protoWorldObject, Vector2D worldObjectPosition, int projectilesCount, ObjectMaterial objectMaterial, bool randomizeHitPointOffset, bool randomRotation, DrawOrder drawOrder, double scale = 1.0, double animationFrameDuration = 2 / 60.0) { var sceneObject = Api.Client.Scene.CreateSceneObject("Temp_HitSparks"); sceneObject.Position = worldObjectPosition; var hitPoint = hitData.HitPoint.ToVector2D(); if (!hitData.IsCliffsHit) { // move hitpoint a bit closer to the center of the object hitPoint = WeaponSystem.SharedOffsetHitWorldPositionCloserToObjectCenter( hitWorldObject, protoWorldObject, hitPoint, isRangedWeapon: randomizeHitPointOffset); } var sparksEntry = hitSparksPreset.GetForMaterial(objectMaterial); if (projectilesCount == 1 && randomizeHitPointOffset && sparksEntry.AllowRandomizedHitPointOffset) { // randomize hitpoint a bit by adding a little random offset var maxOffsetDistance = 0.2; var range = maxOffsetDistance * RandomHelper.NextDouble(); var angleRad = 2 * Math.PI * RandomHelper.NextDouble(); var randomOffset = new Vector2D(range * Math.Cos(angleRad), range * Math.Sin(angleRad)); hitPoint += randomOffset; } var componentSpriteRender = Api.Client.Rendering.CreateSpriteRenderer( sceneObject, positionOffset: hitPoint, spritePivotPoint: (0.5, sparksEntry.PivotY), drawOrder: drawOrder); componentSpriteRender.DrawOrderOffsetY = -hitPoint.Y; componentSpriteRender.Scale = (float)scale * Math.Pow(1.0 / projectilesCount, 0.35); if (sparksEntry.UseScreenBlending) { componentSpriteRender.BlendMode = BlendMode.Screen; } if (randomRotation) { componentSpriteRender.RotationAngleRad = (float)(RandomHelper.NextDouble() * 2 * Math.PI); } var componentAnimator = sceneObject.AddComponent <ClientComponentSpriteSheetAnimator>(); var hitSparksEntry = sparksEntry; componentAnimator.Setup( componentSpriteRender, hitSparksEntry.SpriteSheetAnimationFrames, frameDurationSeconds: animationFrameDuration, isLooped: false); var totalAnimationDuration = animationFrameDuration * componentAnimator.FramesCount; var totalDurationWithLight = 0.15 + totalAnimationDuration; if (hitSparksEntry.LightColor.HasValue) { // create light spot (even for melee weapons) var lightSource = ClientLighting.CreateLightSourceSpot( sceneObject, color: hitSparksEntry.LightColor.Value, spritePivotPoint: (0.5, 0.5), size: 7, // we don't want to display nickname/healthbar for the firing character, it's too quick anyway logicalSize: 0, positionOffset: hitPoint); ClientComponentOneShotLightAnimation.Setup(lightSource, totalDurationWithLight); } componentSpriteRender.Destroy(totalAnimationDuration); componentAnimator.Destroy(totalAnimationDuration); sceneObject.Destroy(totalDurationWithLight); }
public static void ClientExplode( Vector2D position, ExplosionPreset explosionPreset, float volume = 1.0f) { // add screen shakes ClientComponentCameraScreenShakes.AddRandomShakes( duration: explosionPreset.ScreenShakesDuration, worldDistanceMin: explosionPreset.ScreenShakesWorldDistanceMin, worldDistanceMax: explosionPreset.ScreenShakesWorldDistanceMax); // play sound var explosionSoundEmitter = Client.Audio.PlayOneShot(explosionPreset.SoundSet.GetSound(), worldPosition: position, volume: volume, pitch: RandomHelper.Range(0.95f, 1.05f)); // extend explosion sound distance explosionSoundEmitter.CustomMinDistance = (float)explosionPreset.LightWorldSize / 3; explosionSoundEmitter.CustomMaxDistance = (float)explosionPreset.LightWorldSize; // create explosion renderer var explosionSpriteAnimationDuration = explosionPreset.SpriteAnimationDuration; var explosionSceneObject = Client.Scene.CreateSceneObject("Temp explosion", position); explosionSceneObject.Destroy(delay: explosionSpriteAnimationDuration); var explosionSpriteRenderer = Client.Rendering.CreateSpriteRenderer( explosionSceneObject, TextureResource.NoTexture, drawOrder: DrawOrder.Explosion, spritePivotPoint: (0.5, 0.5)); explosionSpriteRenderer.Color = explosionPreset.SpriteColorMultiplicative; explosionSpriteRenderer.Size = explosionPreset.SpriteSize; if (explosionPreset.SpriteColorAdditive.HasValue // ReSharper disable once CompareOfFloatsByEqualityOperator || explosionPreset.SpriteBrightness != 1) { var renderingMaterial = RenderingMaterial.Create(EffectResourceAdditiveColorEffect); renderingMaterial.EffectParameters .Set("ColorAdditive", explosionPreset.SpriteColorAdditive ?? Colors.Black) .Set("Brightness", explosionPreset.SpriteBrightness); explosionSpriteRenderer.RenderingMaterial = renderingMaterial; } var isFlipped = 0 == PositionalRandom.Get(position.ToVector2Ushort(), minInclusive: 0, maxExclusive: 2, seed: 893243289); if (isFlipped) { explosionSpriteRenderer.DrawMode = DrawMode.FlipHorizontally; } ClientComponentOneShotSpriteSheetAnimationHelper.Setup( explosionSpriteRenderer, explosionPreset.SpriteAtlasResources.TakeByRandom(), explosionSpriteAnimationDuration); // add light source for the explosion var explosionLight = ClientLighting.CreateLightSourceSpot( explosionSceneObject, explosionPreset.LightColor, size: explosionPreset.LightWorldSize, positionOffset: (0, 0), spritePivotPoint: (0.5, 0.5)); ClientComponentOneShotLightAnimation.Setup( explosionLight, explosionPreset.LightDuration); // add blast wave var blastAnimationDuration = explosionPreset.BlastwaveAnimationDuration; if (blastAnimationDuration > 0) { ClientTimersSystem.AddAction( explosionPreset.BlastwaveDelay, () => { var blastSceneObject = Client.Scene.CreateSceneObject("Temp explosion", position); blastSceneObject.Destroy(delay: blastAnimationDuration); var blastSpriteRenderer = Client.Rendering.CreateSpriteRenderer( blastSceneObject, new TextureResource("FX/ExplosionBlast"), drawOrder: DrawOrder.Explosion - 1, spritePivotPoint: (0.5, 0.5)); // animate blast wave ClientComponentGenericAnimationHelper.Setup( blastSceneObject, blastAnimationDuration, updateCallback: alpha => { var blastwaveAlpha = (byte)(byte.MaxValue * (1 - alpha)); blastSpriteRenderer.Color = explosionPreset.BlastWaveColor .WithAlpha(blastwaveAlpha); var sizeX = MathHelper.Lerp(explosionPreset.BlastwaveSizeFrom.X, explosionPreset.BlastwaveSizeTo.X, alpha); var sizeY = MathHelper.Lerp(explosionPreset.BlastwaveSizeFrom.Y, explosionPreset.BlastwaveSizeTo.Y, alpha); blastSpriteRenderer.Size = new Size2F(sizeX, sizeY); }); }); } ClientGroundExplosionAnimationHelper.OnExplode( delaySeconds: explosionSpriteAnimationDuration / 2, position: position); }