void CollectFlower(SCNNode node)
        {
            if (node.ParentNode == null)
            {
                return;
            }

            SCNNode soundEmitter = SCNNode.Create();

            soundEmitter.Position = node.Position;
            node.ParentNode.AddChildNode(soundEmitter);
            soundEmitter.RunAction(SCNAction.Sequence(new [] {
                SCNAction.PlayAudioSource(collectFlowerSound, true),
                SCNAction.RemoveFromParentNode()
            }));

            node.RemoveFromParentNode();

            // Check if game is complete.
            bool gameComplete = GameView.DidCollectAFlower();

            // Edit some particles.
            SCNMatrix4 particlePosition = soundEmitter.WorldTransform;

            particlePosition.M42 += 0.1f;
            GameView.Scene.AddParticleSystem(collectParticles, particlePosition);

            if (gameComplete)
            {
                ShowEndScreen();
            }
        }
Exemple #2
0
        public void PlayFootStep()
        {
            if (CurrentFloorMaterial == FloorMaterial.Air)
            {
                return;                 // We are in the air, no sound to play
            }
            int stepSoundIndex = Math.Min(StepsSoundCount - 1, new Random().Next(0, 32767) * StepsSoundCount);

            Node.RunAction(SCNAction.PlayAudioSource(steps[stepSoundIndex, (int)CurrentFloorMaterial], false));
        }
Exemple #3
0
 private void PlayFootStep()
 {
     if (this.groundNode != null && this.IsWalking)
     {
         // We are in the air, no sound to play.
         // Play a random step sound.
         int randSnd        = (new Random().Next(0, 32767) * Character.StepsCount);
         var stepSoundIndex = Math.Min(Character.StepsCount - 1, randSnd);
         characterNode.RunAction(SCNAction.PlayAudioSource(this.steps[stepSoundIndex], false));
     }
 }
Exemple #4
0
 public void DidHitEnemy()
 {
     this.model.RunAction(SCNAction.Group(new SCNAction[]
     {
         SCNAction.PlayAudioSource(this.hitEnemySound, false),
         SCNAction.Sequence(new SCNAction[]
         {
             SCNAction.Wait(0.5),
             SCNAction.PlayAudioSource(explodeEnemySound, false)
         })
     }));
 }
Exemple #5
0
        public void WasTouchedByEnemy()
        {
            var time = DateTime.UtcNow.Ticks;

            if (time > this.lastHitTime + 1d)
            {
                this.lastHitTime = time;
                this.model.RunAction(SCNAction.Sequence(new SCNAction[]
                {
                    SCNAction.PlayAudioSource(this.hitSound, false),
                    SCNAction.RepeatAction(SCNAction.Sequence(new SCNAction[]
                    {
                        SCNAction.FadeOpacityTo(0.01f, 0.1f),
                        SCNAction.FadeOpacityTo(1f, 0.1f)
                    }), 4)
                }));
            }
        }
        void CollectPearl(SCNNode node)
        {
            if (node.ParentNode == null)
            {
                return;
            }

            SCNNode soundEmitter = SCNNode.Create();

            soundEmitter.Position = node.Position;
            node.ParentNode.AddChildNode(soundEmitter);
            soundEmitter.RunAction(SCNAction.Sequence(new [] {
                SCNAction.PlayAudioSource(collectPearlSound, true),
                SCNAction.RemoveFromParentNode()
            }));

            node.RemoveFromParentNode();
            GameView.DidCollectAPearl();
        }
        void WasHit()
        {
            if (isInvincible)
            {
                return;
            }

            isInvincible = true;
            Character.Hit();

            Character.Node.RunAction(SCNAction.Sequence(new [] {
                SCNAction.PlayAudioSource(hitSound, false),
                SCNAction.RepeatAction(SCNAction.Sequence(new [] {
                    SCNAction.FadeOpacityTo(.01f, 0.1),
                    SCNAction.FadeOpacityTo(1f, 0.1)
                }), 7),
                SCNAction.Run(_ => isInvincible = false)
            }));
        }
