예제 #1
0
        private void UpdateFromGamepad(Transform referenceObj, GamepadInput gamepad)
        {
            float referenceAngle = (referenceObj != null) ? referenceObj.Angle : 0.0f;

            if (gamepad.LeftThumbstick.Length > 0.25f)
            {
                float mappedLength = (gamepad.LeftThumbstick.Length - 0.25f) / 0.75f;
                this.controlMovement = gamepad.LeftThumbstick * mappedLength / gamepad.LeftThumbstick.Length;
            }
            else
            {
                this.controlMovement = Vector2.Zero;
            }

            if (gamepad.RightThumbstick.Length > 0.5f)
            {
                this.controlLookAngle = gamepad.RightThumbstick.Angle;
                this.controlLookSpeed = (gamepad.RightThumbstick.Length - 0.5f) / 0.5f;
            }
            else if (gamepad.LeftThumbstick.Length > 0.25f)
            {
                this.controlLookAngle = gamepad.LeftThumbstick.Angle;
                this.controlLookSpeed = (gamepad.LeftThumbstick.Length - 0.25f) / 0.75f;
            }

            bool targetAimed = MathF.CircularDist(referenceAngle, this.controlLookAngle) < MathF.RadAngle1 * 10;

            this.controlFireWeapon =
                (targetAimed && gamepad.RightThumbstick.Length > 0.9f) ||
                gamepad[GamepadAxis.RightTrigger] > 0.5f ||
                gamepad[GamepadButton.RightShoulder] ||
                gamepad[GamepadButton.A];
            this.controlQuit  = gamepad.ButtonHit(GamepadButton.Back);
            this.controlStart = gamepad.ButtonHit(GamepadButton.Start);
        }
예제 #2
0
        [Test] public void Perpendicular()
        {
            AssertVectorEqual(new Vector2(0.0f, -1.0f).PerpendicularLeft, -1.0f, 0.0f);
            AssertVectorEqual(new Vector2(1.0f, 0.0f).PerpendicularLeft, 0.0f, -1.0f);
            AssertVectorEqual(new Vector2(0.0f, 1.0f).PerpendicularLeft, 1.0f, 0.0f);
            AssertVectorEqual(new Vector2(-1.0f, 0.0f).PerpendicularLeft, 0.0f, 1.0f);

            AssertVectorEqual(new Vector2(0.0f, -1.0f).PerpendicularRight, 1.0f, 0.0f);
            AssertVectorEqual(new Vector2(1.0f, 0.0f).PerpendicularRight, 0.0f, 1.0f);
            AssertVectorEqual(new Vector2(0.0f, 1.0f).PerpendicularRight, -1.0f, 0.0f);
            AssertVectorEqual(new Vector2(-1.0f, 0.0f).PerpendicularRight, 0.0f, -1.0f);

            Random rnd = new Random(1);

            for (int i = 0; i < 100; i++)
            {
                Vector2 vector = rnd.NextVector2();
                Vector2 left   = vector.PerpendicularLeft;
                Vector2 right  = vector.PerpendicularRight;

                Assert.AreEqual(MathF.RadAngle90, MathF.CircularDist(vector.Angle, left.Angle), Epsilon);
                Assert.AreEqual(MathF.RadAngle90, MathF.CircularDist(vector.Angle, right.Angle), Epsilon);

                Assert.AreEqual(-1.0f, MathF.TurnDir(vector.Angle, left.Angle));
                Assert.AreEqual(1.0f, MathF.TurnDir(vector.Angle, right.Angle));
            }
        }
예제 #3
0
        void ICmpUpdatable.OnUpdate()
        {
            Transform           transform  = this.GameObj.Transform;
            CharacterController controller = this.GameObj.GetComponent <CharacterController>();
            ActorRenderer       sprite     = this.GameObj.GetComponent <ActorRenderer>();

            float targetMoveAngle = controller.TargetLookDir;

            bool isMoving = controller.TargetMovement.Length > 0.01f;

            if (isMoving)
            {
                sprite.AnimDuration = this.spriteSheetBaseDuration / controller.TargetMovement.Length;
            }
            sprite.AnimPaused = !isMoving;

            if (MathF.CircularDist(targetMoveAngle, 0.0f) <= MathF.RadAngle45)
            {
                sprite.AnimFirstFrame = this.spriteSheetIndex + this.spriteSheetOffset * 0;
            }
            else if (MathF.CircularDist(targetMoveAngle, MathF.RadAngle90) <= MathF.RadAngle45)
            {
                sprite.AnimFirstFrame = this.spriteSheetIndex + this.spriteSheetOffset * 1;
            }
            else if (MathF.CircularDist(targetMoveAngle, MathF.RadAngle270) <= MathF.RadAngle45)
            {
                sprite.AnimFirstFrame = this.spriteSheetIndex + this.spriteSheetOffset * 3;
            }
            else
            {
                sprite.AnimFirstFrame = this.spriteSheetIndex + this.spriteSheetOffset * 2;
            }
        }
