public static SCNMatrix4 Normalize(this SCNMatrix4 matrix)
        {
            // for row-major matrixes only
            var normalized = matrix;

            var row0 = SCNVector4.Normalize(matrix.Row0);
            var row1 = SCNVector4.Normalize(matrix.Row1);
            var row2 = SCNVector4.Normalize(matrix.Row2);

            normalized.Row0 = row0;
            normalized.Row1 = row1;
            normalized.Row2 = row2;

            return(normalized);
        }
Beispiel #2
0
        private void UpdateCatapultStable()
        {
            if (!this.Disabled)
            {
                // Catapult will be unstable when the physics settles, therefore we do not update catapult's stability status
                if (GameTime.TimeSinceLevelStart > CatapultPhysicsSettleTime)
                {
                    // Cannot use simdVelocity on client since simdVelocity could be high from physicsSync interacting with local physics engine
                    if (!this.lastPosition.HasValue)
                    {
                        this.lastPosition = this.Base.PresentationNode.WorldPosition;
                        return;
                    }

                    var position = this.Base.PresentationNode.WorldPosition;
                    var speed    = ((position - this.lastPosition.Value) / (float)GameTime.DeltaTime).Length;
                    this.lastPosition = position;

                    // Base below table?
                    // Base tilted? base's up vector must maintain some amount of y to be determined as stable
                    var transform = this.Base.PresentationNode.Transform;
                    transform.Transpose();
                    var baseUp = SCNVector4.Normalize(transform.Column1);
                    if (position.Y < -1f || Math.Abs(baseUp.Y) < MinStableTiltBaseUpY)
                    {
                        // Switch to knocked mode
                        if (!this.isCatapultKnocked)
                        {
                            this.catapultKnockedStartTime = GameTime.Time;
                        }

                        this.isCatapultKnocked = true;
                        this.isCatapultStable  = false;
                        return;
                    }

                    this.isCatapultKnocked = false;

                    // Base could be moving although the catapult is not knocked
                    this.isCatapultStable = speed < MaxSpeedToCountAsStable;
                }
            }
        }
Beispiel #3
0
        private SCNVector3 ComputeBallPosition(CameraInfo cameraInfo)
        {
            var cameraRay = cameraInfo.Ray;

            // These should be based on the projectile radius.
            // This affects centering of ball, and can hit near plane of camera
            // This is always centering to one edge of screen independent of screen orient
            // We always want the ball at the bottom of the screen.
            var distancePullToCamera = 0.21f;
            var ballShiftDown        = 0.2f;

            var targetBallPosition = cameraRay.Position + cameraRay.Direction * distancePullToCamera;

            var cameraDown = -SCNVector4.Normalize(cameraInfo.Transform.Column1).Xyz;

            targetBallPosition += cameraDown * ballShiftDown;

            // Clamp to only the valid side
            var pullWorldPosition = this.pullOrigin.WorldPosition;

            if (pullWorldPosition.Z < 0f)
            {
                targetBallPosition.Z = Math.Min(targetBallPosition.Z, pullWorldPosition.Z);
            }
            else
            {
                targetBallPosition.Z = Math.Max(targetBallPosition.Z, pullWorldPosition.Z);
            }

            // Clamp to cone/circular core
            var yDistanceFromPull       = Math.Max(0f, pullWorldPosition.Y - targetBallPosition.Y);
            var minBallDistanceFromPull = 0.5f;
            var pullBlockConeSlope      = 1.0f;
            var pullBlockConeRadius     = yDistanceFromPull / pullBlockConeSlope;
            var pullBlockCoreRadius     = Math.Max(minBallDistanceFromPull, pullBlockConeRadius);

            // if pull is in the core, move it out.
            var pullWorldPositionGrounded  = new SCNVector3(pullWorldPosition.X, 0f, pullWorldPosition.Z);
            var targetPullPositionGrounded = new SCNVector3(targetBallPosition.X, 0f, targetBallPosition.Z);
            var targetInitialToTargetPull  = targetPullPositionGrounded - pullWorldPositionGrounded;

            if (pullBlockCoreRadius > targetInitialToTargetPull.Length)
            {
                var moveOutDirection = SCNVector3.Normalize(targetInitialToTargetPull);
                var newTargetPullPositionGrounded = pullWorldPositionGrounded + moveOutDirection * pullBlockCoreRadius;
                targetBallPosition = new SCNVector3(newTargetPullPositionGrounded.X, targetBallPosition.Y, newTargetPullPositionGrounded.Z);
            }

            // only use the 2d distance, so that user can gauage stretch indepdent of mtch
            var distance2D = targetBallPosition - pullWorldPosition;
            var stretchY   = Math.Abs(distance2D.Y);

            distance2D.Y = 0f;

            var stretchDistance = distance2D.Length;

            this.stretch = DigitExtensions.Clamp((double)stretchDistance, this.properties.MinStretch, this.properties.MaxStretch);

            // clamp a little bit farther than maxStretch
            // can't let the strap move back too far right now
            var clampedStretchDistance = (float)(1.1d * this.properties.MaxStretch);

            if (stretchDistance > clampedStretchDistance)
            {
                targetBallPosition = (clampedStretchDistance / stretchDistance) * (targetBallPosition - pullWorldPosition) + pullWorldPosition;
                stretchDistance    = clampedStretchDistance;
            }

            // Make this optional, not required.  You're often at max stretch.
            // Also have a timer for auto-launch.  This makes it very difficuilt to test
            // storing state in member data
            this.IsPulledTooFar = stretchDistance > (float)(this.properties.MaxStretch) || stretchY > (float)(this.properties.MaxStretch);

            return(targetBallPosition);
        }