예제 #1
0
        public override void Update(double deltaTime)
        {
            PlayerCharacter playerCharacter     = GameSimulation.Sim.GameLevel.PlayerCharacter;
            SCNVector3      pos                 = ParentNode.Position;
            nfloat          distanceToCharacter = SCNVector3.Subtract(playerCharacter.Position, pos).Length;

            if (distanceToCharacter >= 1000f)
            {
                return;
            }

            if (!isIdle)
            {
                return;
            }

            if (playerCharacter.IsWalking)
            {
                mainSkeleton.AddAnimation(CachedAnimationForKey("monkey_get_coconut-1"), null);
                isIdle = false;
            }
            else if (MathUtils.RandomPercent() <= 0.001f)
            {
                isIdle = false;
                mainSkeleton.AddAnimation(CachedAnimationForKey("monkey_tree_hang_taunt-1"), null);
            }
        }
        public void UpdateVirtualObjectPosition(VirtualObject virtualObject, SCNVector3 position, bool filterPosition, NMatrix4 cameraTransform)
        {
            var cameraWorldPos   = cameraTransform.Translation();
            var cameraToPosition = position.Subtract(cameraWorldPos);

            // Limit the distance of the object from the camera to a maximum of 10m
            if (cameraToPosition.LengthFast > 10)
            {
                cameraToPosition = cameraToPosition.Normalized() * 10;
            }

            // Compute the average distance of the object from the camera over the last ten
            // updates. If filterPosition is true, compute a new position for the object
            // with this average. Notice that the distance is applied to the vector from
            // the camera to the content, so it only affects the percieved distance of the
            // object - the averaging does _not_ make the content "lag".
            var hitTestResultDistance = cameraToPosition.LengthFast;

            virtualObject.RecentVirtualObjectDistances.Add(hitTestResultDistance);
            virtualObject.RecentVirtualObjectDistances.KeepLast(10);

            if (filterPosition)
            {
                var averageDistance     = virtualObject.RecentVirtualObjectDistances.Average();
                var averagedDistancePos = cameraWorldPos + cameraToPosition.Normalized() * averageDistance;
                virtualObject.Position = averagedDistancePos;
            }
            else
            {
                virtualObject.Position = cameraWorldPos + cameraToPosition;
            }
        }
예제 #3
0
        void ResamplePathPositions()
        {
            // Calc the phatom end control point.
            SCNVector3 controlPointA = PathPositions [PathPositions.Count - 2];
            SCNVector3 controlPointB = PathPositions [PathPositions.Count - 3];
            SCNVector3 controlPoint;

            controlPoint.X = controlPointA.X + (controlPointA.X - controlPointB.X);
            controlPoint.Y = controlPointA.Y + (controlPointA.Y - controlPointB.Y);
            controlPoint.Z = controlPointA.Z + (controlPointA.Z - controlPointB.Z);

            PathPositions [PathPositions.Count - 1] = controlPoint;

            // Calc the phatom begin control point.
            controlPointA = PathPositions [1];
            controlPointB = PathPositions [2];

            controlPoint.X    = controlPointA.X + (controlPointA.X - controlPointB.X);
            controlPoint.Y    = controlPointA.Y + (controlPointA.Y - controlPointB.Y);
            controlPoint.Z    = controlPointA.Z + (controlPointA.Z - controlPointB.Z);
            PathPositions [0] = controlPoint;

            var   newPath                  = new List <SCNVector3> ();
            var   lastPosition             = new SCNVector3();
            float minDistanceBetweenPoints = 10.0f;
            float steps = 10000f;

            for (int i = 0; i < steps; i++)
            {
                float      t = i / steps;
                SCNVector3 currentPostion = LocationAlongPath(t);
                if (i == 0)
                {
                    newPath.Add(currentPostion);
                    lastPosition = currentPostion;
                }
                else
                {
                    var    sub  = SCNVector3.Subtract(lastPosition, currentPostion);
                    nfloat dist = sub.Length;

                    if (dist > minDistanceBetweenPoints)
                    {
                        newPath.Add(currentPostion);
                        lastPosition = currentPostion;
                    }
                }
            }

            // Last Step. Return the path position array for our pathing system to query.
            PathPositions = newPath;
        }
        private void SetNewVirtualObjectPosition(VirtualObject virtualObject, SCNVector3 position, NMatrix4 cameraTransform)
        {
            var cameraWorldPos   = cameraTransform.Translation();
            var cameraToPosition = position.Subtract(cameraWorldPos);

            // Limit the distance of the object from the camera to a maximum of 10m
            if (cameraToPosition.LengthFast > 10)
            {
                cameraToPosition = cameraToPosition.Normalized() * 10;
            }

            virtualObject.Position = cameraWorldPos + cameraToPosition;
            virtualObject.RecentVirtualObjectDistances.Clear();
        }