예제 #4
0
        public override void OnUpdate()
        {
            base.OnUpdate();
            ActorRenderer sprite    = this.GameObj.GetComponent <ActorRenderer>();
            Transform     transform = this.GameObj.Transform;

            Vector2 moveVec = transform.Vel.Xy;
            float   moveDir = moveVec.Angle;

            if (moveVec.Length <= 0.75f)
            {
                sprite.AnimFirstFrame = 0;
            }
            else if (MathF.CircularDist(moveDir, 0.0f) <= MathF.RadAngle45)
            {
                sprite.AnimFirstFrame = 9;
            }
            else if (MathF.CircularDist(moveDir, MathF.RadAngle90) <= MathF.RadAngle45)
            {
                sprite.AnimFirstFrame = 6;
            }
            else if (MathF.CircularDist(moveDir, MathF.RadAngle270) <= MathF.RadAngle45)
            {
                sprite.AnimFirstFrame = 3;
            }
            else
            {
                sprite.AnimFirstFrame = 0;
            }

            this.lifeTimeMs += Time.TimeMult * Time.MsPFMult;
            if (this.lifeTimeMs > 500.0f)
            {
                this.Energy -= (Time.MsPFMult / (50.0f)) * Time.TimeMult;
                if (this.Energy + this.TransferEnergy <= 0.0f)
                {
                    this.GameObj.Dispose();
                }
                this.HurtCharacters();
            }

            if (this.fireLoopInstance != null && this.fireLoopInstance.Disposed)
            {
                this.fireLoopInstance = null;
            }
            if (this.fireLoopInstance == null)
            {
                float scale = this.GetScale(this.Energy);
                if (scale > 0.05f && this.fireLoopSound != null)
                {
                    this.fireLoopInstance        = DualityApp.Sound.PlaySound3D(this.fireLoopSound, this.GameObj);
                    this.fireLoopInstance.Looped = true;
                    this.fireLoopInstance.Volume = scale;
                }
            }
        }
예제 #5
0
        private void DrawLocalAngleConstraint(Canvas canvas, RigidBody body, Vector2 anchor, float targetAngle, float currentAngle, float radius)
        {
            Vector3 bodyPos = body.GameObj.Transform.Pos;

            ColorRgba clr    = this.JointColor;
            ColorRgba clrErr = this.JointErrorColor;

            Vector2 anchorToWorld = body.GameObj.Transform.GetWorldVector(anchor);
            Vector2 angleVec      = Vector2.FromAngleLength(targetAngle, radius);
            Vector2 errorVec      = Vector2.FromAngleLength(currentAngle, radius);
            bool    hasError      = MathF.CircularDist(targetAngle, currentAngle) >= MathF.RadAngle1;

            if (hasError)
            {
                float circleBegin = currentAngle;
                float circleEnd   = targetAngle;
                if (MathF.TurnDir(circleBegin, circleEnd) < 0)
                {
                    MathF.Swap(ref circleBegin, ref circleEnd);
                    circleEnd = circleBegin + MathF.CircularDist(circleBegin, circleEnd);
                }

                canvas.State.SetMaterial(new BatchInfo(DrawTechnique.Alpha, clrErr));
                canvas.DrawLine(
                    bodyPos.X + anchorToWorld.X,
                    bodyPos.Y + anchorToWorld.Y,
                    bodyPos.Z,
                    bodyPos.X + anchorToWorld.X + errorVec.X,
                    bodyPos.Y + anchorToWorld.Y + errorVec.Y,
                    bodyPos.Z);
                canvas.DrawCircleSegment(
                    bodyPos.X + anchorToWorld.X,
                    bodyPos.Y + anchorToWorld.Y,
                    bodyPos.Z,
                    radius,
                    circleBegin,
                    circleEnd);
                this.DrawLocalText(canvas, body,
                                   string.Format("{0:F0}°", MathF.RadToDeg(MathF.NormalizeAngle(currentAngle))),
                                   anchorToWorld + errorVec,
                                   Vector2.UnitY,
                                   errorVec.Angle);
            }
            canvas.State.SetMaterial(new BatchInfo(DrawTechnique.Alpha, clr));
            canvas.DrawLine(
                bodyPos.X + anchorToWorld.X,
                bodyPos.Y + anchorToWorld.Y,
                bodyPos.Z,
                bodyPos.X + anchorToWorld.X + angleVec.X,
                bodyPos.Y + anchorToWorld.Y + angleVec.Y,
                bodyPos.Z);
            this.DrawLocalText(canvas, body,
                               string.Format("{0:F0}°", MathF.RadToDeg(MathF.NormalizeAngle(targetAngle))),
                               anchorToWorld + angleVec,
                               angleVec.Angle);
        }
