Merge pull request #236 from xamarin/brumbaug-fox2

Moving ios11/Fox2 samples to mac-ios-samples repo
This commit is contained in:
Brad Umbaugh 2018-05-11 11:40:57 -06:00 коммит произвёл GitHub
Родитель 8ea25021cc c66db2c46d
Коммит 0bf88aad74
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
302 изменённых файлов: 0 добавлений и 7613 удалений

Просмотреть файл

@ -1,123 +0,0 @@

namespace Fox2
{
using CoreAnimation;
using Fox2.Extensions;
using GameplayKit;
using SceneKit;
using System;
/// <summary>
/// This class is used as a base class for all game components.
/// </summary>
public class BaseComponent : GKComponent
{
public static float EnemyAltitude => -0.46f;
public GKAgent2D Agent { get; } = new GKAgent2D();
public bool IsAutoMoveNode { get; set; } = true;
public virtual bool IsDead()
{
return false;
}
public void PositionAgentFromNode()
{
var nodeComponent = base.Entity.GetComponent(typeof(GKSCNNodeComponent)) as GKSCNNodeComponent;
this.Agent.SetTransform(nodeComponent.Node.Transform);
}
public void PositionNodeFromAgent()
{
var nodeComponent = base.Entity.GetComponent(typeof(GKSCNNodeComponent)) as GKSCNNodeComponent;
nodeComponent.Node.Transform = this.Agent.GetTransform();
}
public void ConstrainPosition()
{
var position = this.Agent.Position;
if (position.X > 2f)
{
position.X = 2f;
}
else if (position.X < -2f)
{
position.X = -2f;
}
if (position.Y > 12.5f)
{
position.Y = 12.5f;
}
else if (position.Y < 8.5f)
{
position.Y = 8.5f;
}
this.Agent.Position = position;
}
public override void Update(double deltaTimeInSeconds)
{
if (!this.IsDead())
{
this.Agent.Update(deltaTimeInSeconds);
this.ConstrainPosition();
if (this.IsAutoMoveNode)
{
this.PositionNodeFromAgent();
}
base.Update(deltaTimeInSeconds);
}
}
protected void PerformEnemyDieWithExplosion(SCNNode enemy, SCNVector3 direction)
{
var explositionScene = SCNScene.FromFile("art.scnassets/enemy/enemy_explosion.scn");
if (explositionScene != null)
{
SCNTransaction.Begin();
SCNTransaction.AnimationDuration = 0.4f;
SCNTransaction.AnimationTimingFunction = CAMediaTimingFunction.FromName(CAMediaTimingFunction.EaseOut);
SCNTransaction.SetCompletionBlock(() =>
{
explositionScene.RootNode.EnumerateHierarchy((SCNNode node, out bool stop) =>
{
stop = false;
if (node.ParticleSystems != null)
{
foreach (var particle in node.ParticleSystems)
{
enemy.AddParticleSystem(particle);
}
}
});
// Hide
if (enemy.ChildNodes.Length > 0)
{
enemy.ChildNodes[0].Opacity = 0f;
}
});
direction.Y = 0;
enemy.RemoveAllAnimations();
enemy.EulerAngles = new SCNVector3(enemy.EulerAngles.X, enemy.EulerAngles.X + (float)Math.PI * 4.0f, enemy.EulerAngles.Z);
enemy.WorldPosition += SCNVector3.Normalize(direction) * 1.5f;
this.PositionAgentFromNode();
SCNTransaction.Commit();
}
else
{
Console.WriteLine("Missing enemy_explosion.scn");
}
}
}
}

Просмотреть файл

@ -1,17 +0,0 @@

namespace Fox2
{
[System.Flags]
public enum Bitmask : uint
{
Character = 1 << 0,// the main character
Collision = 1 << 1, // the ground and walls
Enemy = 1 << 2,// the enemies
Trigger = 1 << 3, // the box that triggers camera changes and other actions
Collectable = 1 << 4, // the collectables (gems and key)
}
}

Просмотреть файл

@ -1,848 +0,0 @@