예제 #5
0
        public static FeatureHitTestResult HitTestFromOrigin(this ARSCNView self, SCNVector3 origin, SCNVector3 direction)
        {
            if (self.Session == null || ViewController.CurrentFrame == null)
            {
                return(null);
            }

            var currentFrame = ViewController.CurrentFrame;

            var features = currentFrame.RawFeaturePoints;

            if (features == null)
            {
                return(null);
            }

            var points = features.Points;

            // Determine the point from the whole point cloud which is closest to the hit test ray.
            var closestFeaturePoint = origin;
            var minDistance         = float.MaxValue;

            for (int n = 0; n < (int)features.Count; ++n)
            {
                var feature    = points[n];
                var featurePos = new SCNVector3(feature.X, feature.Y, feature.Z);

                var originVector = origin.Subtract(featurePos);
                var crossProduct = originVector.Cross(direction);
                var featureDistanceFromResult = crossProduct.Length;

                if (featureDistanceFromResult < minDistance)
                {
                    closestFeaturePoint = featurePos;
                    minDistance         = featureDistanceFromResult;
                }
            }

            // Compute the point along the ray that is closest to the selected feature.
            var originToFeature       = closestFeaturePoint.Subtract(origin);
            var hitTestResult         = origin.Add(direction * direction.Dot(originToFeature));
            var hitTestResultDistance = hitTestResult.Subtract(origin).LengthFast;

            // Return result
            return(new FeatureHitTestResult(hitTestResult, hitTestResultDistance, closestFeaturePoint, minDistance));
        }
예제 #6
0
        public static SCNNode SCAddChildNode(SCNNode container, string name, string path, nfloat scale)
        {
            // Load the scene from the specified file
            var scene = SCNScene.FromFile(path);

            // Retrieve the root node
            var node = scene.RootNode;

            // Search for the node named "name"
            if (name.Length > 0)
            {
                node = node.FindChildNode(name, true);
            }
            else
            {
                node = node.ChildNodes [0];                 // Take the first child if no name is passed
            }
            if (scale != 0)
            {
                // Rescale based on the current bounding box and the desired scale
                // Align the node to 0 on the Y axis
                var min = new SCNVector3();
                var max = new SCNVector3();
                node.GetBoundingBox(ref min, ref max);

                var mid = SCNVector3.Add(min, max);
                mid   = SCNVector3.Multiply(mid, 0.5f);
                mid.Y = min.Y;                 // Align on bottom

                var size    = SCNVector3.Subtract(max, min);
                var maxSize = (nfloat)Math.Max(Math.Max(size.X, size.Y), size.Z);

                scale = scale / maxSize;
                mid   = SCNVector3.Multiply(mid, scale);
                mid   = -mid;

                node.Scale    = new SCNVector3(scale, scale, scale);
                node.Position = new SCNVector3(mid);
            }

            // Add to the container passed in argument
            container.AddChildNode(node);

            return(node);
        }
예제 #7
0
        private void Explosion(SCNVector3 center, List <SCNNode> nodes)
        {
            foreach (var node in nodes)
            {
                var position = node.PresentationNode.Position;
                var dir      = SCNVector3.Subtract(position, center);

                var force    = (nfloat)25.0f;
                var distance = dir.Length;

                dir = SCNVector3.Multiply(dir, force / NMath.Max(0.01f, distance));

                node.PhysicsBody.ApplyForce(dir, new SCNVector3(RandFloat(-0.2, 0.2), RandFloat(-0.2, 0.2), RandFloat(-0.2, 0.2)), true);

                node.RunAction(SCNAction.Sequence(new SCNAction[] {
                    SCNAction.Wait(2),
                    SCNAction.FadeOut(0.5f),
                    SCNAction.RemoveFromParentNode()
                }));
            }
        }