예제 #6
0
        private void DrawLocalAngleConstraint(Canvas canvas, RigidBody body, Vector2 anchor, float targetAngle, float currentAngle, float radius)
        {
            ColorRgba baseColor = canvas.State.ColorTint;
            Vector3   bodyPos   = body.GameObj.Transform.Pos;

            radius = this.GetScreenMinScale(canvas, radius, this.minAngleConstraintRadius);

            float   lineWidth     = this.GetScreenConstantScale(canvas, this.defaultLineWidth);
            Vector2 anchorToWorld = body.GameObj.Transform.GetWorldVector(anchor);
            Vector2 angleVec      = Vector2.FromAngleLength(targetAngle, radius);
            Vector2 errorVec      = Vector2.FromAngleLength(currentAngle, radius);
            bool    hasError      = MathF.CircularDist(targetAngle, currentAngle) >= MathF.RadAngle1;

            if (hasError)
            {
                float circleBegin = currentAngle;
                float circleEnd   = targetAngle;
                if (MathF.TurnDir(circleBegin, circleEnd) < 0)
                {
                    MathF.Swap(ref circleBegin, ref circleEnd);
                    circleEnd = circleBegin + MathF.CircularDist(circleBegin, circleEnd);
                }

                canvas.State.ColorTint = baseColor * this.JointErrorColor;
                canvas.FillThickLine(
                    bodyPos.X + anchorToWorld.X,
                    bodyPos.Y + anchorToWorld.Y,
                    0.0f,
                    bodyPos.X + anchorToWorld.X + errorVec.X,
                    bodyPos.Y + anchorToWorld.Y + errorVec.Y,
                    0.0f,
                    lineWidth);
                canvas.FillCircleSegment(
                    bodyPos.X + anchorToWorld.X,
                    bodyPos.Y + anchorToWorld.Y,
                    0.0f,
                    radius,
                    circleBegin,
                    circleEnd,
                    lineWidth);
            }
            canvas.State.ColorTint = baseColor * this.JointColor;
            canvas.FillThickLine(
                bodyPos.X + anchorToWorld.X,
                bodyPos.Y + anchorToWorld.Y,
                0.0f,
                bodyPos.X + anchorToWorld.X + angleVec.X,
                bodyPos.Y + anchorToWorld.Y + angleVec.Y,
                0.0f,
                lineWidth);
            canvas.State.ColorTint = baseColor;
        }
예제 #7
0
        private void TilesetView_MouseMove(object sender, MouseEventArgs e)
        {
            Size  tileSize   = this.TilesetView.DisplayedTileSize;
            Point tilePos    = this.TilesetView.GetTileIndexLocation(this.TilesetView.HoveredTileIndex);
            Point posOnTile  = new Point(e.X - tilePos.X, e.Y - tilePos.Y);
            Size  centerSize = new Size(
                tileSize.Width - TilemapsResCache.TilesetCollisionVertical.Width * 2 - 2,
                tileSize.Height - TilemapsResCache.TilesetCollisionHorizontal.Height * 2 - 2);

            // Determine the hovered tile hotspot for user interaction
            TileHotSpot lastHoveredArea = this.hoveredArea;

            if (posOnTile.X > (tileSize.Width - centerSize.Width) / 2 &&
                posOnTile.Y > (tileSize.Height - centerSize.Height) / 2 &&
                posOnTile.X < (tileSize.Width + centerSize.Width) / 2 &&
                posOnTile.Y < (tileSize.Height + centerSize.Height) / 2)
            {
                this.hoveredArea = TileHotSpot.Center;
            }
            else
            {
                float angle = MathF.Angle(tileSize.Width / 2, tileSize.Height / 2, posOnTile.X, posOnTile.Y);
                if (MathF.CircularDist(angle, 0.0f) < MathF.RadAngle45)
                {
                    this.hoveredArea = TileHotSpot.Top;
                }
                else if (MathF.CircularDist(angle, MathF.RadAngle90) < MathF.RadAngle45)
                {
                    this.hoveredArea = TileHotSpot.Right;
                }
                else if (MathF.CircularDist(angle, MathF.RadAngle180) < MathF.RadAngle45)
                {
                    this.hoveredArea = TileHotSpot.Bottom;
                }
                else
                {
                    this.hoveredArea = TileHotSpot.Left;
                }
            }

            // If the user is in the process of setting or clearing bits, perform the drawing operation
            if (this.isUserDrawing)
            {
                this.PerformUserDrawAction();
            }

            if (lastHoveredArea != this.hoveredArea)
            {
                this.TilesetView.InvalidateTile(this.TilesetView.HoveredTileIndex, 0);
            }
        }
예제 #8
0
        void ICmpUpdatable.OnUpdate()
        {
            // Calculate velocity values from last frames movement
            if (MathF.Abs(Time.TimeMult) > float.Epsilon)
            {
                Transform transform = this.GameObj.Transform;
                Vector3   pos       = transform.Pos;
                float     angle     = transform.Angle;

                this.posDiff   = pos - this.lastPosition;
                this.angleDiff = MathF.TurnDir(this.lastAngle, angle) * MathF.CircularDist(this.lastAngle, angle);

                Vector3 lastVelocity      = this.posDiff / Time.TimeMult;
                float   lastAngleVelocity = this.angleDiff / Time.TimeMult;

                this.velocity      += (lastVelocity - this.velocity) * 0.25f * Time.TimeMult;
                this.angleVelocity += (lastAngleVelocity - this.angleVelocity) * 0.25f * Time.TimeMult;
                this.lastPosition   = pos;
                this.lastAngle      = angle;
            }
        }