namespace Fox2
{
using CoreFoundation;
using Foundation;
using Fox2.Enums;
using Fox2.Extensions;
using OpenTK;
using SceneKit;
using System;
using System.Collections.Generic;
using System.Linq;
/// <summary>
/// This class manages the main character, including its animations, sounds and direction.
/// </summary>
public class Character : NSObject
{
private static SCNVector3 InitialPosition = new SCNVector3(0.1f, -0.2f, 0f);
private static nfloat SpeedFactor = 2f;
private static int StepsCount = 10;
// some constants
private static float Gravity = 0.004f;
private static float JumpImpulse = 0.1f;
private static float MinAltitude = -10f;
private static bool IsEnableFootStepSound = true;
private static float CollisionMargin = 0.04f;
private static SCNVector3 ModelOffset = new SCNVector3(0f, -Character.CollisionMargin, 0f);
private static float CollisionMeshBitMask = 8f;
// Character handle
private SCNNode characterOrientation; // the node to rotate to orient the character
private SCNNode characterNode; // top level node
private SCNNode model; // the model loaded from the character file
// Physics
private SCNVector3 collisionShapeOffsetFromModel = SCNVector3.Zero;
private SCNPhysicsShape characterCollisionShape;
private float downwardAcceleration = 0f;
// Jump
private SCNVector3 groundNodeLastPosition = SCNVector3.Zero;
private SCNNode groundNode;
private int jumpState = 0;
private float targetAltitude = 0f;
// void playing the step sound too often
private int lastStepFrame = 0;
private int frameCounter = 0;
// Direction
private Vector2 controllerDirection = Vector2.Zero;
private double previousUpdateTime = 0d;
// states
private long lastHitTime = 0L;
private int attackCount = 0;
private bool shouldResetCharacterPosition;
// Particle systems
private SCNParticleSystem jumpDustParticle;
private SCNParticleSystem fireEmitter;
private SCNParticleSystem smokeEmitter;
private SCNParticleSystem whiteSmokeEmitter;
private SCNParticleSystem spinParticle;
private SCNParticleSystem spinCircleParticle;
private SCNNode spinParticleAttach;
private nfloat whiteSmokeEmitterBirthRate = 0f;
private nfloat smokeEmitterBirthRate = 0f;
private nfloat fireEmitterBirthRate = 0f;
// Sound effects
private SCNAudioSource aahSound;
private SCNAudioSource hitSound;
private SCNAudioSource ouchSound;
private SCNAudioSource jumpSound;
private SCNAudioSource attackSound;
private SCNAudioSource hitEnemySound;
private SCNAudioSource catchFireSound;
private SCNAudioSource explodeEnemySound;
private readonly List<SCNAudioSource> steps = new List<SCNAudioSource>(Character.StepsCount);
public Character(SCNScene scene) : base()
{
this.LoadCharacter();
this.LoadParticles();
this.LoadSounds();
this.LoadAnimations();
}
public SCNNode Node => this.characterNode;
public bool IsJump { get; set; }
public float BaseAltitude { get; set; } = 0f;
public SCNPhysicsWorld PhysicsWorld { get; set; }
public Vector2 Direction { get; set; } = new Vector2();
#region Initialization
private void LoadCharacter()
{
// Load character from external file
var scene = SCNScene.FromFile("art.scnassets/character/max.scn");
this.model = scene.RootNode.FindChildNode("Max_rootNode", true);
this.model.Position = Character.ModelOffset;
/* setup character hierarchy
character
|_orientationNode
|_model
*/
this.characterNode = new SCNNode { Name = "character", Position = Character.InitialPosition };
this.characterOrientation = new SCNNode();
this.characterNode.AddChildNode(this.characterOrientation);
this.characterOrientation.AddChildNode(this.model);
var collider = this.model.FindChildNode("collider", true);
if (collider?.PhysicsBody != null)
{
collider.PhysicsBody.CollisionBitMask = (int)(Bitmask.Enemy | Bitmask.Trigger | Bitmask.Collectable);
}
// Setup collision shape
var min = new SCNVector3();
var max = new SCNVector3();
this.model.GetBoundingBox(ref min, ref max);
nfloat collisionCapsuleRadius = (max.X - min.X) * 0.4f;
nfloat collisionCapsuleHeight = max.Y - min.Y;
var collisionGeometry = SCNCapsule.Create(collisionCapsuleRadius, collisionCapsuleHeight);
this.characterCollisionShape = SCNPhysicsShape.Create(collisionGeometry,
new NSMutableDictionary() { { SCNPhysicsShapeOptionsKeys.CollisionMargin, NSNumber.FromFloat(Character.CollisionMargin) } });
this.collisionShapeOffsetFromModel = new SCNVector3(0f, (float)collisionCapsuleHeight * 0.51f, 0f);
}
private void LoadParticles()
{
var particleScene = SCNScene.FromFile("art.scnassets/character/jump_dust.scn");
var particleNode = particleScene.RootNode.FindChildNode("particle", true);
this.jumpDustParticle = particleNode.ParticleSystems.FirstOrDefault();
particleScene = SCNScene.FromFile("art.scnassets/particles/burn.scn");
var burnParticleNode = particleScene.RootNode.FindChildNode("particles", true);
var particleEmitter = new SCNNode();
this.characterOrientation.AddChildNode(particleEmitter);
this.fireEmitter = burnParticleNode.FindChildNode("fire", true).ParticleSystems[0];
this.fireEmitterBirthRate = fireEmitter.BirthRate;
this.fireEmitter.BirthRate = 0f;
this.smokeEmitter = burnParticleNode.FindChildNode("smoke", true).ParticleSystems[0];
this.smokeEmitterBirthRate = smokeEmitter.BirthRate;
this.smokeEmitter.BirthRate = 0f;
this.whiteSmokeEmitter = burnParticleNode.FindChildNode("whiteSmoke", true).ParticleSystems[0];
this.whiteSmokeEmitterBirthRate = whiteSmokeEmitter.BirthRate;
this.whiteSmokeEmitter.BirthRate = 0f;
particleScene = SCNScene.FromFile("art.scnassets/particles/particles_spin.scn");
this.spinParticle = (particleScene.RootNode.FindChildNode("particles_spin", true)?.ParticleSystems?.FirstOrDefault());
this.spinCircleParticle = (particleScene.RootNode.FindChildNode("particles_spin_circle", true)?.ParticleSystems?.FirstOrDefault());
particleEmitter.Position = new SCNVector3(0f, 0.05f, 0f);
particleEmitter.AddParticleSystem(this.fireEmitter);
particleEmitter.AddParticleSystem(this.smokeEmitter);
particleEmitter.AddParticleSystem(this.whiteSmokeEmitter);
this.spinParticleAttach = this.model.FindChildNode("particles_spin_circle", true);
}
private void LoadSounds()
{
this.aahSound = SCNAudioSource.FromFile("audio/aah_extinction.mp3");
this.aahSound.Volume = 1f;
this.aahSound.Positional = false;
this.aahSound.Load();
this.catchFireSound = SCNAudioSource.FromFile("audio/panda_catch_fire.mp3");
this.catchFireSound.Volume = 5f;
this.catchFireSound.Positional = false;
this.catchFireSound.Load();
this.ouchSound = SCNAudioSource.FromFile("audio/ouch_firehit.mp3");
this.ouchSound.Volume = 2f;
this.ouchSound.Positional = false;
this.ouchSound.Load();
this.hitSound = SCNAudioSource.FromFile("audio/hit.mp3");
this.hitSound.Volume = 2f;
this.hitSound.Positional = false;
this.hitSound.Load();
this.hitEnemySound = SCNAudioSource.FromFile("audio/Explosion1.m4a");
this.hitEnemySound.Volume = 2f;
this.hitEnemySound.Positional = false;
this.hitEnemySound.Load();
this.explodeEnemySound = SCNAudioSource.FromFile("audio/Explosion2.m4a");
this.explodeEnemySound.Volume = 2f;
this.explodeEnemySound.Positional = false;
this.explodeEnemySound.Load();
this.jumpSound = SCNAudioSource.FromFile("audio/jump.m4a");
this.jumpSound.Volume = 0.2f;
this.jumpSound.Positional = false;
this.jumpSound.Load();
this.attackSound = SCNAudioSource.FromFile("audio/attack.mp3");
this.attackSound.Volume = 1.0f;
this.attackSound.Positional = false;
this.attackSound.Load();
for (var i = 0; i < Character.StepsCount; i++)
{
var audioSource = SCNAudioSource.FromFile($"audio/Step_rock_0{i}.mp3");
audioSource.Volume = 0.5f;
audioSource.Positional = false;
audioSource.Load();
this.steps.Add(audioSource);
}
}
private void LoadAnimations()
{
var idleAnimation = Character.LoadAnimation("art.scnassets/character/max_idle.scn");
this.model.AddAnimation(idleAnimation, new NSString("idle"));
idleAnimation.Play();
var walkAnimation = Character.LoadAnimation("art.scnassets/character/max_walk.scn");
walkAnimation.Speed = Character.SpeedFactor;
walkAnimation.Stop();
if (Character.IsEnableFootStepSound)
{
walkAnimation.Animation.AnimationEvents = new SCNAnimationEvent[]
{
SCNAnimationEvent.Create(0.1f, (animation, animatedObject, playingBackward) => { this.PlayFootStep(); }),
SCNAnimationEvent.Create(0.6f, (animation, animatedObject, playingBackward) => { this.PlayFootStep(); })
};
}
this.model.AddAnimation(walkAnimation, new NSString("walk"));
var jumpAnimation = Character.LoadAnimation("art.scnassets/character/max_jump.scn");
jumpAnimation.Animation.RemovedOnCompletion = false;
jumpAnimation.Stop();
jumpAnimation.Animation.AnimationEvents = new SCNAnimationEvent[] { SCNAnimationEvent.Create(0f, (animation, animatedObject, playingBackward) => { this.PlayJumpSound(); }) };
this.model.AddAnimation(jumpAnimation, new NSString("jump"));
var spinAnimation = Character.LoadAnimation("art.scnassets/character/max_spin.scn");
spinAnimation.Animation.RemovedOnCompletion = false;
spinAnimation.Speed = 1.5f;
spinAnimation.Stop();
spinAnimation.Animation.AnimationEvents = new SCNAnimationEvent[] { SCNAnimationEvent.Create(0f, (animation, animatedObject, playingBackward) => { this.PlayAttackSound(); }) };
this.model.AddAnimation(spinAnimation, new NSString("spin"));
}
public void QueueResetCharacterPosition()
{
this.shouldResetCharacterPosition = true;
}
#endregion
#region Audio
private bool isBurning;
public bool IsBurning
{
get
{
return this.isBurning;
}
set
{
if (this.isBurning != value)
{
this.isBurning = value;
//walk faster when burning
var oldSpeed = this.WalkSpeed;
this.WalkSpeed = oldSpeed;
if (this.isBurning)
{
this.model.RunAction(SCNAction.Sequence(new SCNAction[]
{
SCNAction.PlayAudioSource(catchFireSound, false),
SCNAction.PlayAudioSource(ouchSound, false),
SCNAction.RepeatActionForever(SCNAction.Sequence(new SCNAction[]
{
SCNAction.FadeOpacityTo(0.01f, 0.1),
SCNAction.FadeOpacityTo(1f, 0.1)
}))
}));
this.whiteSmokeEmitter.BirthRate = 0f;
this.fireEmitter.BirthRate = this.fireEmitterBirthRate;
this.smokeEmitter.BirthRate = this.smokeEmitterBirthRate;
}
else
{
this.model.RemoveAllAudioPlayers();
this.model.RemoveAllActions();
this.model.Opacity = 1f;
this.model.RunAction(SCNAction.PlayAudioSource(aahSound, false));
SCNTransaction.Begin();
SCNTransaction.AnimationDuration = 0f;
this.whiteSmokeEmitter.BirthRate = this.whiteSmokeEmitterBirthRate;
this.fireEmitter.BirthRate = 0f;
this.smokeEmitter.BirthRate = 0f;
SCNTransaction.Commit();
SCNTransaction.Begin();
SCNTransaction.AnimationDuration = 5f;
whiteSmokeEmitter.BirthRate = 0f;
SCNTransaction.Commit();
}
}
}
}
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));
}
}
private void PlayJumpSound()
{
this.characterNode.RunAction(SCNAction.PlayAudioSource(this.jumpSound, false));
}
private void PlayAttackSound()
{
this.characterNode.RunAction(SCNAction.PlayAudioSource(this.attackSound, false));
}
#endregion
#region Controlling the character
private nfloat directionAngle = 0f;
public nfloat DirectionAngle
{
get
{
return this.directionAngle;
}
set
{
this.directionAngle = value;
this.characterOrientation.RunAction(SCNAction.RotateTo(0f, this.directionAngle, 0f, 0.1f, true));
}
}
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);
}
}
}
#endregion
#region Animating the character
private nfloat walkSpeed = 1f;
private bool isWalking;
public bool IsAttacking => this.attackCount > 0;
public bool IsWalking
{
get
{
return this.isWalking;
}
set
{
if (this.isWalking != value)
{
this.isWalking = value;
// Update node animation.
var player = this.model.GetAnimationPlayer(new NSString("walk"));
if (this.isWalking)
{
player?.Play();
}
else
{
player?.StopWithBlendOutDuration(0.2f);
}
}
}
}
public nfloat WalkSpeed
{
get
{
return this.walkSpeed;
}
set
{
this.walkSpeed = value;
var burningFactor = this.IsBurning ? 2f : 1f;
var player = this.model.GetAnimationPlayer(new NSString("walk"));
if (player != null)
{
player.Speed = Character.SpeedFactor * this.walkSpeed * burningFactor;
}
}
}
public void Attack()
{
this.attackCount += 1;
this.model.GetAnimationPlayer(new NSString("spin"))?.Play();
DispatchQueue.MainQueue.DispatchAfter(new DispatchTime(DispatchTime.Now, 5), () =>
{
this.attackCount -= 1;
});
this.spinParticleAttach.AddParticleSystem(this.spinCircleParticle);
}
private SCNVector3 CharacterDirection(SCNNode pointOfView)
{
SCNVector3 result;
var controllerDir = this.Direction;
if (controllerDir.AllZero())
{
result = SCNVector3.Zero;
}
else
{
var directionWorld = SCNVector3.Zero;
if (pointOfView != null)
{
var p1 = pointOfView.PresentationNode.ConvertPositionToNode(new SCNVector3(controllerDir.X, 0f, controllerDir.Y), null);
var p0 = pointOfView.PresentationNode.ConvertPositionToNode(SCNVector3.Zero, null);
directionWorld = p1 - p0;
directionWorld.Y = 0f;
if (directionWorld != SCNVector3.Zero)
{
var minControllerSpeedFactor = 0.2f;
var maxControllerSpeedFactor = 1f;
var speed = controllerDir.Length * (maxControllerSpeedFactor - minControllerSpeedFactor) + minControllerSpeedFactor;
directionWorld = speed * SCNVector3.Normalize(directionWorld);
}
}
result = directionWorld;
}
return result;
}
private void ResetCharacterPosition()
{
this.characterNode.Position = Character.InitialPosition;
this.downwardAcceleration = 0f;
}
#endregion
#region enemy
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)
})
}));
}
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)
}));
}
}
#endregion
#region utils
public static SCNAnimationPlayer LoadAnimation(string sceneName)
{
var scene = SCNScene.FromFile(sceneName);
SCNAnimationPlayer animationPlayer = null;
// find top level animation
scene.RootNode.EnumerateChildNodes((SCNNode child, out bool stop) =>
{
var keys = child.GetAnimationKeys();
if (keys.Any())
{
animationPlayer = child.GetAnimationPlayer(keys[0]);
stop = true;
}
else
{
stop = false;
}
});
return animationPlayer;
}
#endregion
#region physics contact
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;
}
private Tuple<SCNVector3, SCNVector3> HandleSlidingAtContact(SCNPhysicsContact closestContact, SCNVector3 start, SCNVector3 velocity)
{
var originalDistance = velocity.Length;
var colliderPositionAtContact = start + (float)closestContact.SweepTestFraction * velocity;
// Compute the sliding plane.
var slidePlaneNormal = new SCNVector3(closestContact.ContactNormal);
var slidePlaneOrigin = new SCNVector3(closestContact.ContactPoint);
var centerOffset = slidePlaneOrigin - colliderPositionAtContact;
// Compute destination relative to the point of contact.
var destinationPoint = slidePlaneOrigin + velocity;
// We now project the destination point onto the sliding plane.
var distPlane = SCNVector3.Dot(slidePlaneOrigin, slidePlaneNormal);
// Project on plane.
var t = Utils.PlaneIntersect(slidePlaneNormal, distPlane, destinationPoint, slidePlaneNormal);
var normalizedVelocity = velocity * (1f / originalDistance);
var angle = SCNVector3.Dot(slidePlaneNormal, normalizedVelocity);
var frictionCoeff = 0.3f;
if (Math.Abs(angle) < 0.9f)
{
t += (float)10E-3;
frictionCoeff = 1.0f;
}
var newDestinationPoint = (destinationPoint + t * slidePlaneNormal) - centerOffset;
// Advance start position to nearest point without collision.
var computedVelocity = frictionCoeff * (float)(1f - closestContact.SweepTestFraction) * originalDistance * SCNVector3.Normalize(newDestinationPoint - start);
return new Tuple<SCNVector3, SCNVector3>(computedVelocity, colliderPositionAtContact);
}
#endregion
}
}