Exemple #8
0
        public void Update(double time, ISCNSceneRenderer renderer)
        {
            this.frameCounter += 1;

            if (this.shouldResetCharacterPosition)
            {
                this.shouldResetCharacterPosition = false;
                this.ResetCharacterPosition();
            }
            else
            {
                var characterVelocity = SCNVector3.Zero;

                // setup
                var groundMove = SCNVector3.Zero;

                // did the ground moved?
                if (this.groundNode != null)
                {
                    var groundPosition = groundNode.WorldPosition;
                    groundMove = groundPosition - this.groundNodeLastPosition;
                }

                characterVelocity = new SCNVector3(groundMove.X, 0, groundMove.Z);

                var direction = this.CharacterDirection(renderer.PointOfView);

                if (this.previousUpdateTime == 0d)
                {
                    this.previousUpdateTime = time;
                }

                var deltaTime         = time - previousUpdateTime;
                var characterSpeed    = (nfloat)deltaTime * Character.SpeedFactor * this.WalkSpeed;
                var virtualFrameCount = (int)(deltaTime / (1d / 60d));
                this.previousUpdateTime = time;

                // move
                if (!direction.AllZero())
                {
                    characterVelocity = direction * (float)characterSpeed;
                    var runModifier = 1f;

#if __OSX__
                    // TODO: UI thread exception
                    //if (AppKit.NSEvent.CurrentModifierFlags.HasFlag(AppKit.NSEventModifierMask.ShiftKeyMask))
                    //{
                    //   runModifier = 2f;
                    //}
#endif
                    this.WalkSpeed = (nfloat)(runModifier * direction.Length);

                    // move character
                    this.DirectionAngle = (nfloat)Math.Atan2(direction.X, direction.Z);

                    this.IsWalking = true;
                }
                else
                {
                    this.IsWalking = false;
                }

                // put the character on the ground
                var up        = new SCNVector3(0f, 1f, 0f);
                var wPosition = this.characterNode.WorldPosition;
                // gravity
                this.downwardAcceleration -= Character.Gravity;
                wPosition.Y += downwardAcceleration;
                var HIT_RANGE = 0.2f;
                var p0        = wPosition;
                var p1        = wPosition;
                p0.Y = wPosition.Y + up.Y * HIT_RANGE;
                p1.Y = wPosition.Y - up.Y * HIT_RANGE;

                var options = new NSMutableDictionary <NSString, NSObject>()
                {
                    { SCNHitTest.BackFaceCullingKey, NSObject.FromObject(false) },
                    { SCNHitTest.OptionCategoryBitMaskKey, NSNumber.FromFloat(Character.CollisionMeshBitMask) },
                    { SCNHitTest.IgnoreHiddenNodesKey, NSObject.FromObject(false) }
                };

                var hitFrom   = new SCNVector3(p0);
                var hitTo     = new SCNVector3(p1);
                var hitResult = renderer.Scene.RootNode.HitTest(hitFrom, hitTo, options).FirstOrDefault();

                var wasTouchingTheGroup = this.groundNode != null;
                this.groundNode = null;
                var touchesTheGround = false;
                var wasBurning       = this.IsBurning;

                var hit = hitResult;
                if (hit != null)
                {
                    var ground = new SCNVector3(hit.WorldCoordinates);
                    if (wPosition.Y <= ground.Y + Character.CollisionMargin)
                    {
                        wPosition.Y = ground.Y + Character.CollisionMargin;
                        if (this.downwardAcceleration < 0f)
                        {
                            this.downwardAcceleration = 0f;
                        }
                        this.groundNode  = hit.Node;
                        touchesTheGround = true;

                        //touching lava?
                        this.IsBurning = this.groundNode?.Name == "COLL_lava";
                    }
                }
                else
                {
                    if (wPosition.Y < Character.MinAltitude)
                    {
                        wPosition.Y = Character.MinAltitude;
                        //reset
                        this.QueueResetCharacterPosition();
                    }
                }

                this.groundNodeLastPosition = this.groundNode != null ? this.groundNode.WorldPosition : SCNVector3.Zero;

                //jump -------------------------------------------------------------
                if (this.jumpState == 0)
                {
                    if (this.IsJump && touchesTheGround)
                    {
                        this.downwardAcceleration += Character.JumpImpulse;
                        this.jumpState             = 1;

                        this.model.GetAnimationPlayer(new NSString("jump"))?.Play();
                    }
                }
                else
                {
                    if (this.jumpState == 1 && !this.IsJump)
                    {
                        this.jumpState = 2;
                    }

                    if (this.downwardAcceleration > 0f)
                    {
                        for (int i = 0; i < virtualFrameCount; i++)
                        {
                            downwardAcceleration *= this.jumpState == 1 ? 0.99f : 0.2f;
                        }
                    }

                    if (touchesTheGround)
                    {
                        if (!wasTouchingTheGroup)
                        {
                            this.model.GetAnimationPlayer(new NSString("jump"))?.StopWithBlendOutDuration(0.1);

                            // trigger jump particles if not touching lava
                            if (this.IsBurning)
                            {
                                this.model.FindChildNode("dustEmitter", true)?.AddParticleSystem(this.jumpDustParticle);
                            }
                            else
                            {
                                // jump in lava again
                                if (wasBurning)
                                {
                                    this.characterNode.RunAction(SCNAction.Sequence(new SCNAction[]
                                    {
                                        SCNAction.PlayAudioSource(this.catchFireSound, false),
                                        SCNAction.PlayAudioSource(this.ouchSound, false)
                                    }));
                                }
                            }
                        }

                        if (!this.IsJump)
                        {
                            this.jumpState = 0;
                        }
                    }
                }

                if (touchesTheGround && !wasTouchingTheGroup && !this.IsBurning && this.lastStepFrame < this.frameCounter - 10)
                {
                    // sound
                    this.lastStepFrame = frameCounter;
                    this.characterNode.RunAction(SCNAction.PlayAudioSource(this.steps[0], false));
                }

                if (wPosition.Y < this.characterNode.Position.Y)
                {
                    wPosition.Y = this.characterNode.Position.Y;
                }

                //------------------------------------------------------------------

                // progressively update the elevation node when we touch the ground
                if (touchesTheGround)
                {
                    this.targetAltitude = (float)wPosition.Y;
                }

                this.BaseAltitude *= 0.95f;
                this.BaseAltitude += this.targetAltitude * 0.05f;

                characterVelocity.Y += this.downwardAcceleration;
                if (characterVelocity.LengthSquared > 10E-4 * 10E-4)
                {
                    var startPosition = this.characterNode.PresentationNode.WorldPosition + this.collisionShapeOffsetFromModel;
                    this.SlideInWorld(startPosition, characterVelocity);
                }
            }
        }
Exemple #9
0
 private void PlayAttackSound()
 {
     this.characterNode.RunAction(SCNAction.PlayAudioSource(this.attackSound, false));
 }
        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;
                }
            }
        }