예제 #9
0
        void ICmpUpdatable.OnUpdate()
        {
            Transform      transform = this.GameObj.Transform;
            RigidBody      body      = this.GameObj.GetComponent <RigidBody>();
            SpriteRenderer sprite    = this.GameObj.GetComponent <SpriteRenderer>();

            float turnDiff =
                MathF.TurnDir(transform.Angle, this.rotateActivity.Angle) *
                MathF.CircularDist(transform.Angle, this.rotateActivity.Angle);
            float thrusterBoost =
                0.75f * Vector2.Dot(this.thrusterActivity.Normalized, Vector2.FromAngleLength(transform.Angle, 1.0f)) +
                0.25f * this.weaponEnergy;

            body.AngularVelocity = turnDiff * this.rotateActivity.Length * this.rotationSpeed;
            body.ApplyWorldForce(this.thrusterActivity * this.thrusterStrength * (1.0f + 0.5f * thrusterBoost) * body.Mass);

            this.displayedTeamColor = Vector4.Lerp(this.displayedTeamColor, this.teamColor.ToVector(), 0.1f * Time.TimeMult);
            sprite.ColorTint        = this.displayedTeamColor.ToColor();

            this.weaponTimer  = MathF.Max(0.0f, this.weaponTimer - Time.TimeMult * Time.SPFMult);
            this.weaponEnergy = MathF.Min(1.0f, this.weaponEnergy + Time.TimeMult * Time.SPFMult / 5.0f);
            this.health       = MathF.Min(1.0f, this.health + Time.TimeMult * Time.SPFMult / 30.0f);

            if (this == this.GameObj.ParentScene.FindComponent <Player>().ControlTarget)
            {
                if (!this.Disposed)
                {
                    if (this.thrusterSoundInstance == null || this.thrusterSoundInstance.Disposed)
                    {
                        this.thrusterSoundInstance        = DualityApp.Sound.PlaySound(this.thrusterSound);
                        this.thrusterSoundInstance.Looped = true;
                    }
                    this.thrusterSoundInstance.Volume = this.thrusterActivity.Length * (0.5f + 0.5f * thrusterBoost);
                    this.thrusterSoundInstance.Pitch  = 0.8f + 0.4f * this.thrusterActivity.Length * (0.5f + 0.5f * thrusterBoost);
                }
            }
        }
예제 #10
0
 /// <summary>
 /// Turns the object to the given absolute radian angle. This will affect the Transforms <see cref="AngleVel">angular velocity</see> value.
 /// </summary>
 /// <param name="value"></param>
 public void TurnToAbs(float value)
 {
     this.TurnBy(MathF.TurnDir(this.angleAbs, value) * MathF.CircularDist(value, this.angleAbs));
 }
예제 #11
0
 /// <summary>
 /// Turns the object to the given radian angle in local space of its parent object. This will be treated as movement, rather than teleportation.
 /// </summary>
 /// <param name="value"></param>
 public void TurnToLocal(float value)
 {
     this.TurnBy(MathF.TurnDir(this.angle, value) * MathF.CircularDist(value, this.angle));
 }
예제 #12
0
        public override void Draw(Canvas target, Vector3 basePos, float baseRotation, float baseScale)
        {
            float borderRadius = DefaultOutlineWidth;
            float circleRadius = this.radius * baseScale;

            // Scale anti-proportional to perspective scale in order to keep a constant size
            // in screen space even when actually drawing in world space.
            {
                float scale = target.DrawDevice.GetScaleAtZ(this.pos.Z + basePos.Z);
                borderRadius /= scale;
                if (this.invariantScale)
                {
                    circleRadius /= scale;
                }
            }

            // Determine circle position
            Vector3 circlePos = this.pos;

            MathF.TransformCoord(ref circlePos.X, ref circlePos.Y, baseRotation, baseScale);
            circlePos += basePos;

            // Draw circle
            target.State.ColorTint *= this.Color;
            target.FillCircleSegment(
                circlePos.X,
                circlePos.Y,
                circlePos.Z,
                circleRadius - borderRadius * 0.5f,
                this.minAngle + baseRotation,
                this.maxAngle + baseRotation);

            // Draw circle outline
            target.State.DepthOffset -= 0.01f;
            target.State.ColorTint   *= ColorRgba.Black;
            target.FillCircleSegment(
                circlePos.X,
                circlePos.Y,
                circlePos.Z,
                circleRadius,
                this.minAngle + baseRotation,
                this.maxAngle + baseRotation,
                borderRadius);
            if (MathF.CircularDist(this.minAngle, this.maxAngle) > MathF.RadAngle1 * 0.001f)
            {
                Vector2 minAngleVec = Vector2.FromAngleLength(this.minAngle + baseRotation, circleRadius);
                Vector2 maxAngleVec = Vector2.FromAngleLength(this.maxAngle + baseRotation, circleRadius);
                target.FillThickLine(
                    circlePos.X,
                    circlePos.Y,
                    circlePos.Z,
                    circlePos.X + minAngleVec.X,
                    circlePos.Y + minAngleVec.Y,
                    circlePos.Z,
                    borderRadius);
                target.FillThickLine(
                    circlePos.X,
                    circlePos.Y,
                    circlePos.Z,
                    circlePos.X + maxAngleVec.X,
                    circlePos.Y + maxAngleVec.Y,
                    circlePos.Z,
                    borderRadius);
            }
        }