Просмотреть файл

@ -1,156 +0,0 @@

namespace Fox2
{
using Fox2.Enums;
using GameplayKit;
using OpenTK;
using SceneKit;
using System;
/// <summary>
/// This class implements the chasing behavior.
/// </summary>
public class ChaserComponent : BaseComponent
{
private float maxAcceleration = 8f;
private float hitDistance = 0.5f;
private float chaseDistance = 3f;
private float wanderSpeed = 1f;
private float chaseSpeed = 9f;
private float mass = 0.3f;
private ChaserState state = ChaserState.Chase;
private float speed = 9f;
private GKGoal chaseGoal;
private GKGoal wanderGoal;
private GKGoal centerGoal;
private GKBehavior behavior;
private PlayerComponent player;
public PlayerComponent Player
{
get
{
return this.player;
}
set
{
this.player = value;
this.Agent.Mass = this.mass;
this.Agent.MaxAcceleration = this.maxAcceleration;
this.chaseGoal = GKGoal.GetGoalToSeekAgent(this.player?.Agent);
this.wanderGoal = GKGoal.GetGoalToWander(this.wanderSpeed);
var center = new Vector2[]
{
new Vector2(-1f, 9f),
new Vector2(1f, 9f),
new Vector2(1f, 11f),
new Vector2(-1f, 11f)
};
var path = new GKPath(center, 0.5f, true);
this.centerGoal = GKGoal.GetGoalToStayOnPath(path, 1d);
this.behavior = GKBehavior.FromGoals(new GKGoal[] { this.chaseGoal, this.wanderGoal, this.centerGoal });
this.Agent.Behavior = behavior;
this.StartWandering();
}
}
public override bool IsDead()
{
return this.state == ChaserState.Dead;
}
private void StartWandering()
{
if (this.behavior != null)
{
this.Agent.MaxSpeed = this.wanderSpeed;
this.behavior.SetWeight(1f, this.wanderGoal);
this.behavior.SetWeight(0f, this.chaseGoal);
this.behavior.SetWeight(0.6f, this.centerGoal);
this.state = ChaserState.Wander;
}
}
private void StartChasing()
{
if (this.behavior != null)
{
this.Agent.MaxSpeed = this.speed;
this.behavior.SetWeight(0f, this.wanderGoal);
this.behavior.SetWeight(1f, this.chaseGoal);
this.behavior.SetWeight(0.1f, this.centerGoal);
this.state = ChaserState.Chase;
}
}
public override void Update(double deltaTimeInSeconds)
{
if (this.state != ChaserState.Dead)
{
var character = this.player?.Character;
var playerComponent = this.player?.Entity?.GetComponent(typeof(GKSCNNodeComponent)) as GKSCNNodeComponent;
var nodeComponent = base.Entity?.GetComponent(typeof(GKSCNNodeComponent)) as GKSCNNodeComponent;
if (character != null && playerComponent != null && nodeComponent != null)
{
var enemyNode = nodeComponent.Node;
var playerNode = playerComponent.Node;
var distance = (enemyNode.WorldPosition - playerNode.WorldPosition).Length;
// Chase if below chaseDistance from enemy, wander otherwise.
switch (this.state)
{
case ChaserState.Wander:
if (distance < this.chaseDistance)
{
this.StartChasing();
}
break;
case ChaserState.Chase:
if (distance > this.chaseDistance)
{
this.StartWandering();
}
break;
case ChaserState.Dead:
break;
}
this.speed = Math.Min(this.chaseSpeed, (float)distance);
this.HandleEnemyResponse(character, enemyNode);
base.Update(deltaTimeInSeconds);
}
}
}
private void HandleEnemyResponse(Character character, SCNNode enemy)
{
var direction = enemy.WorldPosition - character.Node.WorldPosition;
if (direction.Length < this.hitDistance)
{
if (character.IsAttacking)
{
this.state = ChaserState.Dead;
character.DidHitEnemy();
this.PerformEnemyDieWithExplosion(enemy, direction);
}
else
{
character.WasTouchedByEnemy();
}
}
}
}
}

Просмотреть файл

@ -1,12 +0,0 @@

namespace Fox2.Enums
{
public enum AudioSourceKind
{
Collect = 1,
CollectBig = 2,
UnlockDoor = 3,
HitEnemy = 4,
TotalCount = 5,
}
}

Просмотреть файл

@ -1,13 +0,0 @@

namespace Fox2.Enums
{
[System.Flags]
public enum Bitmask : uint
{
Character = 1 << 0,// the main character
Collision = 1 << 1, // the ground and walls
Enemy = 1 << 2,// the enemies
Trigger = 1 << 3, // the box that triggers camera changes and other actions
Collectable = 1 << 4, // the collectables (gems and key)
}
}

Просмотреть файл

@ -1,10 +0,0 @@

namespace Fox2.Enums
{
public enum ChaserState
{
Wander,
Chase,
Dead
}
}

Просмотреть файл

@ -1,12 +0,0 @@

namespace Fox2.Enums
{
public enum GroundType
{
Grass,
Rock,
Water,
InTheAir,
Count
}
}

Просмотреть файл

@ -1,13 +0,0 @@

namespace Fox2.Enums
{
public enum ParticleKind
{
Collect,
CollectBig,
KeyApparition,
EnemyExplosion,
UnlockDoor,
TotalCount
}
}

Просмотреть файл

@ -1,10 +0,0 @@

namespace Fox2.Enums
{
public enum ScaredState
{
Wander,
Flee,
Dead
}
}

Просмотреть файл

@ -1,43 +0,0 @@

