public WeaponFireTracePreset( string traceTexturePath, IReadOnlyWeaponHitSparksPreset hitSparksPreset, double traceSpeed, ushort traceSpriteWidthPixels, int traceStartOffsetPixels, double traceStartScaleSpeedExponent = 1.0, double traceEndFadeOutExponent = 1.0, bool useScreenBlending = false, bool?drawHitSparksAsLight = null) { this.TraceTexture = traceTexturePath is not null ? new TextureResource(traceTexturePath, isTransparent: true) : null; this.TraceSpeed = traceSpeed; this.HitSparksPreset = hitSparksPreset; this.TraceStartScaleSpeedExponent = traceStartScaleSpeedExponent; this.TraceEndFadeOutExponent = traceEndFadeOutExponent; this.TraceWorldLength = traceSpriteWidthPixels / 256.0; this.TraceStartWorldOffset = traceStartOffsetPixels / 256.0; this.TraceMinDistance = this.TraceWorldLength * 0.5; this.UseScreenBlending = useScreenBlending; this.DrawHitSparksAsLight = drawHitSparksAsLight ?? this.HasTrace; }
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); }