예제 #13
0
        void ICmpUpdatable.OnUpdate()
        {
            // Don't have a valid, active animation? Early-out.
            if (this.activeAnim == null)
            {
                return;
            }
            if (this.activeAnim.FrameCount <= 0)
            {
                return;
            }
            if (this.activeAnim.DirectionMap.Length == 0)
            {
                return;
            }

            // Retrieve the actor renderer we're going to animate
            ActorRenderer actor = this.GameObj.GetComponent <ActorRenderer>();

            // Determine the active direction
            int   startFrame   = 0;
            float minAngleDiff = float.MaxValue;

            for (int i = 0; i < this.activeAnim.DirectionMap.Length; i++)
            {
                float angleDiff = MathF.CircularDist(
                    this.animDirection,
                    MathF.DegToRad(this.activeAnim.DirectionMap[i].Angle));
                if (angleDiff < minAngleDiff)
                {
                    minAngleDiff = angleDiff;
                    startFrame   = this.activeAnim.DirectionMap[i].SpriteSheetIndex;
                }
            }

            // Determine the currently displayed frame
            float animProgress   = (this.animTime / this.activeAnim.Duration) % 1.0f;
            int   animCycleCount = (int)(this.animTime / this.activeAnim.Duration);

            switch (this.activeLoopMode)
            {
            // In single-shot animations, complete the animation only once
            case LoopMode.Once:
                if (animCycleCount > 1)
                {
                    animProgress = 0.0f;
                }
                goto case LoopMode.Loop;

            // Regular looped animation
            case LoopMode.Loop:
                actor.SpriteIndex = startFrame + MathF.Clamp(
                    (int)(this.activeAnim.FrameCount * animProgress),
                    0,
                    this.activeAnim.FrameCount);
                break;

            // Alternating regular and reverse animation
            case LoopMode.PingPong:
                bool  reverse = (animCycleCount % 2 == 0);
                float pingPongAnimProgress =
                    reverse ?
                    (1.0f - animProgress) :
                    animProgress;

                actor.SpriteIndex = startFrame + MathF.Clamp(
                    (int)(0.5f + (this.activeAnim.FrameCount - 1) * pingPongAnimProgress),
                    0,
                    this.activeAnim.FrameCount);
                break;
            }

            // Advance animation time, unless we're displaying a fixed single frame
            if (this.activeLoopMode != LoopMode.RandomSingle)
            {
                this.animTime += this.animSpeed * Time.TimeMult * Time.SPFMult;
            }
        }
예제 #14
0
        void ICmpUpdatable.OnUpdate()
        {
            // Don't have a valid, active animation? Early-out.
            if (this.activeAnim == null)
            {
                return;
            }
            if (this.activeAnim.FrameCount <= 0)
            {
                return;
            }
            if (this.activeAnim.DirectionMap.Length == 0)
            {
                return;
            }

            // Determine the active direction
            int   startFrame   = 0;
            float minAngleDiff = float.MaxValue;

            for (int i = 0; i < this.activeAnim.DirectionMap.Length; i++)
            {
                float angleDiff = MathF.CircularDist(
                    this.animDirection,
                    MathF.DegToRad(this.activeAnim.DirectionMap[i].Angle));
                if (angleDiff < minAngleDiff)
                {
                    minAngleDiff = angleDiff;
                    startFrame   = this.activeAnim.DirectionMap[i].SpriteSheetIndex;
                }
            }

            // Reset animation state
            this.spriteIndex.Current = 0;
            this.spriteIndex.Next    = 0;
            this.spriteIndex.Blend   = 0.0f;

            // Determine the currently displayed frames
            float animProgress   = (this.animTime / this.activeAnim.Duration) % 1.0f;
            int   animCycleCount = (int)(this.animTime / this.activeAnim.Duration);

            switch (this.activeLoopMode)
            {
            // In single-shot animations, complete the animation only once
            case LoopMode.Once:
            {
                if (animCycleCount > 1)
                {
                    animProgress = 0.0f;
                }
                goto case LoopMode.Loop;
            }

            // Regular looped animation
            case LoopMode.Loop:
            {
                float frameTemp = this.activeAnim.FrameCount * animProgress;
                this.spriteIndex.Current = startFrame + (int)frameTemp;
                this.spriteIndex.Next    = startFrame + (((int)frameTemp + 1) % this.activeAnim.FrameCount);
                this.spriteIndex.Blend   = frameTemp - (int)frameTemp;
                break;
            }

            // Alternating regular and reverse animation
            case LoopMode.PingPong:
            {
                bool reverse = (animCycleCount % 2 == 0);
                if (reverse)
                {
                    float frameTemp = 0.5f + (this.activeAnim.FrameCount - 1) * (1.0f - animProgress);
                    this.spriteIndex.Current = startFrame + (int)frameTemp;
                    this.spriteIndex.Next    = startFrame + (((int)frameTemp - 1 + this.activeAnim.FrameCount) % this.activeAnim.FrameCount);
                    this.spriteIndex.Blend   = frameTemp - (int)frameTemp;
                }
                else
                {
                    float frameTemp = 0.5f + (this.activeAnim.FrameCount - 1) * animProgress;
                    this.spriteIndex.Current = startFrame + (int)frameTemp;
                    this.spriteIndex.Next    = startFrame + (((int)frameTemp + 1) % this.activeAnim.FrameCount);
                    this.spriteIndex.Blend   = frameTemp - (int)frameTemp;
                }

                break;
            }
            }

            // Apply the updated animation state to the actor / sprite we're animating
            this.ApplySpriteIndex();

            // Advance animation time, unless we're displaying a fixed single frame
            if (this.activeLoopMode != LoopMode.RandomSingle)
            {
                this.animTime += this.animSpeed * Time.TimeMult * Time.SecondsPerFrame;
            }
        }