namespace Fox2.Extensions
{
using GameplayKit;
using OpenTK;
using SceneKit;
using System;
public static class GKAgent2DExtensions
{
public static SCNMatrix4 GetTransform(this GKAgent2D agent)
{
var quat = Quaternion.FromAxisAngle(new Vector3(0, 1, 0), -(agent.Rotation - ((float)Math.PI / 2f)));
var transform = SCNMatrix4.Rotate(quat);
transform.M41 = agent.Position.X;
transform.M42 = BaseComponent.EnemyAltitude;
transform.M43 = agent.Position.Y;
transform.M44 = 1f;
return transform;
}
public static void SetTransform(this GKAgent2D agent, SCNMatrix4 newTransform)
{
var quatf = new SCNQuaternion(newTransform.Column3.Xyz, newTransform.Column3.W);
SCNVector3 axis;
#if !__OSX__
float angle;
quatf.ToAxisAngle(out axis, out angle);
agent.Rotation = -(angle + ((float)Math.PI / 2f));
agent.Position = new Vector2(newTransform.M41, newTransform.M43);
#else
nfloat angle;
quatf.ToAxisAngle(out axis, out angle);
agent.Rotation = -((float)angle + ((float)Math.PI / 2f));
agent.Position = new Vector2((float)newTransform.M41, (float)newTransform.M43);
#endif
}
}
}

Просмотреть файл

@ -1,31 +0,0 @@

namespace Fox2.Extensions
{
using OpenTK;
using SceneKit;
public static class SimdExtensions
{
public static bool AllZero(this SCNVector3 vector3)
{
return vector3.X == 0f && vector3.Y == 0f && vector3.Z == 0f;
}
public static bool AllZero(this Vector2 vector2)
{
return vector2.X == 0f && vector2.Y == 0f;
}
public static SCNVector3 GetPosition(this SCNMatrix4 vector3)
{
return vector3.Column3.Xyz;
}
public static void SetPosition(ref SCNMatrix4 matrix, SCNVector3 value)
{
matrix.M41 = value.X;
matrix.M42 = value.Y;
matrix.M43 = value.Z;
}
}
}

Просмотреть файл

@ -1,20 +0,0 @@

namespace Fox2.Extensions
{
using SceneKit;
public static class Utils
{
/// <summary>
/// Returns plane / ray intersection distance from ray origin.
/// </summary>
#if !__OSX__
public static float PlaneIntersect(SCNVector3 planeNormal, float planeDist, SCNVector3 rayOrigin, SCNVector3 rayDirection)
#else
public static System.nfloat PlaneIntersect(SCNVector3 planeNormal, System.nfloat planeDist, SCNVector3 rayOrigin, SCNVector3 rayDirection)
#endif
{
return (planeDist - SCNVector3.Dot(planeNormal, rayOrigin)) / SCNVector3.Dot(planeNormal, rayDirection);
}
}
}

Просмотреть файл

@ -1,13 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Label="Globals">
<ProjectGuid>96c0a724-8c67-42e4-932e-d053530a640a</ProjectGuid>
<MinimumVisualStudioVersion>14.0</MinimumVisualStudioVersion>
</PropertyGroup>
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.Common.Default.props" />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.Common.props" />
<PropertyGroup />
<Import Project="Fox2.SharedPart.projitems" Label="Shared" />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.CSharp.targets" />
</Project>

Просмотреть файл