예제 #8
0
        private SCNNode SetupVehicle(SCNScene scene)
        {
            var carScene    = SCNScene.FromFile("rc_car", ResourceManager.ResourceFolder, (NSDictionary)null);
            var chassisNode = carScene.RootNode.FindChildNode("rccarBody", false);

            chassisNode.Position = new SCNVector3(0f, 10f, 30f);
            chassisNode.Rotation = new SCNVector4(0f, 1f, 0f, (float)Math.PI);

            var body = SCNPhysicsBody.CreateDynamicBody();

            body.AllowsResting   = false;
            body.Mass            = 80f;
            body.Restitution     = 0.1f;
            body.Friction        = 0.5f;
            body.RollingFriction = 0f;

            chassisNode.PhysicsBody = body;

            var frontCameraNode = SCNNode.Create();

            frontCameraNode.Position    = new SCNVector3(0f, 3.5f, 2.5f);
            frontCameraNode.Rotation    = new SCNVector4(0f, 1f, 0f, (float)Math.PI);
            frontCameraNode.Camera      = SCNCamera.Create();
            frontCameraNode.Camera.XFov = 75f;
            frontCameraNode.Camera.ZFar = 500f;

            chassisNode.AddChildNode(frontCameraNode);

            scene.RootNode.AddChildNode(chassisNode);

            var pipeNode = chassisNode.FindChildNode("pipe", true);

            reactor = SCNParticleSystem.Create("reactor", ResourceManager.ResourceFolder);
            reactor.ParticleImage   = ResourceManager.GetResourcePath("spark.png");
            reactorDefaultBirthRate = reactor.BirthRate;
            reactor.BirthRate       = 0;
            pipeNode.AddParticleSystem(reactor);

            SCNNode wheel0Node = chassisNode.FindChildNode("wheelLocator_FL", true);
            SCNNode wheel1Node = chassisNode.FindChildNode("wheelLocator_FR", true);
            SCNNode wheel2Node = chassisNode.FindChildNode("wheelLocator_RL", true);
            SCNNode wheel3Node = chassisNode.FindChildNode("wheelLocator_RR", true);

            var wheel0 = SCNPhysicsVehicleWheel.Create(wheel0Node);
            var wheel1 = SCNPhysicsVehicleWheel.Create(wheel1Node);
            var wheel2 = SCNPhysicsVehicleWheel.Create(wheel2Node);
            var wheel3 = SCNPhysicsVehicleWheel.Create(wheel3Node);

            var min = SCNVector3.Zero;
            var max = SCNVector3.Zero;

            wheel0Node.GetBoundingBox(ref min, ref max);
            float wheelHalfWidth = 0.5f * (max.X - min.X);

            wheel0.ConnectionPosition = SCNVector3.Add(wheel0Node.ConvertPositionToNode(SCNVector3.Zero, chassisNode), new SCNVector3(wheelHalfWidth, 0f, 0f));
            wheel1.ConnectionPosition = SCNVector3.Subtract(wheel1Node.ConvertPositionToNode(SCNVector3.Zero, chassisNode), new SCNVector3(wheelHalfWidth, 0f, 0f));
            wheel2.ConnectionPosition = SCNVector3.Add(wheel2Node.ConvertPositionToNode(SCNVector3.Zero, chassisNode), new SCNVector3(wheelHalfWidth, 0f, 0f));
            wheel3.ConnectionPosition = SCNVector3.Subtract(wheel3Node.ConvertPositionToNode(SCNVector3.Zero, chassisNode), new SCNVector3(wheelHalfWidth, 0f, 0f));

            var vehicle = SCNPhysicsVehicle.Create(chassisNode.PhysicsBody,
                                                   new SCNPhysicsVehicleWheel[] { wheel0, wheel1, wheel2, wheel3 });

            scene.PhysicsWorld.AddBehavior(vehicle);
            this.vehicle = vehicle;

            return(chassisNode);
        }
