public void AddFace() { var face = new FaceNode(ARSCNFaceGeometry.Create(SCNView.Device)); Faces.Add(face); SCNView.Scene.RootNode.Add(face); face.Position = SCNView.PointOfView.ConvertPositionToNode(new SCNVector3(0, 0, -1), SCNView.Scene.RootNode); var hover = 0.05f; face.RunAction(SCNAction.RepeatActionForever( SCNAction.Sequence(new[] { SCNAction.MoveBy(0, hover, 0, 2).Ease(SCNActionTimingMode.EaseInEaseOut), SCNAction.MoveBy(0, -hover, 0, 2).Ease(SCNActionTimingMode.EaseInEaseOut) }))); }
public void CollectBanana(SCNNode banana) { // Flyoff the banana to the screen space position score label. // Don't increment score until the banana hits the score label. // ignore collisions banana.PhysicsBody = null; BananasCollected++; int variance = 60; nfloat duration = 0.25f; nfloat apexY = worldSpaceLabelScorePosition.Y * 0.8f + (new Random().Next(0, variance) - variance / 2); worldSpaceLabelScorePosition.Z = banana.Position.Z; var apex = new SCNVector3(banana.Position.X + 10 + (new Random().Next(0, variance) - variance / 2), apexY, banana.Position.Z); SCNAction startFlyOff = SCNAction.MoveTo(apex, duration); startFlyOff.TimingMode = SCNActionTimingMode.EaseOut; SCNAction endFlyOff = SCNAction.CustomAction(duration, new SCNActionNodeWithElapsedTimeHandler((node, elapsedTime) => { nfloat t = elapsedTime / duration; var v = new SCNVector3( apex.X + ((worldSpaceLabelScorePosition.X - apex.X) * t), apex.Y + ((worldSpaceLabelScorePosition.Y - apex.Y) * t), apex.X + ((worldSpaceLabelScorePosition.Z - apex.Z) * t)); node.Position = v; })); endFlyOff.TimingMode = SCNActionTimingMode.EaseInEaseOut; SCNAction flyoffSequence = SCNAction.Sequence(new SCNAction[] { startFlyOff, endFlyOff }); banana.RunAction(flyoffSequence, () => { Bananas.Remove(banana); banana.RemoveFromParentNode(); // Add to score. Score++; GameSimulation.Sim.PlaySound("deposit.caf"); // Game Over if (Bananas.Count == 0) { DoGameOver(); } }); }
private void PerformCloseAnimation(bool flash = false) { if (this.isBorderOpen && !this.isAnimating) { this.isBorderOpen = false; this.isAnimating = true; this.borderNode.RemoveAction("pulse"); this.borderNode.Opacity = 1f; // Close animation SCNTransaction.Begin(); SCNTransaction.AnimationDuration = GameBoard.AnimationDuration / 2f; SCNTransaction.AnimationTimingFunction = CAMediaTimingFunction.FromName(CAMediaTimingFunction.EaseOut); this.borderNode.Opacity = 0.99f; SCNTransaction.SetCompletionBlock(() => { SCNTransaction.Begin(); SCNTransaction.AnimationDuration = GameBoard.AnimationDuration / 2f; SCNTransaction.AnimationTimingFunction = CAMediaTimingFunction.FromName(CAMediaTimingFunction.EaseOut); foreach (var segment in this.borderSegments) { segment.Close(); } SCNTransaction.SetCompletionBlock(() => { this.isAnimating = false; }); SCNTransaction.Commit(); }); SCNTransaction.Commit(); if (flash) { var waitAction = SCNAction.Wait(GameBoard.AnimationDuration * 0.75f); var fadeInAction = SCNAction.FadeOpacityTo(0.6f, GameBoard.AnimationDuration * 0.125f); var fadeOutAction = SCNAction.FadeOpacityTo(0f, GameBoard.AnimationDuration * 0.125f); this.FillPlane.RunAction(SCNAction.Sequence(new SCNAction[] { waitAction, fadeOutAction, fadeInAction })); } } }
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) })); }
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() })); } }
public override void OnNodeAddedForAnchor(ISCNSceneRenderer renderer, SCNNode node, ARAnchor anchor) { base.OnNodeAddedForAnchor(renderer, node, anchor); var imageAnchor = anchor as ARImageAnchor; if (imageAnchor == null) { return; } SoundManager.PlaySound("camera"); var anchorTransform = imageAnchor.Transform; var referenceImage = imageAnchor.ReferenceImage; var item = ReferenceLookup[referenceImage]; var next = GetNodeForItem(item.ItemData); next.Position = new SCNVector3(anchorTransform.Column3.X, anchorTransform.Column3.Y + 0.05f, anchorTransform.Column3.Z); NodeLookup[next] = item; var hoverDistance = .025f; var hoverDuration = 2; var up = SCNAction.MoveBy(0, hoverDistance, 0, hoverDuration); var down = SCNAction.MoveBy(0, -hoverDistance, 0, hoverDuration); var seq = SCNAction.Sequence(new[] { up, down }); seq.TimingMode = SCNActionTimingMode.EaseInEaseOut; var hover = SCNAction.RepeatActionForever(seq); next.RunAction(hover); SCNView.Scene.RootNode.AddChildNode(next); }
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); } } }
public override void PresentStep(int index, PresentationViewController presentationViewController) { switch (index) { case (int)ParticleSteps.Fire: TextManager.FlipOutText(SlideTextManager.TextType.Bullet); TextManager.AddEmptyLine(); TextManager.AddBulletAtLevel("Particle Image", 0); TextManager.AddBulletAtLevel("Color over life duration", 0); TextManager.AddBulletAtLevel("Size over life duration", 0); TextManager.AddBulletAtLevel("Several blend modes", 0); TextManager.FlipInText(SlideTextManager.TextType.Bullet); var hole = SCNNode.Create(); hole.Geometry = SCNTube.Create(1.7f, 1.9f, 1.5f); hole.Position = new SCNVector3(0, 0, HOLE_Z); hole.Scale = new SCNVector3(1, 0, 1); GroundNode.AddChildNode(hole); SCNTransaction.Begin(); SCNTransaction.AnimationDuration = 0.5f; hole.Scale = new SCNVector3(1, 1, 1); SCNTransaction.Commit(); var ps = SCNParticleSystem.Create("fire", "Particles"); hole.AddParticleSystem(ps); Hole = hole; break; case (int)ParticleSteps.FireScreen: ps = Hole.ParticleSystems [0]; ps.BlendMode = SCNParticleBlendMode.Screen; break; case (int)ParticleSteps.Local: TextManager.FlipOutText(SlideTextManager.TextType.Bullet); TextManager.AddBulletAtLevel("Local vs Global", 0); TextManager.FlipInText(SlideTextManager.TextType.Bullet); Hole.RemoveAllParticleSystems(); Hole2 = Hole.Clone(); Hole2.Geometry = (SCNGeometry)Hole.Geometry.Copy(); Hole2.Position = new SCNVector3(0, -2, HOLE_Z - 4); GroundNode.AddChildNode(Hole2); SCNTransaction.Begin(); SCNTransaction.AnimationDuration = 0.5; Hole2.Position = new SCNVector3(0, 0, HOLE_Z - 4); SCNTransaction.Commit(); ps = SCNParticleSystem.Create("reactor", "Particles"); ps.ParticleColorVariation = new SCNVector4(0, 0, 0.5f, 0); Hole.AddParticleSystem(ps); var localPs = (SCNParticleSystem)ps.Copy(); localPs.ParticleImage = ps.ParticleImage; localPs.Local = true; Hole2.AddParticleSystem(localPs); var animation = CABasicAnimation.FromKeyPath("position"); animation.From = NSValue.FromVector(new SCNVector3(7, 0, HOLE_Z)); animation.To = NSValue.FromVector(new SCNVector3(-7, 0, HOLE_Z)); animation.BeginTime = CAAnimation.CurrentMediaTime() + 0.75; animation.Duration = 8; animation.AutoReverses = true; animation.RepeatCount = float.MaxValue; animation.TimingFunction = CAMediaTimingFunction.FromName(CAMediaTimingFunction.EaseInEaseOut); animation.TimeOffset = animation.Duration / 2; Hole.AddAnimation(animation, new NSString("animateHole")); animation = CABasicAnimation.FromKeyPath("position"); animation.From = NSValue.FromVector(new SCNVector3(-7, 0, HOLE_Z - 4)); animation.To = NSValue.FromVector(new SCNVector3(7, 0, HOLE_Z - 4)); animation.BeginTime = CAAnimation.CurrentMediaTime() + 0.75; animation.Duration = 8; animation.AutoReverses = true; animation.RepeatCount = float.MaxValue; animation.TimingFunction = CAMediaTimingFunction.FromName(CAMediaTimingFunction.EaseInEaseOut); animation.TimeOffset = animation.Duration / 2; Hole2.AddAnimation(animation, new NSString("animateHole")); break; case (int)ParticleSteps.Gravity: TextManager.FlipOutText(SlideTextManager.TextType.Bullet); TextManager.AddBulletAtLevel("Affected by gravity", 0); TextManager.FlipInText(SlideTextManager.TextType.Bullet); Hole2.RemoveAllParticleSystems(); Hole2.RunAction(SCNAction.Sequence(new SCNAction[] { SCNAction.ScaleTo(0, 0.5), SCNAction.RemoveFromParentNode() })); Hole.RemoveAllParticleSystems(); Hole.RemoveAnimation(new NSString("animateHole"), 0.5f); SCNTransaction.Begin(); SCNTransaction.AnimationDuration = 0.5; var tube = (SCNTube)Hole.Geometry; tube.InnerRadius = 0.3f; tube.OuterRadius = 0.4f; tube.Height = 1.0f; SCNTransaction.Commit(); ps = SCNParticleSystem.Create("sparks", "Particles"); Hole.RemoveAllParticleSystems(); Hole.AddParticleSystem(ps); foreach (var child in ((SCNView)presentationViewController.View).Scene.RootNode.ChildNodes) { if (child.Geometry != null) { if (child.Geometry.GetType() == typeof(SCNFloor)) { FloorNode = child; } } } /*FloorNode = ((SCNView)presentationViewController.View).Scene.RootNode.FindNodes ((SCNNode child, out bool stop) => { * stop = false; * if (child.Geometry != null) * stop = (child.Geometry.GetType () == typeof(SCNFloor)); * return stop; * });*/ /*FloorNode = [presentationViewController.view.scene.rootNode childNodesPassingTest:^BOOL(SCNNode *child, BOOL *stop) { * return [child.geometry isKindOfClass:[SCNFloor class]]; * }][0];*/ ps.ColliderNodes = new SCNNode[] { FloorNode }; break; case (int)ParticleSteps.Collider: TextManager.FlipOutText(SlideTextManager.TextType.Bullet); TextManager.AddBulletAtLevel("Affected by colliders", 0); TextManager.FlipInText(SlideTextManager.TextType.Bullet); var boxNode = SCNNode.Create(); boxNode.Geometry = SCNBox.Create(5, 0.2f, 5, 0); boxNode.Position = new SCNVector3(0, 7, HOLE_Z); boxNode.Geometry.FirstMaterial.Emission.Contents = NSColor.DarkGray; GroundNode.AddChildNode(boxNode); ps = Hole.ParticleSystems [0]; ps.ColliderNodes = new SCNNode[] { FloorNode, boxNode }; animation = CABasicAnimation.FromKeyPath("eulerAngles"); animation.From = NSValue.FromVector(new SCNVector3(0, 0, NMath.PI / 4 * 1.7f)); animation.To = NSValue.FromVector(new SCNVector3(0, 0, -NMath.PI / 4 * 1.7f)); animation.BeginTime = CAAnimation.CurrentMediaTime() + 0.5; animation.Duration = 2; animation.AutoReverses = true; animation.RepeatCount = float.MaxValue; animation.TimingFunction = CAMediaTimingFunction.FromName(CAMediaTimingFunction.EaseInEaseOut); animation.TimeOffset = animation.Duration / 2; boxNode.AddAnimation(animation, new NSString("animateHole")); BoxNode = boxNode; break; case (int)ParticleSteps.Fields: Hole.RemoveAllParticleSystems(); Hole.RunAction(SCNAction.Sequence(new SCNAction[] { SCNAction.ScaleTo(0, 0.75), SCNAction.RemoveFromParentNode() })); BoxNode.RunAction(SCNAction.Sequence(new SCNAction[] { SCNAction.MoveBy(0, 15, 0, 1.0), SCNAction.RemoveFromParentNode() })); var particleHolder = SCNNode.Create(); particleHolder.Position = new SCNVector3(0, 20, HOLE_Z); GroundNode.AddChildNode(particleHolder); ParticleHolder = particleHolder; TextManager.FlipOutText(SlideTextManager.TextType.Bullet); TextManager.AddBulletAtLevel("Affected by physics fields", 0); TextManager.FlipInText(SlideTextManager.TextType.Bullet); ps = SCNParticleSystem.Create("snow", "Particles"); ps.AffectedByPhysicsFields = true; ParticleHolder.AddParticleSystem(ps); Snow = ps; //physics field var field = SCNPhysicsField.CreateTurbulenceField(50, 1); field.HalfExtent = new SCNVector3(20, 20, 20); field.Strength = 4.0f; var fieldOwner = SCNNode.Create(); fieldOwner.Position = new SCNVector3(0, 5, HOLE_Z); GroundNode.AddChildNode(fieldOwner); fieldOwner.PhysicsField = field; FieldOwner = fieldOwner; ps.ColliderNodes = new SCNNode[] { FloorNode }; break; case (int)ParticleSteps.FieldsVortex: VortexFieldOwner = SCNNode.Create(); VortexFieldOwner.Position = new SCNVector3(0, 5, HOLE_Z); GroundNode.AddChildNode(VortexFieldOwner); //tornado var worldOrigin = new SCNVector3(FieldOwner.WorldTransform.M41, FieldOwner.WorldTransform.M42, FieldOwner.WorldTransform.M43); var worldAxis = new SCNVector3(0, 1, 0); var vortex = SCNPhysicsField.CustomField((SCNVector3 position, SCNVector3 velocity, float mass, float charge, double timeInSeconds) => { var l = new SCNVector3(); l.X = worldOrigin.X - position.X; l.Z = worldOrigin.Z - position.Z; SCNVector3 t = Cross(worldAxis, l); var d2 = (l.X * l.X + l.Z * l.Z); var vs = (nfloat)(VS / Math.Sqrt(d2)); var fy = (nfloat)(1.0 - (Math.Min(1.0, (position.Y / 15.0)))); return(new SCNVector3(t.X * vs + l.X * (nfloat)VW * fy, 0, t.Z * vs + l.Z * (nfloat)VW * fy)); }); vortex.HalfExtent = new SCNVector3(100, 100, 100); VortexFieldOwner.PhysicsField = vortex; break; case (int)ParticleSteps.SubSystems: FieldOwner.RemoveFromParentNode(); ParticleHolder.RemoveAllParticleSystems(); Snow.DampingFactor = -1; TextManager.FlipOutText(SlideTextManager.TextType.Bullet); TextManager.AddBulletAtLevel("Sub-particle system on collision", 0); TextManager.FlipInText(SlideTextManager.TextType.Bullet); ps = SCNParticleSystem.Create("rain", "Particles"); var pss = SCNParticleSystem.Create("plok", "Particles"); pss.IdleDuration = 0; pss.Loops = false; ps.SystemSpawnedOnCollision = pss; ParticleHolder.AddParticleSystem(ps); ps.ColliderNodes = new SCNNode[] { FloorNode }; break; case (int)ParticleSteps.Confetti: ParticleHolder.RemoveAllParticleSystems(); TextManager.FlipOutText(SlideTextManager.TextType.Bullet); TextManager.AddBulletAtLevel("Custom blocks", 0); TextManager.FlipInText(SlideTextManager.TextType.Bullet); ps = SCNParticleSystem.Create(); ps.EmitterShape = SCNBox.Create(20, 9, 5, 0); ps.BirthRate = 100; ps.ParticleLifeSpan = 10; ps.ParticleLifeSpanVariation = 0; ps.SpreadingAngle = 20; ps.ParticleSize = 0.25f; ps.ParticleVelocity = 10; ps.ParticleVelocityVariation = 19; ps.BirthDirection = SCNParticleBirthDirection.Constant; ps.EmittingDirection = new SCNVector3(0, -1, 0); ps.BirthLocation = SCNParticleBirthLocation.Volume; ps.ParticleImage = new NSImage(NSBundle.MainBundle.PathForResource("Particles/confetti", "png")); ps.LightingEnabled = true; ps.OrientationMode = SCNParticleOrientationMode.Free; ps.SortingMode = SCNParticleSortingMode.Distance; ps.ParticleAngleVariation = 180; ps.ParticleAngularVelocity = 200; ps.ParticleAngularVelocityVariation = 400; ps.ParticleColor = NSColor.Green; ps.ParticleColorVariation = new SCNVector4(0.2f, 0.1f, 0.1f, 0); ps.ParticleBounce = 0; ps.ParticleFriction = 0.6f; ps.ColliderNodes = new SCNNode[] { FloorNode }; ps.BlendMode = SCNParticleBlendMode.Alpha; var floatAnimation = CAKeyFrameAnimation.FromKeyPath(""); floatAnimation.Values = new NSNumber[] { 1, 1, 0 }; floatAnimation.KeyTimes = new NSNumber[] { 0, 0.9f, 1 }; floatAnimation.Duration = 1.0f; floatAnimation.Additive = false; //ps.PropertyControllers = @{ SCNParticlePropertyOpacity: [SCNParticlePropertyController controllerWithAnimation:floatAnimation] }; //ps.HandleEvent (SCNParticleEvent.Birth, /*[ps handleEvent:SCNParticleEventBirth forProperties:@[SCNParticlePropertyColor] withBlock:^(void **data, size_t *dataStride, uint32_t *indices , NSInteger count) { * * for (int i = 0; i < count; ++i) { * var col = (float *)((char *)data[0] + dataStride[0] * i); * if (rand() & 0x1) { // swith green for red * col[0] = col[1]; * col[1] = 0; * } * * } * }];*/ /*[ps handleEvent:SCNParticleEventCollision forProperties:@[SCNParticlePropertyAngle, SCNParticlePropertyRotationAxis, SCNParticlePropertyAngularVelocity, SCNParticlePropertyVelocity, SCNParticlePropertyContactNormal] withBlock:^(void **data, size_t *dataStride, uint32_t *indices , NSInteger count) { * * for (NSInteger i = 0; i < count; ++i) { * // fix orientation * float *angle = (float *)((char *)data[0] + dataStride[0] * indices[i]); * float *axis = (float *)((char *)data[1] + dataStride[1] * indices[i]); * * float *colNrm = (float *)((char *)data[4] + dataStride[4] * indices[i]); * SCNVector3 collisionNormal = {colNrm[0], colNrm[1], colNrm[2]}; * SCNVector3 cp = SCNVector3CrossProduct(collisionNormal, SCNVector3Make(0, 0, 1)); * CGFloat cpLen = SCNVector3Length(cp); * angle[0] = asin(cpLen); * * axis[0] = cp.x / cpLen; * axis[1] = cp.y / cpLen; * axis[2] = cp.z / cpLen; * * // kill angular rotation * float *angVel = (float *)((char *)data[2] + dataStride[2] * indices[i]); * angVel[0] = 0; * * if (colNrm[1] > 0.4) { * float *vel = (float *)((char *)data[3] + dataStride[3] * indices[i]); * vel[0] = 0; * vel[1] = 0; * vel[2] = 0; * } * } * }];*/ ParticleHolder.AddParticleSystem(ps); break; case (int)ParticleSteps.EmitterCube: ParticleHolder.RemoveAllParticleSystems(); TextManager.FlipOutText(SlideTextManager.TextType.Bullet); TextManager.AddBulletAtLevel("Emitter shape", 0); TextManager.FlipInText(SlideTextManager.TextType.Bullet); ParticleHolder.RemoveFromParentNode(); ps = SCNParticleSystem.Create("emitters", "Particles"); ps.Local = true; ParticleHolder.AddParticleSystem(ps); var node = SCNNode.Create(); node.Position = new SCNVector3(3, 6, HOLE_Z); node.RunAction(SCNAction.RepeatActionForever(SCNAction.RotateBy(NMath.PI * 2, new SCNVector3(0.3f, 1, 0), 8))); GroundNode.AddChildNode(node); Bokeh = ps; node.AddParticleSystem(ps); break; case (int)ParticleSteps.EmitterSphere: Bokeh.EmitterShape = SCNSphere.Create(5); break; case (int)ParticleSteps.EmitterTorus: Bokeh.EmitterShape = SCNTorus.Create(5, 1); break; } }
public override void PresentStep(int index, PresentationViewController presentationViewController) { // Animate by default SCNTransaction.Begin(); SCNTransaction.AnimationDuration = 0; switch (index) { case 0: TextManager.FlipInText(SlideTextManager.TextType.Bullet); break; case 1: TextManager.FlipOutText(SlideTextManager.TextType.Bullet); TextManager.AddEmptyLine(); TextManager.AddCode("#// Rotate forever\n" + "[aNode #runAction:#\n" + " [SCNAction repeatActionForever:\n" + " [SCNAction rotateByX:0 y:M_PI*2 z:0 duration:5.0]]];#"); TextManager.FlipInText(SlideTextManager.TextType.Code); break; case 2: TextManager.FlipOutText(SlideTextManager.TextType.Bullet); TextManager.FlipOutText(SlideTextManager.TextType.Code); TextManager.AddBulletAtLevel("Move", 0); TextManager.AddBulletAtLevel("Rotate", 0); TextManager.AddBulletAtLevel("Scale", 0); TextManager.AddBulletAtLevel("Opacity", 0); TextManager.AddBulletAtLevel("Remove", 0); TextManager.AddBulletAtLevel("Wait", 0); TextManager.AddBulletAtLevel("Custom block", 0); TextManager.FlipInText(SlideTextManager.TextType.Bullet); break; case 3: TextManager.FlipOutText(SlideTextManager.TextType.Bullet); TextManager.AddEmptyLine(); TextManager.AddBulletAtLevel("Directly targets the render tree", 0); TextManager.FlipInText(SlideTextManager.TextType.Bullet); break; case 4: TextManager.AddBulletAtLevel("node.position / node.presentationNode.position", 0); //labels var label1 = TextManager.AddTextAtLevel("Action", 0); label1.Position = new SCNVector3(-15, 3, 0); var label2 = TextManager.AddTextAtLevel("Animation", 0); label2.Position = new SCNVector3(-15, -2, 0); //animation var animNode = SCNNode.Create(); var cubeSize = 4.0f; animNode.Position = new SCNVector3(-5, cubeSize / 2, 0); var cube = SCNBox.Create(cubeSize, cubeSize, cubeSize, 0.05f * cubeSize); cube.FirstMaterial.Diffuse.Contents = new NSImage(NSBundle.MainBundle.PathForResource("SharedTextures/texture", "png")); cube.FirstMaterial.Diffuse.MipFilter = SCNFilterMode.Linear; cube.FirstMaterial.Diffuse.WrapS = SCNWrapMode.Repeat; cube.FirstMaterial.Diffuse.WrapT = SCNWrapMode.Repeat; animNode.Geometry = cube; ContentNode.AddChildNode(animNode); SCNTransaction.Begin(); SCNNode animPosIndicator = null; SCNAnimationEvent startEvt = SCNAnimationEvent.Create(0, (CAAnimation animation, NSObject animatedObject, bool playingBackward) => { SCNTransaction.Begin(); SCNTransaction.AnimationDuration = 0; animPosIndicator.Position = new SCNVector3(10, animPosIndicator.Position.Y, animPosIndicator.Position.Z); SCNTransaction.Commit(); }); SCNAnimationEvent endEvt = SCNAnimationEvent.Create(1, (CAAnimation animation, NSObject animatedObject, bool playingBackward) => { SCNTransaction.Begin(); SCNTransaction.AnimationDuration = 0; animPosIndicator.Position = new SCNVector3(-5, animPosIndicator.Position.Y, animPosIndicator.Position.Z); SCNTransaction.Commit(); }); var anim = CABasicAnimation.FromKeyPath("position.x"); anim.Duration = 3; anim.From = new NSNumber(0.0); anim.To = new NSNumber(15.0); anim.Additive = true; anim.AutoReverses = true; anim.AnimationEvents = new SCNAnimationEvent[] { startEvt, endEvt }; anim.RepeatCount = float.MaxValue; animNode.AddAnimation(anim, new NSString("cubeAnimation")); //action var actionNode = SCNNode.Create(); actionNode.Position = new SCNVector3(-5, cubeSize * 1.5f + 1, 0); actionNode.Geometry = cube; ContentNode.AddChildNode(actionNode); var mv = SCNAction.MoveBy(15, 0, 0, 3); actionNode.RunAction(SCNAction.RepeatActionForever(SCNAction.Sequence(new SCNAction[] { mv, mv.ReversedAction() }))); //position indicator var positionIndicator = SCNNode.Create(); positionIndicator.Geometry = SCNCylinder.Create(0.5f, 0.01f); positionIndicator.Geometry.FirstMaterial.Diffuse.Contents = NSColor.Red; positionIndicator.Geometry.FirstMaterial.LightingModelName = SCNLightingModel.Constant; positionIndicator.EulerAngles = new SCNVector3(NMath.PI / 2, 0, 0); positionIndicator.Position = new SCNVector3(0, 0, cubeSize * 0.5f); actionNode.AddChildNode(positionIndicator); //anim pos indicator animPosIndicator = positionIndicator.Clone(); animPosIndicator.Position = new SCNVector3(5, cubeSize / 2, cubeSize * 0.5f); ContentNode.AddChildNode(animPosIndicator); SCNTransaction.Commit(); break; } SCNTransaction.Commit(); }
public void Update(CameraInfo cameraInfo) { if (this.Delegate == null) { throw new Exception("No delegate"); } // Do not move the lever after it has been activated if (!(this.InteractionToActivate?.IsActivated ?? false)) { if (this.activeSwitch != null) { // Lever Pulling var cameraOffset = this.activeSwitch.PullOffset(cameraInfo.Ray.Position - this.startLeverHoldCameraPosition); var cameraMovedZ = cameraOffset.Z; var targetEulerX = this.startLeverEulerX + LeverPullZtoLeverEulerRotation * cameraMovedZ; targetEulerX = DigitExtensions.Clamp(-LeverMaxEulerX, targetEulerX, LeverMaxEulerX); this.activeSwitch.Angle = targetEulerX; if (targetEulerX <= -LeverMaxEulerX) { // Interaction activation once the switch lever is turned all the way this.InteractionToActivate?.Activate(); // Fade out the switches var waitAction = SCNAction.Wait(3f); var fadeAction = SCNAction.FadeOut(3d); foreach (var resetSwitch in this.resetSwitches) { resetSwitch.Base.RunAction(SCNAction.Sequence(new SCNAction[] { waitAction, fadeAction })); } return; } else { // Inform peers of the movement var leverId = this.resetSwitches.IndexOf(this.activeSwitch); if (leverId == -1) { throw new Exception("No lever in array"); } this.Delegate.DispatchActionToServer(new GameActionType { LeverMove = new LeverMove(leverId, targetEulerX), Type = GameActionType.GActionType.LeverMove }); } } else { // Lever spring back foreach (var lever in this.resetSwitches.Where(lever => lever.Angle < LeverMaxEulerX)) { lever.Angle = Math.Min(LeverMaxEulerX, lever.Angle + LeverSpringBackSpeed * (float)GameTime.DeltaTime); } } // Highlight lever when nearby, otherwise check if we should hide the highlight if (this.highlightedSwitch != null) { if (!this.highlightedSwitch.ShouldHighlight(cameraInfo.Ray)) { this.highlightedSwitch.DoHighlight(false, this.SfxCoordinator); this.highlightedSwitch = null; } } else { foreach (var resetSwitch in this.resetSwitches) { if (resetSwitch.ShouldHighlight(cameraInfo.Ray)) { resetSwitch.DoHighlight(true, this.SfxCoordinator); this.highlightedSwitch = resetSwitch; } } } } }
public override void PresentStep(int index, PresentationViewController presentationViewController) { Step = index; switch (index) { case 0: break; case 1: TextManager.FlipOutText(SlideTextManager.TextType.Bullet); TextManager.SetSubtitle("SCNPhysicsBody"); TextManager.FlipInText(SlideTextManager.TextType.Subtitle); TextManager.AddBulletAtLevel("Dynamic Bodies", 0); // Add some code TextManager.AddCode("#// Make a node dynamic\n" + "aNode.#physicsBody# = [SCNPhysicsBody #dynamicBody#];#"); TextManager.FlipInText(SlideTextManager.TextType.Bullet); TextManager.FlipInText(SlideTextManager.TextType.Code); break; case 2: //add a cube var worldPos = GroundNode.ConvertPositionToNode(new SCNVector3(0, 12, 2), null); var dice = CreateBlock(worldPos, new SCNVector3(1.5f, 1.5f, 1.5f)); dice.PhysicsBody = null; //wait! dice.Rotation = new SCNVector4(0, 0, 1, (float)(Math.PI / 4) * 0.5f); dice.Scale = new SCNVector3(0.001f, 0.001f, 0.001f); ((SCNView)presentationViewController.View).Scene.RootNode.AddChildNode(dice); SCNTransaction.Begin(); SCNTransaction.AnimationDuration = 0.75f; dice.Scale = new SCNVector3(2, 2, 2); SCNTransaction.Commit(); Dices.Add(dice); break; case 3: foreach (var node in Dices) { node.PhysicsBody = SCNPhysicsBody.CreateDynamicBody(); } break; case 4: PresentDices(presentationViewController); break; case 5: TextManager.FlipOutText(SlideTextManager.TextType.Bullet); TextManager.FlipOutText(SlideTextManager.TextType.Code); TextManager.AddBulletAtLevel("Manipulate with forces", 0); // Add some code TextManager.AddCode("#// Apply an impulse\n" + "[aNode.physicsBody #applyForce:#aVector3 #atPosition:#aVector3 #impulse:#YES];#"); TextManager.FlipInText(SlideTextManager.TextType.Bullet); TextManager.FlipInText(SlideTextManager.TextType.Code); break; case 6: // remove dices var center = new SCNVector3(0, -5, 20); center = GroundNode.ConvertPositionToNode(center, null); Explosion(center, Dices); var popTime = new DispatchTime(DispatchTime.Now, (long)(1 * Utils.NSEC_PER_SEC)); DispatchQueue.MainQueue.DispatchAfter(popTime, () => { TextManager.FlipOutText(SlideTextManager.TextType.Code); TextManager.FlipOutText(SlideTextManager.TextType.Bullet); TextManager.AddBulletAtLevel("Static Bodies", 0); TextManager.AddCode("#// Make a node static\n" + "aNode.#physicsBody# = [SCNPhysicsBody #staticBody#];#"); TextManager.FlipInText(SlideTextManager.TextType.Bullet); TextManager.FlipInText(SlideTextManager.TextType.Code); }); break; case 7: PresentWalls(presentationViewController); break; case 8: PresentBalls(presentationViewController); break; case 9: //remove walls var walls = new List <SCNNode> (); GroundNode.EnumerateChildNodes(delegate(SCNNode node, out bool stop) { stop = false; if (node.Name == "container-wall") { node.RunAction(SCNAction.Sequence(new SCNAction [] { SCNAction.MoveBy(new SCNVector3(0, -2, 0), 0.5), SCNAction.RemoveFromParentNode() })); walls.Add(node); } return(stop); }); break; case 10: // remove balls center = new SCNVector3(0, -5, 5); center = GroundNode.ConvertPositionToNode(center, null); Explosion(center, Balls); popTime = new DispatchTime(DispatchTime.Now, (long)(0.5 * Utils.NSEC_PER_SEC)); DispatchQueue.MainQueue.DispatchAfter(popTime, () => { TextManager.FlipOutText(SlideTextManager.TextType.Code); TextManager.FlipOutText(SlideTextManager.TextType.Bullet); TextManager.AddBulletAtLevel("Kinematic Bodies", 0); TextManager.AddCode("#// Make a node kinematic\n" + "aNode.#physicsBody# = [SCNPhysicsBody #kinematicBody#];#"); TextManager.FlipInText(SlideTextManager.TextType.Bullet); TextManager.FlipInText(SlideTextManager.TextType.Code); }); break; case 11: var boxNode = SCNNode.Create(); boxNode.Geometry = SCNBox.Create(10, 0.2f, 10, 0); boxNode.Position = new SCNVector3(0, 5, MIDDLE_Z); boxNode.Geometry.FirstMaterial.Emission.Contents = NSColor.DarkGray; boxNode.PhysicsBody = SCNPhysicsBody.CreateKinematicBody(); boxNode.RunAction(SCNAction.RepeatActionForever(SCNAction.RotateBy(0, 0, NMath.PI * 2, 2.0))); GroundNode.AddChildNode(boxNode); KinematicItems.Add(boxNode); var invisibleWall = SCNNode.Create(); invisibleWall.Geometry = SCNBox.Create(4, 40, 10, 0); invisibleWall.Position = new SCNVector3(-7, 0, MIDDLE_Z); invisibleWall.Geometry.FirstMaterial.Transparency = 0; invisibleWall.PhysicsBody = SCNPhysicsBody.CreateStaticBody(); GroundNode.AddChildNode(invisibleWall); KinematicItems.Add(invisibleWall); invisibleWall = (SCNNode)invisibleWall.Copy(); invisibleWall.Position = new SCNVector3(7, 0, MIDDLE_Z); GroundNode.AddChildNode(invisibleWall); KinematicItems.Add(invisibleWall); invisibleWall = (SCNNode)invisibleWall.Copy(); invisibleWall.Geometry = SCNBox.Create(10, 40, 4, 0); invisibleWall.Geometry.FirstMaterial.Transparency = 0; invisibleWall.Position = new SCNVector3(0, 0, MIDDLE_Z - 7); invisibleWall.PhysicsBody = SCNPhysicsBody.CreateStaticBody(); GroundNode.AddChildNode(invisibleWall); KinematicItems.Add(invisibleWall); invisibleWall = (SCNNode)invisibleWall.Copy(); invisibleWall.Position = new SCNVector3(0, 0, MIDDLE_Z + 7); GroundNode.AddChildNode(invisibleWall); KinematicItems.Add(invisibleWall); for (int i = 0; i < 100; i++) { var ball = SCNNode.Create(); worldPos = boxNode.ConvertPositionToNode(new SCNVector3(RandFloat(-4, 4), RandFloat(10, 30), RandFloat(-1, 4)), null); ball.Position = worldPos; ball.Geometry = SCNSphere.Create(0.5f); ball.Geometry.FirstMaterial.Diffuse.Contents = NSColor.Cyan; ball.PhysicsBody = SCNPhysicsBody.CreateDynamicBody(); ((SCNView)presentationViewController.View).Scene.RootNode.AddChildNode(ball); KinematicItems.Add(ball); } break; case 12: TextManager.FlipOutText(SlideTextManager.TextType.Code); TextManager.FlipOutText(SlideTextManager.TextType.Bullet); TextManager.FlipOutText(SlideTextManager.TextType.Subtitle); TextManager.SetSubtitle("SCNPhysicsShape"); TextManager.AddCode("#// Configure the physics shape\n\n" + "aNode.physicsBody.#physicsShape# = \n\t[#SCNPhysicsShape# shapeWithGeometry:aGeometry options:options];#"); TextManager.FlipInText(SlideTextManager.TextType.Bullet); TextManager.FlipInText(SlideTextManager.TextType.Code); KinematicItems[0].RunAction(SCNAction.Sequence(new SCNAction[] { SCNAction.FadeOut(0.5), SCNAction.RemoveFromParentNode() })); for (int i = 1; i < 5; i++) { KinematicItems[i].RemoveFromParentNode(); } KinematicItems = null; break; case 13: //add meshes PresentMeshes(presentationViewController); break; case 14: // remove meshes center = new SCNVector3(0, -5, 20); center = GroundNode.ConvertPositionToNode(center, null); Explosion(center, Meshes); break; case 15: // add shapes PresentPrimitives(presentationViewController); break; case 16: // remove shapes center = new SCNVector3(0, -5, 20); center = GroundNode.ConvertPositionToNode(center, null); Explosion(center, Shapes); popTime = new DispatchTime(DispatchTime.Now, (long)(0.5 * Utils.NSEC_PER_SEC)); DispatchQueue.MainQueue.DispatchAfter(popTime, () => { TextManager.FlipOutText(SlideTextManager.TextType.Code); TextManager.FlipOutText(SlideTextManager.TextType.Bullet); TextManager.FlipOutText(SlideTextManager.TextType.Subtitle); TextManager.SetSubtitle("SCNPhysicsBehavior"); TextManager.AddCode("#// setup a physics behavior\n\n" + "#SCNPhysicsHingeJoint# *joint = [SCNPhysicsHingeJoint\n\n" + "jointWithBodyA:#nodeA.physicsBody# axisA:[...] anchorA:[...]\n\n" + "bodyB:#nodeB.physicsBody# axisB:[...] anchorB:[...]];\n\n\n" + "[scene.#physicsWorld# addBehavior:joint];#"); TextManager.FlipInText(SlideTextManager.TextType.Bullet); TextManager.FlipInText(SlideTextManager.TextType.Subtitle); TextManager.FlipInText(SlideTextManager.TextType.Code); }); break; case 17: //add meshes PresentHinge(presentationViewController); break; case 18: //remove constraints ((SCNView)presentationViewController.View).Scene.PhysicsWorld.RemoveAllBehaviors(); foreach (var node in Hinges) { node.RunAction(SCNAction.Sequence(new SCNAction[] { SCNAction.Wait(3.0), SCNAction.FadeOut(0.5), SCNAction.RemoveFromParentNode() })); } break; case 19: TextManager.FlipOutText(SlideTextManager.TextType.Bullet); TextManager.FlipOutText(SlideTextManager.TextType.Subtitle); TextManager.FlipOutText(SlideTextManager.TextType.Code); TextManager.SetSubtitle("More..."); TextManager.FlipInText(SlideTextManager.TextType.Subtitle); TextManager.AddBulletAtLevel("SCNPhysicsField", 0); TextManager.AddBulletAtLevel("SCNPhysicsVehicle", 0); TextManager.FlipInText(SlideTextManager.TextType.Bullet); TextManager.FlipInText(SlideTextManager.TextType.Code); break; } }
void StartGame() { if (!gameNodes.HasValue) { throw new InvalidProgramException("Nodes not set"); } var startSequence = SCNAction.Sequence(new SCNAction [] { // Wait for 1 second. SCNAction.Wait(1), SCNAction.Group(new SCNAction[] { SCNAction.FadeIn(0.3), // Start the game. SCNAction.Run(node => { if (!gameNodes.HasValue) { return; } var gNodes = gameNodes.Value; var rnd = new Random(); // Compute a random orientation for the object3D. var theta = (float)(Math.PI * rnd.NextDouble()); var phi = (float)(Math.Acos(2 * rnd.NextDouble() - 1) / NMath.PI); var axis = new Vector3 { X = (float)(Math.Cos(theta) * Math.Sin(phi)), Y = (float)(Math.Sin(theta) * Math.Sin(phi)), Z = (float)Math.Cos(theta) }; var angle = (float)(2 * Math.PI * rnd.NextDouble()); SCNTransaction.Begin(); SCNTransaction.AnimationDuration = 0.3; SCNTransaction.SetCompletionBlock(() => gameStarted = true); gNodes.ObjectMaterial.Transparency = 1; gNodes.Object.Transform = SCNMatrix4.CreateFromAxisAngle(axis, angle); SCNTransaction.Commit(); }) }) }); gameNodes.Value.Object.RunAction(startSequence); // Load and set the background image. var backgroundImage = UIImage.FromBundle("art.scnassets/background.png"); sceneInterface.Scene.Background.Contents = backgroundImage; // Hide particles, set camera projection to orthographic. particleRemovalTimer?.Invalidate(); gameNodes.Value.CongratulationsLabel.RemoveFromParent(); gameNodes.Value.Confetti.Hidden = true; gameNodes.Value.Camera.UsesOrthographicProjection = true; // Reset the countdown. countdown = 30; gameNodes.Value.CountdownLabel.Text = countdown.ToString(); gameNodes.Value.CountdownLabel.FontColor = GameColors.DefaultFont; gameNodes.Value.CountdownLabel.Position = new CGPoint(ContentFrame.Width / 2, ContentFrame.Height - 30); textUpdateTimer?.Invalidate(); textUpdateTimer = NSTimer.CreateRepeatingScheduledTimer(1, UpdateText); }
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; } } }