@ -1,187 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<MSBuildAllProjects>$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects>
<HasSharedItems>true</HasSharedItems>
<SharedGUID>96c0a724-8c67-42e4-932e-d053530a640a</SharedGUID>
</PropertyGroup>
<PropertyGroup Label="Configuration">
<Import_RootNamespace>Fox2.SharedPart</Import_RootNamespace>
</PropertyGroup>
<ItemGroup>
<Compile Include="$(MSBuildThisFileDirectory)BaseComponent.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Character.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ChaserComponent.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Enums\AudioSourceKind.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Enums\ChaserState.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Enums\GroundType.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Enums\ParticleKind.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Enums\ScaredState.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Extensions\GKAgent2DExtensions.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Extensions\SimdExtensions.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Extensions\Utils.cs" />
<Compile Include="$(MSBuildThisFileDirectory)GameController.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interfaces\IMenuDelegate.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Overlay.cs" />
<Compile Include="$(MSBuildThisFileDirectory)PlayerComponent.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ScaredComponent.cs" />
<Compile Include="$(MSBuildThisFileDirectory)UI\Button.cs" />
<Compile Include="$(MSBuildThisFileDirectory)UI\Menu.cs" />
<Compile Include="$(MSBuildThisFileDirectory)UI\Slider.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Enums\Bitmask.cs" />
</ItemGroup>
<ItemGroup>
<Content Include="$(MSBuildThisFileDirectory)audio\aah_extinction.mp3" />
<Content Include="$(MSBuildThisFileDirectory)audio\ambience.mp3" />
<Content Include="$(MSBuildThisFileDirectory)audio\attack.mp3" />
<Content Include="$(MSBuildThisFileDirectory)audio\collect.mp3" />
<Content Include="$(MSBuildThisFileDirectory)audio\collectBig.mp3" />
<Content Include="$(MSBuildThisFileDirectory)audio\hit.mp3" />
<Content Include="$(MSBuildThisFileDirectory)audio\hitEnemy.wav" />
<Content Include="$(MSBuildThisFileDirectory)audio\Music_victory.mp3" />
<Content Include="$(MSBuildThisFileDirectory)audio\ouch_firehit.mp3" />
<Content Include="$(MSBuildThisFileDirectory)audio\panda_catch_fire.mp3" />
<Content Include="$(MSBuildThisFileDirectory)audio\Step_rock_00.mp3" />
<Content Include="$(MSBuildThisFileDirectory)audio\Step_rock_01.mp3" />
<Content Include="$(MSBuildThisFileDirectory)audio\Step_rock_02.mp3" />
<Content Include="$(MSBuildThisFileDirectory)audio\Step_rock_03.mp3" />
<Content Include="$(MSBuildThisFileDirectory)audio\Step_rock_04.mp3" />
<Content Include="$(MSBuildThisFileDirectory)audio\Step_rock_05.mp3" />
<Content Include="$(MSBuildThisFileDirectory)audio\Step_rock_06.mp3" />
<Content Include="$(MSBuildThisFileDirectory)audio\Step_rock_07.mp3" />
<Content Include="$(MSBuildThisFileDirectory)audio\Step_rock_08.mp3" />
<Content Include="$(MSBuildThisFileDirectory)audio\Step_rock_09.mp3" />
<Content Include="$(MSBuildThisFileDirectory)audio\volcano.mp3" />
<Content Include="$(MSBuildThisFileDirectory)Overlays\collectableBIG_empty.png" />
<Content Include="$(MSBuildThisFileDirectory)Overlays\collectableBIG_full.png" />
<Content Include="$(MSBuildThisFileDirectory)Overlays\congratulations.png" />
<Content Include="$(MSBuildThisFileDirectory)Overlays\congratulations_pandaMax.png" />
<Content Include="$(MSBuildThisFileDirectory)Overlays\dpad.png" />
<Content Include="$(MSBuildThisFileDirectory)Overlays\key_empty.png" />
<Content Include="$(MSBuildThisFileDirectory)Overlays\key_full.png" />
<Content Include="$(MSBuildThisFileDirectory)Overlays\MaxIcon.png" />
</ItemGroup>
<ItemGroup>
<None Include="$(MSBuildThisFileDirectory)audio\Explosion1.m4a" />
<None Include="$(MSBuildThisFileDirectory)audio\Explosion2.m4a" />
<None Include="$(MSBuildThisFileDirectory)audio\jump.m4a" />
<None Include="$(MSBuildThisFileDirectory)audio\unlockTheDoor.m4a" />
</ItemGroup>
<ItemGroup>
<Folder Include="$(MSBuildThisFileDirectory)Resources\" />
<Folder Include="$(MSBuildThisFileDirectory)Overlays\" />
<Folder Include="$(MSBuildThisFileDirectory)art.scnassets\" />
</ItemGroup>
<ItemGroup>
<SceneKitAsset Include="$(MSBuildThisFileDirectory)art.scnassets\character\jump_dust.scn" />
<SceneKitAsset Include="$(MSBuildThisFileDirectory)art.scnassets\character\max.scn" />
<SceneKitAsset Include="$(MSBuildThisFileDirectory)art.scnassets\character\max_AO.png" />
<SceneKitAsset Include="$(MSBuildThisFileDirectory)art.scnassets\character\max_diffuse.png" />
<SceneKitAsset Include="$(MSBuildThisFileDirectory)art.scnassets\character\max_diffuseB.png" />
<SceneKitAsset Include="$(MSBuildThisFileDirectory)art.scnassets\character\max_diffuseC.png" />
<SceneKitAsset Include="$(MSBuildThisFileDirectory)art.scnassets\character\max_diffuseD.png" />
<SceneKitAsset Include="$(MSBuildThisFileDirectory)art.scnassets\character\max_idle.scn" />
<SceneKitAsset Include="$(MSBuildThisFileDirectory)art.scnassets\character\max_jump.scn" />
<SceneKitAsset Include="$(MSBuildThisFileDirectory)art.scnassets\character\max_roughness.png" />
<SceneKitAsset Include="$(MSBuildThisFileDirectory)art.scnassets\character\max_specular.png" />
<SceneKitAsset Include="$(MSBuildThisFileDirectory)art.scnassets\character\max_spin.scn" />
<SceneKitAsset Include="$(MSBuildThisFileDirectory)art.scnassets\character\max_walk.scn" />
<SceneKitAsset Include="$(MSBuildThisFileDirectory)art.scnassets\character\smoke.png" />
<SceneKitAsset Include="$(MSBuildThisFileDirectory)art.scnassets\collision.scn" />
<SceneKitAsset Include="$(MSBuildThisFileDirectory)art.scnassets\enemy\baddy_bad_AO.png" />
<SceneKitAsset Include="$(MSBuildThisFileDirectory)art.scnassets\enemy\baddy_bad_DIFFUSE.png" />
<SceneKitAsset Include="$(MSBuildThisFileDirectory)art.scnassets\enemy\baddy_bad_ILLUMINATION.png" />
<SceneKitAsset Include="$(MSBuildThisFileDirectory)art.scnassets\enemy\baddy_bad_NORMAL.png" />
<SceneKitAsset Include="$(MSBuildThisFileDirectory)art.scnassets\enemy\baddy_fearful_AO.png" />
<SceneKitAsset Include="$(MSBuildThisFileDirectory)art.scnassets\enemy\baddy_fearful_DIFFUSE.png" />
<SceneKitAsset Include="$(MSBuildThisFileDirectory)art.scnassets\enemy\baddy_fearful_ILLUMINATION.png" />
<SceneKitAsset Include="$(MSBuildThisFileDirectory)art.scnassets\enemy\baddy_fearful_NORMAL.png" />
<SceneKitAsset Include="$(MSBuildThisFileDirectory)art.scnassets\enemy\baddy_fearful_ROUGHNESS.png" />
<SceneKitAsset Include="$(MSBuildThisFileDirectory)art.scnassets\enemy\dot.png" />
<SceneKitAsset Include="$(MSBuildThisFileDirectory)art.scnassets\enemy\enemies.scn" />
<SceneKitAsset Include="$(MSBuildThisFileDirectory)art.scnassets\enemy\enemy_explosion.scn" />
<SceneKitAsset Include="$(MSBuildThisFileDirectory)art.scnassets\enemy\enemy1.scn" />
<SceneKitAsset Include="$(MSBuildThisFileDirectory)art.scnassets\enemy\enemy2.scn" />
<SceneKitAsset Include="$(MSBuildThisFileDirectory)art.scnassets\enemy\fireMask.png" />
<SceneKitAsset Include="$(MSBuildThisFileDirectory)art.scnassets\enemy\flare.png" />
<SceneKitAsset Include="$(MSBuildThisFileDirectory)art.scnassets\enemy\gradient.png" />
<SceneKitAsset Include="$(MSBuildThisFileDirectory)art.scnassets\level_scene.scn" />
<SceneKitAsset Include="$(MSBuildThisFileDirectory)art.scnassets\particles\burn.scn" />
<SceneKitAsset Include="$(MSBuildThisFileDirectory)art.scnassets\particles\circle.png" />
<SceneKitAsset Include="$(MSBuildThisFileDirectory)art.scnassets\particles\collect.scnp" />
<SceneKitAsset Include="$(MSBuildThisFileDirectory)art.scnassets\particles\collect-big.scnp" />
<SceneKitAsset Include="$(MSBuildThisFileDirectory)art.scnassets\particles\dot.png" />
<SceneKitAsset Include="$(MSBuildThisFileDirectory)art.scnassets\particles\enemy_explosion.scn" />
<SceneKitAsset Include="$(MSBuildThisFileDirectory)art.scnassets\particles\fire.png" />
<SceneKitAsset Include="$(MSBuildThisFileDirectory)art.scnassets\particles\flare.png" />
<SceneKitAsset Include="$(MSBuildThisFileDirectory)art.scnassets\particles\glow_ellipse.png" />
<SceneKitAsset Include="$(MSBuildThisFileDirectory)art.scnassets\particles\glow01.png" />
<SceneKitAsset Include="$(MSBuildThisFileDirectory)art.scnassets\particles\key_apparition.scn" />
<SceneKitAsset Include="$(MSBuildThisFileDirectory)art.scnassets\particles\particles_spin.scn" />
<SceneKitAsset Include="$(MSBuildThisFileDirectory)art.scnassets\particles\unlock_door.scn" />
<SceneKitAsset Include="$(MSBuildThisFileDirectory)art.scnassets\scene.gks" />
<SceneKitAsset Include="$(MSBuildThisFileDirectory)art.scnassets\scene.scn" />
<SceneKitAsset Include="$(MSBuildThisFileDirectory)art.scnassets\textures\Background_sky.png" />
<SceneKitAsset Include="$(MSBuildThisFileDirectory)art.scnassets\textures\circle.png" />
<SceneKitAsset Include="$(MSBuildThisFileDirectory)art.scnassets\textures\cubeMap4096.png" />
<SceneKitAsset Include="$(MSBuildThisFileDirectory)art.scnassets\textures\depart-vieuxVolcan_AO.png" />
<SceneKitAsset Include="$(MSBuildThisFileDirectory)art.scnassets\textures\depart-vieuxVolcan_lightmap.exr" />
<SceneKitAsset Include="$(MSBuildThisFileDirectory)art.scnassets\textures\depart-vieuxVolcan_lightmap.png" />
<SceneKitAsset Include="$(MSBuildThisFileDirectory)art.scnassets\textures\dot.png" />
<SceneKitAsset Include="$(MSBuildThisFileDirectory)art.scnassets\textures\env_star.png" />
<SceneKitAsset Include="$(MSBuildThisFileDirectory)art.scnassets\textures\fern_diffuse.png" />
<SceneKitAsset Include="$(MSBuildThisFileDirectory)art.scnassets\textures\fern_illumination.png" />
<SceneKitAsset Include="$(MSBuildThisFileDirectory)art.scnassets\textures\fern_roughness.png" />
<SceneKitAsset Include="$(MSBuildThisFileDirectory)art.scnassets\textures\fernSpiral_diffuse.png" />
<SceneKitAsset Include="$(MSBuildThisFileDirectory)art.scnassets\textures\fernSpiral_illumination.png" />
<SceneKitAsset Include="$(MSBuildThisFileDirectory)art.scnassets\textures\fernSpiral_roughness.png" />
<SceneKitAsset Include="$(MSBuildThisFileDirectory)art.scnassets\textures\fire.png" />
<SceneKitAsset Include="$(MSBuildThisFileDirectory)art.scnassets\textures\flowmapPanda.png" />
<SceneKitAsset Include="$(MSBuildThisFileDirectory)art.scnassets\textures\gem.png" />
<SceneKitAsset Include="$(MSBuildThisFileDirectory)art.scnassets\textures\gradient_fire.png" />
<SceneKitAsset Include="$(MSBuildThisFileDirectory)art.scnassets\textures\lava_cold2.png" />
<SceneKitAsset Include="$(MSBuildThisFileDirectory)art.scnassets\textures\lava_hot.png" />
<SceneKitAsset Include="$(MSBuildThisFileDirectory)art.scnassets\textures\lava_medium2.png" />
<SceneKitAsset Include="$(MSBuildThisFileDirectory)art.scnassets\textures\lava_splash01.png" />
<SceneKitAsset Include="$(MSBuildThisFileDirectory)art.scnassets\textures\lavaDry_diffuse.png" />
<SceneKitAsset Include="$(MSBuildThisFileDirectory)art.scnassets\textures\lavaDry_Med_diffuse.png" />
<SceneKitAsset Include="$(MSBuildThisFileDirectory)art.scnassets\textures\lavaDry_Med_diffuse.psd" />
<SceneKitAsset Include="$(MSBuildThisFileDirectory)art.scnassets\textures\lavaDry_roughness.png" />
<SceneKitAsset Include="$(MSBuildThisFileDirectory)art.scnassets\textures\lavalBubble.png" />
<SceneKitAsset Include="$(MSBuildThisFileDirectory)art.scnassets\textures\mobilePlateformBig_diffuse.png" />
<SceneKitAsset Include="$(MSBuildThisFileDirectory)art.scnassets\textures\mobilePlateformBig_roughness.png" />
<SceneKitAsset Include="$(MSBuildThisFileDirectory)art.scnassets\textures\mobilePlateformBig_specular.png" />
<SceneKitAsset Include="$(MSBuildThisFileDirectory)art.scnassets\textures\mobilePT_diffuse.png" />
<SceneKitAsset Include="$(MSBuildThisFileDirectory)art.scnassets\textures\noisemap.png" />
<SceneKitAsset Include="$(MSBuildThisFileDirectory)art.scnassets\textures\planks_albedo.png" />
<SceneKitAsset Include="$(MSBuildThisFileDirectory)art.scnassets\textures\planks_metalness.png" />
<SceneKitAsset Include="$(MSBuildThisFileDirectory)art.scnassets\textures\planks_normal.png" />
<SceneKitAsset Include="$(MSBuildThisFileDirectory)art.scnassets\textures\planks_roughness.png" />
<SceneKitAsset Include="$(MSBuildThisFileDirectory)art.scnassets\textures\plantes_AO.png" />
<SceneKitAsset Include="$(MSBuildThisFileDirectory)art.scnassets\textures\plantes_lightmap.exr" />
<SceneKitAsset Include="$(MSBuildThisFileDirectory)art.scnassets\textures\plantes_lightmap.png" />
<SceneKitAsset Include="$(MSBuildThisFileDirectory)art.scnassets\textures\ripples.png" />
<SceneKitAsset Include="$(MSBuildThisFileDirectory)art.scnassets\textures\rocks_border_diffuse.png" />
<SceneKitAsset Include="$(MSBuildThisFileDirectory)art.scnassets\textures\rocks_border_normal.png" />
<SceneKitAsset Include="$(MSBuildThisFileDirectory)art.scnassets\textures\rocks_border_roughness.png" />
<SceneKitAsset Include="$(MSBuildThisFileDirectory)art.scnassets\textures\rocks_top_diffuse.png" />
<SceneKitAsset Include="$(MSBuildThisFileDirectory)art.scnassets\textures\rocks_top_normal.png" />
<SceneKitAsset Include="$(MSBuildThisFileDirectory)art.scnassets\textures\rocks_top_roughness.png" />
<SceneKitAsset Include="$(MSBuildThisFileDirectory)art.scnassets\textures\sand_diffuse.png" />
<SceneKitAsset Include="$(MSBuildThisFileDirectory)art.scnassets\textures\sand_normal.png" />
<SceneKitAsset Include="$(MSBuildThisFileDirectory)art.scnassets\textures\sand_roughness.png" />
<SceneKitAsset Include="$(MSBuildThisFileDirectory)art.scnassets\textures\sky_cube.exr" />
<SceneKitAsset Include="$(MSBuildThisFileDirectory)art.scnassets\textures\sky_cube.png" />
<SceneKitAsset Include="$(MSBuildThisFileDirectory)art.scnassets\textures\smoke_panda.png" />
<SceneKitAsset Include="$(MSBuildThisFileDirectory)art.scnassets\textures\tile_blue_diffuse.png" />
<SceneKitAsset Include="$(MSBuildThisFileDirectory)art.scnassets\textures\tile_blue_roughness.png" />
<SceneKitAsset Include="$(MSBuildThisFileDirectory)art.scnassets\textures\tile_diffuse.png" />
<SceneKitAsset Include="$(MSBuildThisFileDirectory)art.scnassets\textures\tile_roughness.png" />
<SceneKitAsset Include="$(MSBuildThisFileDirectory)art.scnassets\textures\topLava_diffuse.png" />
<SceneKitAsset Include="$(MSBuildThisFileDirectory)art.scnassets\textures\topLava_normal.png" />
<SceneKitAsset Include="$(MSBuildThisFileDirectory)art.scnassets\textures\topLava_roughness.png" />
<SceneKitAsset Include="$(MSBuildThisFileDirectory)art.scnassets\textures\wall_diffuse.png" />
<SceneKitAsset Include="$(MSBuildThisFileDirectory)art.scnassets\textures\wall_roughness.png" />
<SceneKitAsset Include="$(MSBuildThisFileDirectory)art.scnassets\tile.png" />
</ItemGroup>
</Project>

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -1,14 +0,0 @@