예제 #15
0
        private void DrawLocalAngleConstraint(Canvas canvas, RigidBody body, Vector2 anchor, float minAngle, float maxAngle, float currentAngle, float radius)
        {
            Vector3 bodyPos = body.GameObj.Transform.Pos;

            ColorRgba clr    = this.JointColor;
            ColorRgba clrErr = this.JointErrorColor;

            Vector2 anchorToWorld = body.GameObj.Transform.GetWorldVector(anchor);
            Vector2 angleVecMin   = Vector2.FromAngleLength(minAngle, radius);
            Vector2 angleVecMax   = Vector2.FromAngleLength(maxAngle, radius);
            Vector2 errorVec      = Vector2.FromAngleLength(currentAngle, radius);
            float   angleDistMin  = MathF.Abs(currentAngle - minAngle);
            float   angleDistMax  = MathF.Abs(currentAngle - maxAngle);
            float   angleRange    = maxAngle - minAngle;
            bool    hasError      = angleDistMin > angleDistMax ? angleDistMin >= angleRange : angleDistMax >= angleRange;

            if (hasError)
            {
                float circleBegin = currentAngle;
                float circleEnd   = angleDistMin < angleDistMax ? minAngle : maxAngle;
                if (MathF.TurnDir(circleBegin, circleEnd) < 0)
                {
                    MathF.Swap(ref circleBegin, ref circleEnd);
                    circleEnd = circleBegin + MathF.CircularDist(circleBegin, circleEnd);
                }

                canvas.State.SetMaterial(new BatchInfo(DrawTechnique.Alpha, clrErr));
                canvas.DrawLine(
                    bodyPos.X + anchorToWorld.X,
                    bodyPos.Y + anchorToWorld.Y,
                    bodyPos.Z,
                    bodyPos.X + anchorToWorld.X + errorVec.X,
                    bodyPos.Y + anchorToWorld.Y + errorVec.Y,
                    bodyPos.Z);
                canvas.DrawCircleSegment(
                    bodyPos.X + anchorToWorld.X,
                    bodyPos.Y + anchorToWorld.Y,
                    bodyPos.Z,
                    radius,
                    circleBegin,
                    circleEnd);
                this.DrawLocalText(canvas, body,
                                   string.Format("{0:F0}°", MathF.RadToDeg(currentAngle)),
                                   anchorToWorld + errorVec,
                                   Vector2.UnitY,
                                   errorVec.Angle);
            }
            canvas.State.SetMaterial(new BatchInfo(DrawTechnique.Alpha, clr));
            canvas.DrawCircleSegment(
                bodyPos.X + anchorToWorld.X,
                bodyPos.Y + anchorToWorld.Y,
                bodyPos.Z,
                radius,
                minAngle,
                maxAngle);
            canvas.DrawLine(
                bodyPos.X + anchorToWorld.X,
                bodyPos.Y + anchorToWorld.Y,
                bodyPos.Z,
                bodyPos.X + anchorToWorld.X + angleVecMin.X,
                bodyPos.Y + anchorToWorld.Y + angleVecMin.Y,
                bodyPos.Z);
            canvas.DrawLine(
                bodyPos.X + anchorToWorld.X,
                bodyPos.Y + anchorToWorld.Y,
                bodyPos.Z,
                bodyPos.X + anchorToWorld.X + angleVecMax.X,
                bodyPos.Y + anchorToWorld.Y + angleVecMax.Y,
                bodyPos.Z);
            this.DrawLocalText(canvas, body,
                               string.Format("{0:F0}°", MathF.RadToDeg(minAngle)),
                               anchorToWorld + angleVecMin,
                               angleVecMin.Angle);
            this.DrawLocalText(canvas, body,
                               string.Format("{0:F0}°", MathF.RadToDeg(maxAngle)),
                               anchorToWorld + angleVecMax,
                               angleVecMax.Angle);
        }
