Beispiel #1
0
        private void SlideInWorld(SCNVector3 start, SCNVector3 velocity)
        {
            var maxSlideIteration = 4;
            var iteration         = 0;
            var stop = false;

            var replacementPoint = start;

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

            while (!stop)
            {
                var from = SCNMatrix4.Identity;
                SimdExtensions.SetPosition(ref from, start);

                var to = SCNMatrix4.Identity;
                SimdExtensions.SetPosition(ref to, start + velocity);

                var contacts = this.PhysicsWorld.ConvexSweepTest(this.characterCollisionShape, from, to, options.Dictionary);
                if (contacts.Any())
                {
                    (velocity, start) = this.HandleSlidingAtContact(contacts.FirstOrDefault(), start, velocity);
                    iteration        += 1;

                    if (velocity.LengthSquared <= (10E-3 * 10E-3) || iteration >= maxSlideIteration)
                    {
                        replacementPoint = start;
                        stop             = true;
                    }
                }
                else
                {
                    replacementPoint = start + velocity;
                    stop             = true;
                }
            }

            this.characterNode.WorldPosition = replacementPoint - this.collisionShapeOffsetFromModel;
        }
		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;
			}
		}
        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;
                }
            }
        }