namespace Fox2.Interfaces
{
using Foundation;
public interface IMenuDelegate : INSObjectProtocol
{
void FStopChanged(float value);
void FocusDistanceChanged(float value);
void DebugMenuSelectCameraAtIndex(int index);
}
}

Просмотреть файл

@ -1,224 +0,0 @@

namespace Fox2
{
using CoreGraphics;
using Foundation;
using Fox2.UI;
using SpriteKit;
using System;
using System.Collections.Generic;
/// <summary>
/// This class manages the 2D overlay (score).
/// </summary>
public class Overlay : SKScene
{
private List<SKSpriteNode> collectedGemsSprites;
private SKNode congratulationsGroupNode;
private SKSpriteNode collectedKeySprite;
private SKNode overlayNode;
// demo UI
private Menu demoMenu;
private int collectedGemsCount = 0;
public Overlay(CGSize size, GameController controller) : base(size)
{
this.overlayNode = new SKNode();
var width = size.Width;
var height = size.Height;
this.collectedGemsSprites = new List<SKSpriteNode>();
// Setup the game overlays using SpriteKit.
this.ScaleMode = SKSceneScaleMode.ResizeFill;
this.AddChild(this.overlayNode);
this.overlayNode.Position = new CGPoint(0f, height);
// The Max icon.
var characterNode = SKSpriteNode.FromImageNamed("Overlays/MaxIcon.png");
var menuButton = new Button(characterNode)
{
Position = new CGPoint(50f, -50f),
XScale = 0.5f,
YScale = 0.5f,
};
this.overlayNode.AddChild(menuButton);
menuButton.SetClickedTarget(this.ToggleMenu);
// The Gems
for (int i = 0; i < 1; i++)
{
var gemNode = SKSpriteNode.FromImageNamed("Overlays/collectableBIG_empty.png");
gemNode.Position = new CGPoint(125f + i * 80f, -50f);
gemNode.XScale = 0.25f;
gemNode.YScale = 0.25f;
this.overlayNode.AddChild(gemNode);
this.collectedGemsSprites.Add(gemNode);
}
// The key
this.collectedKeySprite = SKSpriteNode.FromImageNamed("Overlays/key_empty.png");
this.collectedKeySprite.Position = new CGPoint(195f, -50f);
this.collectedKeySprite.XScale = 0.4f;
this.collectedKeySprite.YScale = 0.4f;
this.overlayNode.AddChild(this.collectedKeySprite);
// The virtual D-pad
#if __IOS__
this.ControlOverlay = new ControlOverlay(new CGRect(0f, 0f, width, height));
this.ControlOverlay.LeftPad.Delegate = controller;
this.ControlOverlay.RightPad.Delegate = controller;
this.ControlOverlay.ButtonA.Delegate = controller;
this.ControlOverlay.ButtonB.Delegate = controller;
this.AddChild(this.ControlOverlay);
#endif
// the demo UI
this.demoMenu = new Menu(size)
{
Hidden = true,
Delegate = controller,
};
this.overlayNode.AddChild(this.demoMenu);
// Assign the SpriteKit overlay to the SceneKit view.
base.UserInteractionEnabled = false;
}
public Overlay(NSCoder coder)
{
throw new NotImplementedException("init(coder:) has not been implemented");
}
#if __IOS__
public ControlOverlay ControlOverlay { get; set; }
#endif
public int CollectedGemsCount
{
get
{
return this.collectedGemsCount;
}
set
{
this.collectedGemsCount = value;
this.collectedGemsSprites[this.collectedGemsCount - 1].Texture = SKTexture.FromImageNamed("Overlays/collectableBIG_full.png");
this.collectedGemsSprites[this.collectedGemsCount - 1].RunAction(SKAction.Sequence(new SKAction[] { SKAction.WaitForDuration(0.5f),
SKAction.ScaleBy(1.5f, 0.2f),
SKAction.ScaleBy(1f / 1.5f, 0.2f) }));
}
}
public void Layout2DOverlay()
{
this.overlayNode.Position = new CGPoint(0f, this.Size.Height);
if (this.congratulationsGroupNode != null)
{
this.congratulationsGroupNode.Position = new CGPoint(this.Size.Width * 0.5f, this.Size.Height * 0.5f);
this.congratulationsGroupNode.XScale = 1f;
this.congratulationsGroupNode.YScale = 1f;
var currentBbox = this.congratulationsGroupNode.CalculateAccumulatedFrame();
var margin = 25f;
var bounds = new CGRect(0f, 0f, this.Size.Width, this.Size.Height);
var maximumAllowedBbox = bounds.Inset(margin, margin);
var top = currentBbox.GetMaxY() - this.congratulationsGroupNode.Position.Y;
var bottom = this.congratulationsGroupNode.Position.Y - currentBbox.GetMinY();
var maxTopAllowed = maximumAllowedBbox.GetMaxY() - this.congratulationsGroupNode.Position.Y;
var maxBottomAllowed = this.congratulationsGroupNode.Position.Y - maximumAllowedBbox.GetMinY();
var left = this.congratulationsGroupNode.Position.X - currentBbox.GetMinX();
var right = currentBbox.GetMaxX() - this.congratulationsGroupNode.Position.X;
var maxLeftAllowed = this.congratulationsGroupNode.Position.X - maximumAllowedBbox.GetMinX();
var maxRightAllowed = maximumAllowedBbox.GetMaxX() - this.congratulationsGroupNode.Position.X;
var topScale = top > maxTopAllowed ? maxTopAllowed / top : 1;
var bottomScale = bottom > maxBottomAllowed ? maxBottomAllowed / bottom : 1;
var leftScale = left > maxLeftAllowed ? maxLeftAllowed / left : 1; ;
var rightScale = right > maxRightAllowed ? maxRightAllowed / right : 1;
var scale = NMath.Min(topScale, NMath.Min(bottomScale, NMath.Min(leftScale, rightScale)));
this.congratulationsGroupNode.XScale = scale;
this.congratulationsGroupNode.YScale = scale;
}
}
public void DidCollectKey()
{
this.collectedKeySprite.Texture = SKTexture.FromImageNamed("Overlays/key_full.png");
this.collectedKeySprite.RunAction(SKAction.Sequence(new SKAction[]{ SKAction.WaitForDuration(0.5f),
SKAction.ScaleBy(1.5f, 0.2f),
SKAction.ScaleBy(1f / 1.5f, 0.2f) }));
}
#if __IOS__
public void ShowVirtualPad()
{
this.ControlOverlay.Hidden = false;
}
public void HideVirtualPad()
{
this.ControlOverlay.Hidden = true;
}
#endif
#region Congratulate the player
public void ShowEndScreen()
{
// Congratulation title
var congratulationsNode = SKSpriteNode.FromImageNamed("Overlays/congratulations.png");
// Max image
var characterNode = SKSpriteNode.FromImageNamed("Overlays/congratulations_pandaMax.png");
characterNode.Position = new CGPoint(0f, -220f);
characterNode.AnchorPoint = new CGPoint(0.5f, 0f);
this.congratulationsGroupNode = new SKNode();
this.congratulationsGroupNode.AddChild(characterNode);
this.congratulationsGroupNode.AddChild(congratulationsNode);
this.AddChild(this.congratulationsGroupNode);
// Layout the overlay
this.Layout2DOverlay();
// Animate
congratulationsNode.Alpha = 0f;
congratulationsNode.XScale = 0f;
congratulationsNode.YScale = 0f;
congratulationsNode.RunAction(SKAction.Group(new SKAction[] { SKAction.FadeInWithDuration(0.25),
SKAction.Sequence(new SKAction[] { SKAction.ScaleTo(1.22f, 0.25),
SKAction.ScaleTo(1f, 0.1) }) }));
characterNode.Alpha = 0f;
characterNode.XScale = 0f;
characterNode.YScale = 0f;
characterNode.RunAction(SKAction.Sequence(new SKAction[] { SKAction.WaitForDuration(0.5),
SKAction.Group(new SKAction[] { SKAction.FadeInWithDuration(0.5),
SKAction.Sequence(new SKAction[] { SKAction.ScaleTo(1.22f, 0.25),
SKAction.ScaleTo(1f, 0.1) }) }) }));
}
#endregion
private void ToggleMenu(Button sender)
{
this.demoMenu.Hidden = !this.demoMenu.Hidden;
}
}
}