예제 #16
0
        private void TilesetView_MouseMove(object sender, MouseEventArgs e)
        {
            Size  tileSize   = this.TilesetView.DisplayedTileSize;
            Point tilePos    = this.TilesetView.GetTileIndexLocation(this.TilesetView.HoveredTileIndex);
            Point posOnTile  = new Point(e.X - tilePos.X, e.Y - tilePos.Y);
            Size  centerSize = new Size(tileSize.Width / 2, tileSize.Height / 2);

            // Determine the hovered tile hotspot for user interaction
            TileConnection lastHoveredArea = this.hoveredArea;

            if (posOnTile.X > (tileSize.Width - centerSize.Width) / 2 &&
                posOnTile.Y > (tileSize.Height - centerSize.Height) / 2 &&
                posOnTile.X < (tileSize.Width + centerSize.Width) / 2 &&
                posOnTile.Y < (tileSize.Height + centerSize.Height) / 2)
            {
                this.hoveredArea = TileConnection.None;
            }
            else
            {
                float angle     = MathF.Angle(tileSize.Width / 2, tileSize.Height / 2, posOnTile.X, posOnTile.Y);
                float threshold = MathF.DegToRad(22.5f);
                if (MathF.CircularDist(angle, MathF.DegToRad(315.0f)) <= threshold)
                {
                    this.hoveredArea = TileConnection.TopLeft;
                }
                else if (MathF.CircularDist(angle, MathF.DegToRad(0.0f)) <= threshold)
                {
                    this.hoveredArea = TileConnection.Top;
                }
                else if (MathF.CircularDist(angle, MathF.DegToRad(45.0f)) <= threshold)
                {
                    this.hoveredArea = TileConnection.TopRight;
                }
                else if (MathF.CircularDist(angle, MathF.DegToRad(270.0f)) <= threshold)
                {
                    this.hoveredArea = TileConnection.Left;
                }
                else if (MathF.CircularDist(angle, MathF.DegToRad(90.0f)) <= threshold)
                {
                    this.hoveredArea = TileConnection.Right;
                }
                else if (MathF.CircularDist(angle, MathF.DegToRad(225.0f)) <= threshold)
                {
                    this.hoveredArea = TileConnection.BottomLeft;
                }
                else if (MathF.CircularDist(angle, MathF.DegToRad(180.0f)) <= threshold)
                {
                    this.hoveredArea = TileConnection.Bottom;
                }
                else
                {
                    this.hoveredArea = TileConnection.BottomRight;
                }
            }

            // Update action state
            TilesetAutoTileInput autoTile = this.currentAutoTile;

            if (autoTile != null)
            {
                this.isBaseTileDraw =
                    autoTile.BaseTileIndex == -1 ||
                    autoTile.BaseTileIndex == this.TilesetView.HoveredTileIndex;
            }
            this.UpdateExternalDrawMode();

            // If the user is in the process of setting or clearing bits, perform the drawing operation
            if (this.isUserDrawing)
            {
                this.PerformUserDrawAction();
            }

            if (lastHoveredArea != this.hoveredArea)
            {
                this.TilesetView.InvalidateTile(this.TilesetView.HoveredTileIndex, 0);
            }
        }