예제 #9
0
        public virtual void DidSimulatePhysics(ISCNSceneRenderer renderer, double timeInSeconds)
        {
            float defaultEngineForce  = 300.0f;
            float defaultBrakingForce = 3.0f;
            float steeringClamp       = 0.6f;
            float cameraDamping       = 0.3f;

            GameView scnView = GameView;

            float engineForce  = 0;
            float brakingForce = 0;

            var   controllers = GCController.Controllers;
            float orientation = this.orientation;

            switch (scnView.TouchesCount)
            {
            case 1:
                engineForce       = defaultEngineForce;
                reactor.BirthRate = reactorDefaultBirthRate;
                break;

            case 2:
                engineForce       = -defaultEngineForce;
                reactor.BirthRate = 0;
                break;

            case 3:
                brakingForce      = 100;
                reactor.BirthRate = 0;
                break;

            default:
                brakingForce      = defaultBrakingForce;
                reactor.BirthRate = 0;
                break;
            }

            if (controllers != null && controllers.Length > 0)
            {
                GCController             controller = controllers [0];
                GCGamepad                pad        = controller.Gamepad;
                GCControllerDirectionPad dpad       = pad.DPad;

                if (dpad.Right.IsPressed)
                {
                    if (orientationCum < 0f)
                    {
                        orientationCum *= decrementOrientation;
                    }

                    orientationCum += incrementOrientation;

                    if (orientationCum > 1f)
                    {
                        orientationCum = 1f;
                    }
                }
                else if (dpad.Left.IsPressed)
                {
                    if (orientationCum > 0)
                    {
                        orientationCum *= decrementOrientation;
                    }

                    orientationCum -= incrementOrientation;

                    if (orientationCum < -1)
                    {
                        orientationCum = -1;
                    }
                }
                else
                {
                    orientationCum *= decrementOrientation;
                }
            }

            vehicleSteering = -orientation;
            if (orientation == 0)
            {
                vehicleSteering *= 0.9f;
            }
            if (vehicleSteering < -steeringClamp)
            {
                vehicleSteering = -steeringClamp;
            }
            if (vehicleSteering > steeringClamp)
            {
                vehicleSteering = steeringClamp;
            }

            vehicle.SetSteeringAngle(vehicleSteering, 0);
            vehicle.SetSteeringAngle(vehicleSteering, 1);

            vehicle.ApplyEngineForce(engineForce, 2);
            vehicle.ApplyEngineForce(engineForce, 3);

            vehicle.ApplyBrakingForce(brakingForce, 2);
            vehicle.ApplyBrakingForce(brakingForce, 3);

            ReorientCarIfNeeded();

            SCNNode    car       = vehicleNode.PresentationNode;
            SCNVector3 carPos    = car.Position;
            var        targetPos = new SCNVector3(carPos.X, 30f, carPos.Z + 25f);
            var        cameraPos = new SCNVector3(cameraNode.Position);

            cameraPos           = SCNVector3.Add(cameraPos, cameraDamping * (SCNVector3.Subtract(targetPos, cameraPos)));
            cameraNode.Position = cameraPos;

            if (scnView.InCarView)
            {
                var frontPosition = scnView.PointOfView.PresentationNode.ConvertPositionToNode(new SCNVector3(0f, 0f, -30f), null);
                spotLightNode.Position = new SCNVector3(frontPosition.X, 80f, frontPosition.Z);
                spotLightNode.Rotation = new SCNVector4(1f, 0f, 0f, -(float)Math.PI / 2f);
            }
            else
            {
                spotLightNode.Position = new SCNVector3(carPos.X, 80f, carPos.Z + 30f);
                spotLightNode.Rotation = new SCNVector4(1f, 0f, 0f, -(float)(Math.PI / 2.8));
            }

            var overlayScene = (OverlayScene)scnView.OverlayScene;

            overlayScene.SpeedNeedle.ZRotation = -(vehicle.SpeedInKilometersPerHour * (float)Math.PI / maxSpeed);
        }
예제 #10
0
        public virtual void Update(ISCNSceneRenderer renderer, double timeInSeconds)
        {
            // delta time since last update
            if (Math.Abs(previousUpdateTime) < float.Epsilon)
            {
                previousUpdateTime = timeInSeconds;
            }

            double deltaTime = Math.Min(Math.Max(1.0 / 60.0, timeInSeconds - previousUpdateTime), 1f);

            previousUpdateTime = timeInSeconds;

            // Reset some states every frame
            maxPenetrationDistance  = 0;
            positionNeedsAdjustment = false;

            SCNVector3 direction       = GameView.CurrentDirection;
            SCNVector3 initialPosition = Character.Node.Position;

            // Move
            if (Math.Abs(direction.X) > float.Epsilon && Math.Abs(direction.Z) > float.Epsilon)
            {
                var characterSpeed = (float)deltaTime * CharacterSpeedFactor * .84f;
                Character.Node.Position = new SCNVector3(
                    initialPosition.X + direction.X * characterSpeed,
                    initialPosition.Y + direction.Y * characterSpeed,
                    initialPosition.Z + direction.Z * characterSpeed
                    );

                // update orientation
                double angle = Math.Atan2(direction.X, direction.Z);
                Character.Direction = (float)angle;
                Character.Walking   = true;
            }
            else
            {
                Character.Walking = false;
            }

            var p0 = Character.Node.Position;
            var p1 = Character.Node.Position;

            p0.Y -= MaxJump;
            p1.Y += MaxRise;

            var options = new SCNPhysicsTest {
                CollisionBitMask = (nuint)(int)(Bitmask.Collision | Bitmask.Water),
                SearchMode       = SCNPhysicsSearchMode.Closest
            };

            SCNHitTestResult[] results = GameView.Scene.PhysicsWorld.RayTestWithSegmentFromPoint(p1, p0, options);
            float groundY = -10;

            if (results.Length > 0)
            {
                SCNHitTestResult result = results [0];
                groundY = result.WorldCoordinates.Y;
                UpdateCameraWithCurrentGround(result.Node);
                SCNMaterial groundMaterial = result.Node.ChildNodes [0].Geometry.FirstMaterial;
                if (grassArea == groundMaterial)
                {
                    Character.CurrentFloorMaterial = FloorMaterial.Grass;
                }
                else if (waterArea == groundMaterial)
                {
                    if (Character.Burning)
                    {
                        Character.Pshhhh();
                        Character.Node.RunAction(SCNAction.Sequence(new [] {
                            SCNAction.PlayAudioSource(pshhhSound, true),
                            SCNAction.PlayAudioSource(aahSound, false)
                        }));
                    }

                    Character.CurrentFloorMaterial = FloorMaterial.Water;

                    options = new SCNPhysicsTest {
                        CollisionBitMask = (nuint)(int)Bitmask.Collision,
                        SearchMode       = SCNPhysicsSearchMode.Closest
                    };

                    results = GameView.Scene.PhysicsWorld.RayTestWithSegmentFromPoint(p1, p0, options);
                    result  = results [0];
                    groundY = result.WorldCoordinates.Y;
                }
                else
                {
                    Character.CurrentFloorMaterial = FloorMaterial.Rock;
                }
            }

//			var nextPosition = Character.Node.Position;
//			const double threshold = 1e-5;
//
//			if (groundY < nextPosition.Y - threshold) {
//				// approximation of acceleration for a delta time
//				accelerationY += (float)(deltaTime * GravityAcceleration);
//				if (groundY < nextPosition.Y - 0.2)
//					Character.CurrentFloorMaterial = FloorMaterial.Air;
//			} else {
//				accelerationY = 0;
//			}
//
//			nextPosition.Y -= accelerationY;
//
//			// reset acceleration if we touch the ground
//			if (groundY > nextPosition.Y) {
//				accelerationY = 0;
//				nextPosition.Y = groundY;
//			}

            // Flames are static physics bodies, but they are moved by an action - So we need to tell the physics engine that the transforms did change.
            foreach (SCNNode flame in flames)
            {
                flame.PhysicsBody.ResetTransform();
            }

            // Adjust the volume of the enemy based on the distance with the character.
            float      distanceToClosestEnemy = float.MaxValue;
            SCNVector3 pos3 = Character.Node.Position;

            foreach (SCNNode enemy in enemies)
            {
                // distance to enemy
                SCNMatrix4 enemyMat      = enemy.WorldTransform;
                var        enemyPosition = new SCNVector3(enemyMat.M41, enemyMat.M42, enemyMat.M43);
                float      distance      = SCNVector3.Subtract(pos3, enemyPosition).Length;
                distanceToClosestEnemy = Math.Min(distanceToClosestEnemy, distance);
            }

            // Adjust sounds volumes based on distance with the enemy.
            if (!gameIsComplete)
            {
                double fireVolume = 0.3 * Math.Max(0.0, Math.Min(1.0, 1.0 - (distanceToClosestEnemy - 1.2) / 1.6));
                var    mixerNode  = flameThrowerSound.AudioNode as AVAudioMixerNode;
                if (mixerNode != null)
                {
                    mixerNode.Volume = (float)fireVolume;
                }
            }
        }