Двоичные данные
ios11/Fox2/Fox2.Shared/Overlays/MaxIcon.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 21 KiB

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 6.8 KiB

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 19 KiB

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 620 KiB

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 549 KiB

Двоичные данные
ios11/Fox2/Fox2.Shared/Overlays/dpad.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 12 KiB

Двоичные данные
ios11/Fox2/Fox2.Shared/Overlays/key_empty.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 5.0 KiB

Двоичные данные
ios11/Fox2/Fox2.Shared/Overlays/key_full.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 16 KiB

Просмотреть файл

@ -1,17 +0,0 @@

namespace Fox2
{
/// <summary>
/// This class represents the player.
/// </summary>
public class PlayerComponent : BaseComponent
{
public Character Character { get; set; }
public override void Update(double deltaTimeInSeconds)
{
this.PositionAgentFromNode();
base.Update(deltaTimeInSeconds);
}
}
}

Просмотреть файл

@ -1,145 +0,0 @@

namespace Fox2
{
using Fox2.Enums;
using GameplayKit;
using OpenTK;
using SceneKit;
/// <summary>
/// This class implements the scared behavior.
/// </summary>
public class ScaredComponent : BaseComponent
{
private float maxAcceleration = 2.534f;
private float fleeDistance = 2f;
private float wanderSpeed = 1f;
private float mass = 0.326f;
private ScaredState state = ScaredState.Wander;
private GKGoal fleeGoal;
private GKGoal wanderGoal;
private GKGoal centerGoal;
private GKBehavior behavior;
private PlayerComponent player;
public PlayerComponent Player
{
get
{
return this.player;
}
set
{
this.player = value;
this.Agent.Mass = this.mass;
this.Agent.MaxAcceleration = this.maxAcceleration;
this.fleeGoal = GKGoal.GetGoalToFleeAgent(this.player?.Agent);
this.wanderGoal = GKGoal.GetGoalToWander(this.wanderSpeed);
var center = new Vector2[]
{
new Vector2(-1f, 9f),
new Vector2(1f, 9f),
new Vector2(1f, 11f),
new Vector2(-1f, 11f)
};
var path = new GKPath(center, 0.5f, true);
this.centerGoal = GKGoal.GetGoalToStayOnPath(path, 1d);
this.behavior = GKBehavior.FromGoals(new GKGoal[] { this.fleeGoal, this.wanderGoal, this.centerGoal });
this.Agent.Behavior = behavior;
this.StartWandering();
}
}
public override bool IsDead()
{
return this.state == ScaredState.Dead;
}
private void StartWandering()
{
if (this.behavior != null)
{
this.behavior.SetWeight(1f, this.wanderGoal);
this.behavior.SetWeight(0f, this.fleeGoal);
this.behavior.SetWeight(0.3f, this.centerGoal);
this.state = ScaredState.Wander;
}
}
private void StartFleeing()
{
if (this.behavior != null)
{
this.behavior.SetWeight(0f, this.wanderGoal);
this.behavior.SetWeight(1f, this.fleeGoal);
this.behavior.SetWeight(0.4f, this.centerGoal);
this.state = ScaredState.Flee;
}
}
public override void Update(double deltaTimeInSeconds)
{
if (this.state != ScaredState.Dead)
{
var character = this.player?.Character;
var playerComponent = this.player?.Entity?.GetComponent(typeof(GKSCNNodeComponent)) as GKSCNNodeComponent;
var nodeComponent = base.Entity?.GetComponent(typeof(GKSCNNodeComponent)) as GKSCNNodeComponent;
if (character != null && playerComponent != null && nodeComponent != null)
{
var enemyNode = nodeComponent.Node;
var playerNode = playerComponent.Node;
var distance = (enemyNode.WorldPosition - playerNode.WorldPosition).Length;
// Chase if below chaseDistance from enemy, wander otherwise.
switch (this.state)
{
case ScaredState.Wander:
if (distance < this.fleeDistance)
{
this.StartFleeing();
}
break;
case ScaredState.Flee:
if (distance > this.fleeDistance)
{
this.StartWandering();
}
break;
case ScaredState.Dead:
break;
}
this.HandleEnemyResponse(character, enemyNode);
base.Update(deltaTimeInSeconds);
}
}
}
private void HandleEnemyResponse(Character character, SCNNode enemy)
{
var direction = enemy.WorldPosition - character.Node.WorldPosition;
if (direction.Length < 0.5f)
{
if (character.IsAttacking)
{
this.state = ScaredState.Dead;
character.DidHitEnemy();
this.PerformEnemyDieWithExplosion(enemy, direction);
}
else
{
character.WasTouchedByEnemy();
}
}
}
}
}

Просмотреть файл

@ -1,119 +0,0 @@

namespace Fox2.UI
{
using CoreGraphics;
using Foundation;
using SpriteKit;
using System;
#if !__OSX__
using UIKit;
using SKColor = UIKit.UIColor;
#else
using AppKit;
using SKColor = AppKit.NSColor;
#endif
/// <summary>
/// A basic `SKNode` based button.
/// </summary>
public class Button : SKNode
{
private CGSize size = CGSize.Empty;
private Action<Button> actionClicked;
private SKSpriteNode background;
private SKLabelNode label;
public Button(string text) : base()
{
// create a label
var fontName = "Optima-ExtraBlack";
this.label = SKLabelNode.FromFont(fontName);
this.label.Text = text;
this.label.FontSize = 18;
this.label.FontColor = SKColor.White;
this.label.Position = new CGPoint(0f, -8f);
// create the background
this.size = new CGSize(this.label.Frame.Size.Width + 10f, 30f);
this.background = new SKSpriteNode(SKColor.FromCIColor(new CoreImage.CIColor(0f, 0f, 0f, 0.75f)), size);
// add to the root node
this.AddChild(this.background);
this.AddChild(this.label);
// Track mouse event
base.UserInteractionEnabled = true;
}
public Button(SKNode node) : base()
{
// Track mouse event
base.UserInteractionEnabled = true;
this.size = node.Frame.Size;
this.AddChild(node);
}
public Button(NSCoder coder)
{
throw new NotImplementedException("init(coder:) has not been implemented");
}
public nfloat Height => this.size.Height;
public nfloat Width => this.size.Width;
private void SetText(string text)
{
this.label.Text = text;
}
private void SetBackgroundColor(SKColor color)
{
if (this.background != null)
{
this.background.Color = color;
}
}
public void SetClickedTarget(Action<Button> action)
{
this.actionClicked = action;
}
#if __OSX__
public override void MouseDown(NSEvent @event)
{
this.SetBackgroundColor(NSColor.FromRgba(0f, 0f, 0f, 1.0f));
}
public override void MouseUp(NSEvent @event)
{
this.SetBackgroundColor(NSColor.FromRgba(0f, 0f, 0f, 0.75f));
var x = this.Position.X + ((this.Parent?.Position.X) ?? 0f);
var y = this.Position.Y + ((this.Parent?.Position.Y) ?? 0f);
var p = @event.LocationInWindow;
if (Math.Abs(p.X - x) < this.Width / 2 * this.XScale && Math.Abs(p.Y - y) < this.Height / 2 * this.YScale)
{
this.actionClicked.Invoke(this);
}
}
#endif
#if __IOS__
public override void TouchesEnded(NSSet touches, UIEvent @event)
{
this.actionClicked.Invoke(this);
}
#endif
}
}

Просмотреть файл

@ -1,166 +0,0 @@