예제 #17
0
파일: Ship.cs 프로젝트: ykafia/duality
        void ICmpUpdatable.OnUpdate()
        {
            Transform     transform = this.GameObj.Transform;
            RigidBody     body      = this.GameObj.GetComponent <RigidBody>();
            ShipBlueprint blueprint = this.blueprint.Res;

            // Heal when damaged
            if (this.hitpoints < 1.0f)
            {
                this.hitpoints = MathF.Clamp(this.hitpoints + blueprint.HealRate * Time.SPFMult * Time.TimeMult / blueprint.MaxHitpoints, 0.0f, 1.0f);
            }

            // Apply force according to the desired thrust
            Vector2 actualVelocity      = body.LinearVelocity;
            Vector2 targetVelocity      = this.targetThrust * blueprint.MaxSpeed;
            Vector2 velocityDiff        = (targetVelocity - actualVelocity);
            float   sameDirectionFactor = Vector2.Dot(
                velocityDiff / MathF.Max(0.001f, velocityDiff.Length),
                this.targetThrust / MathF.Max(0.001f, this.targetThrust.Length));
            Vector2 thrusterActivity = this.targetThrust.Length * MathF.Max(sameDirectionFactor, 0.0f) * velocityDiff / MathF.Max(velocityDiff.Length, 1.0f);

            if (thrusterActivity.Length > 0.00001f)             // Don't wake physics without actually doing work
            {
                body.ApplyWorldForce(thrusterActivity * blueprint.ThrusterPower);
            }

            // Turn to the desired fire angle
            if (this.targetAngleRatio > 0.0f)
            {
                float shortestTurnDirection = MathF.TurnDir(transform.Angle, this.targetAngle);
                float shortestTurnLength    = MathF.CircularDist(transform.Angle, this.targetAngle);
                float turnDirection;
                float turnLength;
                if (MathF.Abs(body.AngularVelocity) > blueprint.MaxTurnSpeed * 0.25f)
                {
                    turnDirection = MathF.Sign(body.AngularVelocity);
                    turnLength    = (turnDirection == shortestTurnDirection) ? shortestTurnLength : (MathF.RadAngle360 - shortestTurnLength);
                }
                else
                {
                    turnDirection = shortestTurnDirection;
                    turnLength    = shortestTurnLength;
                }
                float turnSpeedRatio        = MathF.Min(turnLength * 0.25f, MathF.RadAngle30) / MathF.RadAngle30;
                float turnVelocity          = turnSpeedRatio * turnDirection * blueprint.MaxTurnSpeed * this.targetAngleRatio;
                float angularVelocityChange = (turnVelocity - body.AngularVelocity) * blueprint.TurnPower;
                if (MathF.Abs(angularVelocityChange) > 0.0000001f)                 // Don't wake physics without actually doing work
                {
                    body.AngularVelocity += angularVelocityChange * Time.TimeMult;
                }
            }

            // Weapon cooldown
            this.weaponTimer = MathF.Max(0.0f, this.weaponTimer - Time.MsPFMult * Time.TimeMult);

            // Play the owners special flight sound, when available
            if (this.owner != null && this.owner.FlightLoop != null)
            {
                SoundListener listener    = Scene.Current.FindComponent <SoundListener>();
                Vector3       listenerPos = listener.GameObj.Transform.Pos;

                // Determine the target panning manually, because we don't want a true 3D sound here (doppler, falloff, ...)
                float targetPanning;
                if (listenerPos.Xy == transform.Pos.Xy || Player.AlivePlayers.Count() <= 1)
                {
                    targetPanning = 0.0f;
                }
                else
                {
                    targetPanning = -Vector2.Dot(Vector2.UnitX, (listenerPos - transform.Pos).Xy.Normalized);
                }

                // Determine the target volume
                float targetVolume = MathF.Clamp(this.targetThrust.Length, 0.0f, 1.0f);

                // Clean up disposed flight loop
                if (this.flightLoop != null && this.flightLoop.Disposed)
                {
                    this.flightLoop = null;
                }

                // Start the flight loop when requested
                if (targetVolume > 0.0f && this.flightLoop == null)
                {
                    if ((int)Time.MainTimer.TotalMilliseconds % 2976 <= (int)Time.MsPFMult)
                    {
                        this.flightLoop        = DualityApp.Sound.PlaySound(this.owner.FlightLoop);
                        this.flightLoop.Looped = true;
                    }
                }

                // Configure existing flight loop
                if (this.flightLoop != null)
                {
                    this.flightLoop.Volume  += (targetVolume - this.flightLoop.Volume) * 0.05f * Time.TimeMult;
                    this.flightLoop.Panning += (targetPanning - this.flightLoop.Panning) * 0.05f * Time.TimeMult;
                }
            }

            // Display the damage effect when damaged
            if (this.hitpoints < 0.85f && blueprint.DamageEffect != null)
            {
                // Create a new damage effect instance, if not present yet
                if (this.damageEffect == null)
                {
                    GameObject damageObj = blueprint.DamageEffect.Res.Instantiate(transform.Pos);
                    damageObj.Parent = this.GameObj;

                    this.damageEffect = damageObj.GetComponent <ParticleEffect>();
                    if (this.damageEffect == null)
                    {
                        throw new NullReferenceException();
                    }
                }

                // Configure the damage effect
                foreach (ParticleEmitter emitter in this.damageEffect.Emitters)
                {
                    if (emitter == null)
                    {
                        continue;
                    }
                    emitter.BurstDelay = new Range(50.0f + this.hitpoints * 50.0f, 100.0f + this.hitpoints * 300.0f);
                    if (this.owner != null)
                    {
                        ColorHsva targetColor = this.owner.Color.ToHsva();
                        emitter.MinColor = new ColorHsva(targetColor.H, targetColor.S, emitter.MinColor.V, emitter.MinColor.A);
                        emitter.MaxColor = new ColorHsva(targetColor.H, targetColor.S, emitter.MaxColor.V, emitter.MaxColor.A);
                    }
                }
            }
            // Get rid of existing damage effects, if no longer needed
            else if (this.damageEffect != null)
            {
                // Stop emitting and dispose when empty
                foreach (ParticleEmitter emitter in this.damageEffect.Emitters)
                {
                    if (emitter == null)
                    {
                        continue;
                    }
                    emitter.BurstDelay = float.MaxValue;
                }
                this.damageEffect.DisposeWhenEmpty = true;
                this.damageEffect = null;
            }
        }