namespace Fox2.UI
{
using CoreGraphics;
using Foundation;
using Fox2.Interfaces;
using SpriteKit;
using System;
using System.Collections.Generic;
using System.Linq;
/// <summary>
/// The `SKNode` based menu.
/// </summary>
public class Menu : SKNode
{
private readonly List<Button> cameraButtons = new List<Button>();
private readonly List<Slider> dofSliders = new List<Slider>();
private const float ButtonMargin = 250f;
private const float Duration = 0.3f;
private const float MenuY = 40f;
private bool isMenuHidden;
public Menu(CGSize size) : base()
{
// Track mouse event
base.UserInteractionEnabled = true;
// Camera buttons
var buttonLabels = new string[] { "Camera 1", "Camera 2", "Camera 3" };
this.cameraButtons = buttonLabels.Select(label => new Button(label)).ToList();
for (int i = 0; i < this.cameraButtons.Count; i++)
{
var button = this.cameraButtons[i];
var x = button.Width / 2 + (i > 0 ? this.cameraButtons[i - 1].Position.X + this.cameraButtons[i - 1].Width / 2 + 10 : ButtonMargin);
var y = size.Height - MenuY;
button.Position = new CGPoint(x, y);
button.SetClickedTarget(this.MenuChanged);
this.AddChild(button);
}
// Depth of Field
buttonLabels = new string[] { "fStop", "Focus" };
this.dofSliders = buttonLabels.Select(label => new Slider(300, 10, label)).ToList();
for (int i = 0; i < dofSliders.Count; i++)
{
var slider = dofSliders[i];
slider.Position = new CGPoint(ButtonMargin, size.Height - i * 30.0f - 70.0f);
slider.Alpha = 0.0f;
this.AddChild(slider);
}
this.dofSliders[0].SetClickedTarget(this.CameraFStopChanged);
this.dofSliders[1].SetClickedTarget(this.CameraFocusDistanceChanged);
}
public Menu(NSCoder coder)
{
throw new NotImplementedException("init(coder:) has not been implemented");
}
public IMenuDelegate Delegate { get; set; }
public override bool Hidden
{
get
{
return this.isMenuHidden;
}
set
{
this.isMenuHidden = value;
if (this.isMenuHidden)
{
this.Hide();
}
else
{
this.Show();
}
}
}
private void MenuChanged(Button sender)
{
this.HideSlidersMenu();
var index = this.cameraButtons.IndexOf(sender);
if (index >= 0)
{
this.Delegate?.DebugMenuSelectCameraAtIndex(index);
if (index == 2)
{
this.ShowSlidersMenu();
}
}
}
private void Show()
{
foreach (var button in this.cameraButtons)
{
button.Alpha = 0.0f;
button.RunAction(SKAction.FadeInWithDuration(Duration));
}
this.isMenuHidden = false;
}
private void Hide()
{
foreach (var button in this.cameraButtons)
{
button.Alpha = 1.0f;
button.RunAction(SKAction.FadeOutWithDuration(Duration));
}
this.HideSlidersMenu();
this.isMenuHidden = true;
}
private void HideSlidersMenu()
{
foreach (var slider in this.dofSliders)
{
slider.RunAction(SKAction.FadeOutWithDuration(Duration));
}
}
private void ShowSlidersMenu()
{
foreach (var slider in this.dofSliders)
{
slider.RunAction(SKAction.FadeInWithDuration(Duration));
}
this.dofSliders[0].Value = 0.1f;
this.dofSliders[1].Value = 0.5f;
this.CameraFStopChanged(this.dofSliders[0]);
this.CameraFocusDistanceChanged(this.dofSliders[1]);
}
private void CameraFStopChanged(object sender)
{
if (this.Delegate != null)
{
this.Delegate.FStopChanged(this.dofSliders[0].Value + 0.2f);
}
}
private void CameraFocusDistanceChanged(object sender)
{
if (this.Delegate != null)
{
this.Delegate.FocusDistanceChanged(this.dofSliders[1].Value * 20.0f + 3.0f);
}
}
}
}

Просмотреть файл

@ -1,144 +0,0 @@

namespace Fox2.UI
{
using CoreGraphics;
using Foundation;
using SpriteKit;
using System;
#if __IOS__
using UIKit;
using SKColor = UIKit.UIColor;
#elif __OSX__
using AppKit;
using SKColor = AppKit.NSColor;
#else
using SKColor = UIKit.UIColor;
#endif
/// <summary>
/// A basic `SKNode` based slider.
/// </summary>
public class Slider : SKNode
{
private Action<Slider> actionClicked;
private SKSpriteNode background;
private SKLabelNode label;
private SKShapeNode slider;
private float value = 0f;
public Slider(int width, int height, string text) : base()
{
// create a label
var fontName = "Optima-ExtraBlack";
this.label = SKLabelNode.FromFont(fontName);
this.label.Text = text;
this.label.FontSize = 18;
this.label.FontColor = SKColor.White;
this.label.Position = new CGPoint(0f, -8f);
// create background & slider
this.background = new SKSpriteNode(SKColor.White, new CGSize(width, 2f));
this.slider = SKShapeNode.FromCircle(height);
this.slider.FillColor = SKColor.White;
this.background.AnchorPoint = new CGPoint(0f, 0.5f);
this.slider.Position = new CGPoint(this.label.Frame.Size.Width / 2f + 15f, 0f);
this.background.Position = new CGPoint(this.label.Frame.Size.Width / 2f + 15f, 0f);
// add to the root node
this.AddChild(this.label);
this.AddChild(this.background);
this.AddChild(this.slider);
// track mouse event
base.UserInteractionEnabled = true;
this.Value = 0f;
}
public Slider(NSCoder coder)
{
throw new NotImplementedException("init(coder:) has not been implemented");
}
public nfloat Width => this.background.Frame.Size.Width;
public nfloat Height => this.slider.Frame.Size.Height;
public float Value
{
get
{
return this.value;
}
set
{
this.value = value;
this.slider.Position = new CGPoint(this.background.Position.X + this.value * this.Width, 0f);
}
}
private void SetBackgroundColor(SKColor color)
{
if (this.background != null)
{
background.Color = color;
}
}
public void SetClickedTarget(Action<Slider> action)
{
this.actionClicked = action;
}
#if __OSX__
public override void MouseDown(NSEvent @event)
{
this.MouseDragged(@event);
}
public override void MouseUp(NSEvent @event)
{
this.SetBackgroundColor(SKColor.White);
}
public override void MouseDragged(NSEvent @event)
{
this.SetBackgroundColor(SKColor.Gray);
var posInView = this.Scene.ConvertPointFromNode(this.Position, this.Parent);
var x = @event.LocationInWindow.X - posInView.X - this.background.Position.X;
var pos = NMath.Min(NMath.Min(x, this.Width), 0f);
this.slider.Position = new CGPoint(this.background.Position.X + pos, 0f);
this.Value = (float)(pos / this.Width);
this.actionClicked.Invoke(this);
}
#endif
#if __IOS__
public override void TouchesMoved(NSSet touches, UIEvent @event)
{
this.SetBackgroundColor(UIColor.Gray);
var first = touches.ToArray<UITouch>()[0];
var x = first.LocationInNode(this).X - this.background.Position.X;
var position = Math.Max(NMath.Min(x, this.Width), 0f);
this.slider.Position = new CGPoint(this.background.Position.X + position, 0f);
this.Value = (float)(position / this.Width);
this.actionClicked.Invoke(this);
}
#endif
}
}

Двоичный файл не отображается.

Двоичный файл не отображается.

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 46 KiB

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 235 KiB

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 247 KiB

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 243 KiB

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 176 KiB

Двоичный файл не отображается.

Двоичный файл не отображается.

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 72 KiB

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 8.2 KiB

Двоичный файл не отображается.

Двоичный файл не отображается.

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 12 KiB

Двоичный файл не отображается.

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 131 KiB

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 108 KiB

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 74 KiB

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 393 KiB

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 82 KiB

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 164 KiB

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 96 KiB

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 261 KiB

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 172 KiB

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 911 B

Двоичный файл не отображается.

Двоичный файл не отображается.

Двоичный файл не отображается.

Двоичный файл не отображается.

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 36 KiB

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 54 KiB

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 17 KiB

Двоичный файл не отображается.

Двоичный файл не отображается.

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 18 KiB

Двоичный файл не отображается.

Двоичный файл не отображается.

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 911 B

Двоичный файл не отображается.

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 14 KiB

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 54 KiB

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 65 KiB

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 4.8 KiB

Двоичный файл не отображается.

Двоичный файл не отображается.

Двоичный файл не отображается.

Двоичные данные
ios11/Fox2/Fox2.Shared/art.scnassets/scene.gks

Двоичный файл не отображается.

Двоичные данные
ios11/Fox2/Fox2.Shared/art.scnassets/scene.scn

Двоичный файл не отображается.

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 5.4 MiB

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 19 KiB

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 123 KiB

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 320 KiB

Двоичный файл не отображается.

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 440 KiB

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 911 B

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 5.7 KiB

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 42 KiB

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 8.7 KiB

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 16 KiB

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 53 KiB

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 9.5 KiB

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 17 KiB

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 27 KiB

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 373 KiB

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 2.7 KiB

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 17 KiB

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 1.2 MiB

Двоичный файл не отображается.

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 590 KiB

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше