Rozhraní API pro hry pro iOS v Xamarin.iOS

Tento článek popisuje nová vylepšení her poskytovaná iOSem 9, která lze použít ke zlepšení grafiky a zvukových funkcí hry Xamarin.iOS.

Společnost Apple provedla několik technologických vylepšení rozhraní API pro hry v iOSu 9, která usnadňují implementaci herní grafiky a zvuku v aplikaci Xamarin.iOS. Patří mezi ně snadné vývoje prostřednictvím architektur vysoké úrovně a využití výkonu GPU zařízení s iOSem pro lepší rychlost a grafické schopnosti.

An example of an app running flocking

To zahrnuje HerníKit, ReplayKit, Model I/O, MetalKit a Metal Performance Shadery spolu s novými, vylepšenými funkcemi Metal, SceneKit a SpriteKit.

Tento článek vám představí všechny způsoby, jak vylepšit hru Xamarin.iOS s novými vylepšeními her pro iOS 9:

Představení sady GameplayKit

Nová architektura GamesKit společnosti Apple poskytuje sadu technologií, které usnadňují vytváření her pro zařízení s iOSem snížením množství opakujících se běžných kódů potřebných k implementaci. GameKit poskytuje nástroje pro vývoj herní mechaniky, které lze snadno kombinovat s grafickým modulem (například SceneKit nebo SpriteKit) k rychlému doručení dokončené hry.

GameKit obsahuje několik běžných, herních algoritmů, jako jsou:

  • Simulace agentů založená na chování, která umožňuje definovat pohyby a cíle, které bude AI automaticky sledovat.
  • A minmax artificial intelligence for turn-based game play.
  • Systém pravidel pro logiku her řízenou daty s přibližným důvodem pro zajištění nově vznikajícího chování.

Herní sada GameKit navíc využívá přístup k vývoji her stavebním blokem pomocí modulární architektury, která poskytuje následující funkce:

  • Stavový stroj pro zpracování složitých procedurálních systémů založených na kódu ve hře.
  • Nástroje pro poskytování náhodného hraní her a neprediktovatelnosti, aniž by to způsobilo problémy s laděním.
  • Opakovaně použitelná architektura založená na komponentách na entitách.

Další informace o Nástroji GameplayKit najdete v průvodci programováním sady Gameplaykit společnosti Apple a referenční informace k architektuře GameplayKit.

Příklady sady GameplayKit

Pojďme se rychle podívat na implementaci některé jednoduché mechaniky hraní her v aplikaci Xamarin.iOS pomocí sady herních her.

Pathfinding

Pathfinding je schopnost AI prvku hry najít cestu kolem herní desky. Například 2D nepřítel našel cestu přes bludiště nebo 3D postavu přes terén první osoby-střelec světa.

Představte si následující mapu:

An example pathfinding map

Pomocí pathfinding tohoto kódu jazyka C# můžete najít cestu přes mapu:

var a = GKGraphNode2D.FromPoint (new Vector2 (0, 5));
var b = GKGraphNode2D.FromPoint (new Vector2 (3, 0));
var c = GKGraphNode2D.FromPoint (new Vector2 (2, 6));
var d = GKGraphNode2D.FromPoint (new Vector2 (4, 6));
var e = GKGraphNode2D.FromPoint (new Vector2 (6, 5));
var f = GKGraphNode2D.FromPoint (new Vector2 (6, 0));

a.AddConnections (new [] { b, c }, false);
b.AddConnections (new [] { e, f }, false);
c.AddConnections (new [] { d }, false);
d.AddConnections (new [] { e, f }, false);

var graph = GKGraph.FromNodes(new [] { a, b, c, d, e, f });

var a2e = graph.FindPath (a, e); // [ a, c, d, e ]
var a2f = graph.FindPath (a, f); // [ a, b, f ]

Console.WriteLine(String.Join ("->", (object[]) a2e));
Console.WriteLine(String.Join ("->", (object[]) a2f));

Klasický expertní systém

Následující fragment kódu jazyka C# ukazuje, jak lze Pomocí Sady GameplayKit implementovat klasický expertní systém:

string output = "";
bool reset = false;
int input = 15;

public override void ViewDidLoad ()
{
    base.ViewDidLoad ();

    /*
    If reset is true, clear the output and set reset to false
    */
    var clearRule = GKRule.FromPredicate ((rules) => reset, rules => {
        output = "";
        reset = false;
    });
    clearRule.Salience = 1;

    var fizzRule = GKRule.FromPredicate (mod (3), rules => {
        output += "fizz";
    });
    fizzRule.Salience = 2;

    var buzzRule = GKRule.FromPredicate (mod (5), rules => {
        output += "buzz";
    });
    buzzRule.Salience = 2;

    /*
    This *always* evaluates to true, but is higher Salience, so evaluates after lower-salience items
    (which is counter-intuitive). Print the output, and reset (thus triggering "ResetRule" next time)
    */
    var outputRule = GKRule.FromPredicate (rules => true, rules => {
        System.Console.WriteLine(output == "" ? input.ToString() : output);
        reset = true;
    });
    outputRule.Salience = 3;

    var rs = new GKRuleSystem ();
    rs.AddRules (new [] {
        clearRule,
        fizzRule,
        buzzRule,
        outputRule
    });

    for (input = 1; input < 16; input++) {
        rs.Evaluate ();
        rs.Reset ();
    }
}

protected Func<GKRuleSystem, bool> mod(int m)
{
    Func<GKRuleSystem,bool> partiallyApplied = (rs) => input % m == 0;
    return partiallyApplied;
}

Na základě dané sady pravidel (GKRule) a známé sady vstupů vytvoří expertní systém (GKRuleSystem) předvídatelný výstup (fizzbuzz v našem příkladu výše).

Flockovacích

Hejna umožňuje skupině entit kontrolovaných pomocí umělé inteligence chovat se jako hejno, kde skupina reaguje na pohyby a akce hlavní entity, jako je hejn ptáků v letu nebo škola plavání ryb.

Následující fragment kódu jazyka C# implementuje chování hejna pomocí Sady GameplayKit a SpriteKit pro grafické zobrazení:

using System;
using SpriteKit;
using CoreGraphics;
using UIKit;
using GameplayKit;
using Foundation;
using System.Collections.Generic;
using System.Linq;
using OpenTK;

namespace FieldBehaviorExplorer
{
    public static class FlockRandom
    {
        private static GKARC4RandomSource rand = new GKARC4RandomSource ();

        static FlockRandom ()
        {
            rand.DropValues (769);
        }

        public static float NextUniform ()
        {
            return rand.GetNextUniform ();
        }
    }

    public class FlockingScene : SKScene
    {
        List<Boid> boids = new List<Boid> ();
        GKComponentSystem componentSystem;
        GKAgent2D trackingAgent; //Tracks finger on screen
        double lastUpdateTime = Double.NaN;
        //Hold on to behavior so it doesn't get GC'ed
        static GKBehavior flockingBehavior;
        static GKGoal seekGoal;

        public FlockingScene (CGSize size) : base (size)
        {
            AddRandomBoids (20);

            var scale = 0.4f;
            //Flocking system
            componentSystem = new GKComponentSystem (typeof(GKAgent2D));
            var behavior = DefineFlockingBehavior (boids.Select (boid => boid.Agent).ToArray<GKAgent2D>(), scale);
            boids.ForEach (boid => {
                boid.Agent.Behavior = behavior;
                componentSystem.AddComponent(boid.Agent);
            });

            trackingAgent = new GKAgent2D ();
            trackingAgent.Position = new Vector2 ((float) size.Width / 2.0f, (float) size.Height / 2.0f);
            seekGoal = GKGoal.GetGoalToSeekAgent (trackingAgent);
        }

        public override void TouchesBegan (NSSet touches, UIEvent evt)
        {
            boids.ForEach(boid => boid.Agent.Behavior.SetWeight(1.0f, seekGoal));
        }

        public override void TouchesEnded (NSSet touches, UIEvent evt)
        {
            boids.ForEach (boid => boid.Agent.Behavior.SetWeight (0.0f, seekGoal));
        }

        public override void TouchesMoved (NSSet touches, UIEvent evt)
        {
            var touch = (UITouch) touches.First();
            var loc = touch.LocationInNode (this);
            trackingAgent.Position = new Vector2((float) loc.X, (float) loc.Y);
        }

        private void AddRandomBoids (int count)
        {
            var scale = 0.4f;
            for (var i = 0; i < count; i++) {
                var b = new Boid (UIColor.Red, this.Size, scale);
                boids.Add (b);
                this.AddChild (b);
            }
        }

        internal static GKBehavior DefineFlockingBehavior(GKAgent2D[] boidBrains, float scale)
        {
            if (flockingBehavior == null) {
                var flockingGoals = new GKGoal[3];
                flockingGoals [0] = GKGoal.GetGoalToSeparate (boidBrains, 100.0f * scale, (float)Math.PI * 8.0f);
                flockingGoals [1] = GKGoal.GetGoalToAlign (boidBrains, 40.0f * scale, (float)Math.PI * 8.0f);
                flockingGoals [2] = GKGoal.GetGoalToCohere (boidBrains, 40.0f * scale, (float)Math.PI * 8.0f);

                flockingBehavior = new GKBehavior ();
                flockingBehavior.SetWeight (25.0f, flockingGoals [0]);
                flockingBehavior.SetWeight (10.0f, flockingGoals [1]);
                flockingBehavior.SetWeight (10.0f, flockingGoals [2]);
            }
            return flockingBehavior;
        }

        public override void Update (double currentTime)
        {
            base.Update (currentTime);
            if (Double.IsNaN(lastUpdateTime)) {
                lastUpdateTime = currentTime;
            }
            var delta = currentTime - lastUpdateTime;
            componentSystem.Update (delta);
        }
    }

    public class Boid : SKNode, IGKAgentDelegate
    {
        public GKAgent2D Agent { get { return brains; } }
        public SKShapeNode Sprite { get { return sprite; } }

        class BoidSprite : SKShapeNode
        {
            public BoidSprite (UIColor color, float scale)
            {
                var rot = CGAffineTransform.MakeRotation((float) (Math.PI / 2.0f));
                var path = new CGPath ();
                path.MoveToPoint (rot, new CGPoint (10.0, 0.0));
                path.AddLineToPoint (rot, new CGPoint (0.0, 30.0));
                path.AddLineToPoint (rot, new CGPoint (10.0, 20.0));
                path.AddLineToPoint (rot, new CGPoint (20.0, 30.0));
                path.AddLineToPoint (rot, new CGPoint (10.0, 0.0));
                path.CloseSubpath ();

                this.SetScale (scale);
                this.Path = path;
                this.FillColor = color;
                this.StrokeColor = UIColor.White;

            }
        }

        private GKAgent2D brains;
        private BoidSprite sprite;
        private static int boidId = 0;

        public Boid (UIColor color, CGSize size, float scale)
        {
            brains = BoidBrains (size, scale);
            sprite = new BoidSprite (color, scale);
            sprite.Position = new CGPoint(brains.Position.X, brains.Position.Y);
            sprite.ZRotation = brains.Rotation;
            sprite.Name = boidId++.ToString ();

            brains.Delegate = this;

            this.AddChild (sprite);
        }

        private GKAgent2D BoidBrains(CGSize size, float scale)
        {
            var brains = new GKAgent2D ();
            var x = (float) (FlockRandom.NextUniform () * size.Width);
            var y = (float) (FlockRandom.NextUniform () * size.Height);
            brains.Position = new Vector2 (x, y);

            brains.Rotation = (float)(FlockRandom.NextUniform () * Math.PI * 2.0);
            brains.Radius = 30.0f * scale;
            brains.MaxSpeed = 0.5f;
            return brains;
        }

        [Export ("agentDidUpdate:")]
        public void AgentDidUpdate (GameplayKit.GKAgent agent)
        {
        }

        [Export ("agentWillUpdate:")]
        public void AgentWillUpdate (GameplayKit.GKAgent agent)
        {
            var brainsIn = (GKAgent2D) agent;
            sprite.Position = new CGPoint(brainsIn.Position.X, brainsIn.Position.Y);
            sprite.ZRotation = brainsIn.Rotation;
            Console.WriteLine ($"{sprite.Name} -> [{sprite.Position}], {sprite.ZRotation}");
        }
    }
}

Dále implementujte tuto scénu v kontroleru zobrazení:

public override void ViewDidLoad ()
{
    base.ViewDidLoad ();
        // Perform any additional setup after loading the view, typically from a nib.
        this.View = new SKView {
        ShowsFPS = true,
        ShowsNodeCount = true,
        ShowsDrawCount = true
    };
}

public override void ViewWillLayoutSubviews ()
{
    base.ViewWillLayoutSubviews ();

    var v = (SKView)View;
    if (v.Scene == null) {
        var scene = new FlockingScene (View.Bounds.Size);
        scene.ScaleMode = SKSceneScaleMode.AspectFill;
        v.PresentScene (scene);
    }
}

Když poběžíte, malé animované "Boids" se bude pohybovat kolem prstu klepnutí:

The little animated Boids will flock around the finger taps

Další příklady Apple

Kromě výše uvedených ukázek poskytuje Apple následující ukázkové aplikace, které je možné překódovat do C# a Xamarin.iOS:

Kov

V iOSu 9 společnost Apple provedla několik změn a dodatků k metalu, aby poskytovala přístup k GPU s nízkou režií. Pomocí nástroje Metal můžete maximalizovat grafický a výpočetní potenciál vašich aplikací pro iOS.

Architektura Metal zahrnuje následující nové funkce:

  • Nové soukromé a hloubkové textury vzorníku pro OS X.
  • Vylepšená kvalita stínu s hloubkovým upínacím a samostatným předním a zadním vzorníkem.
  • Vylepšení standardní knihovny pro stínování kovů.
  • Výpočetní shadery podporují širší rozsah formátů pixelů.

Architektura MetalKitu

Architektura MetalKit poskytuje sadu tříd nástrojů a funkcí, které snižují množství práce potřebné k použití metalu v aplikaci pro iOS. MetalKit poskytuje podporu ve třech klíčových oblastech:

  1. Asynchronní načítání textury z různých zdrojů, včetně běžných formátů, jako jsou PNG, JPEG, KTX a PVR.
  2. Snadný přístup k prostředkům založeným na vstupně-výstupních operacích pro zpracování modelů specifických pro kov. Tyto funkce jsou vysoce optimalizované tak, aby poskytovaly efektivní přenos dat mezi vstupně-výstupními sítěmi modelu a kovovými vyrovnávacími paměťmi.
  3. Předdefinovaná zobrazení a správa zobrazení, která výrazně snižují množství kódu potřebného k zobrazení grafických vykreslování v aplikaci pro iOS.

Další informace o nástroji MetalKit najdete v referenční příručce k platformě MetalKit Framework společnosti Apple, průvodci programováním kovu, referenční příručce k metalovým rozhraním a jazyku stínování kovů.

Architektura shaderů výkonu kovu

Architektura Metal Performance Shader poskytuje vysoce optimalizovanou sadu grafických a výpočetních shaderů pro použití v metalových aplikacích pro iOS. Každý shader v rozhraní Metal Performance Shader byl speciálně vyladěn tak, aby poskytoval vysoký výkon na grafických procesorech iOS podporovaných systémem iOS.

Pomocí tříd shaderu výkonu kovu můžete dosáhnout nejvyššího možného výkonu u každého konkrétního gpu iOS, aniž byste museli cílit na jednotlivé základy kódu a udržovat je. Shadery výkonu kovu lze použít s libovolným kovovým prostředkem, jako jsou textury a vyrovnávací paměti.

Rozhraní Metal Performance Shader poskytuje sadu běžných shaderů, jako jsou:

  • Gaussian Blur (MPSImageGaussianBlur)
  • Detekce Sobel Edge (MPSImageSobel)
  • Histogram obrázku (MPSImageHistogram)

Další informace najdete v průvodci jazykem stínování kovů společnosti Apple.

Představení vstupně-výstupních operací modelu

Architektura Model I/O společnosti Apple poskytuje podrobné znalosti o 3D prostředcích (jako jsou modely a jejich související prostředky). Vstupně-výstupní modely poskytují hry s iOSem s fyzickými materiály, modely a osvětlením, které lze použít s GamesKitem, Metalem a SceneKitem.

V/V modelu můžete podporovat následující typy úloh:

  • Importujte osvětlení, materiály, mesh data, nastavení kamery a další informace založené na scéně z různých oblíbených formátů softwaru a herních motorů.
  • Zpracování nebo generování informací založených na scéně, jako je vytvoření procedurálně texturovaných kopií nebo pečení osvětlení do sítě.
  • Pracuje s MetalKitem, SceneKitem a GLKitem k efektivnímu načítání herních prostředků do vyrovnávací paměti GPU pro vykreslování.
  • Exportujte informace založené na scéně do různých oblíbených formátů softwaru a herních motorů.

Další informace o vstupně-výstupních operacích modelů najdete v referenčních informacích k rozhraní Modelu a V Framework společnosti Apple .

Představení sady ReplayKit

Nová architektura ReplayKit společnosti Apple umožňuje snadno přidat záznam hry do hry pro iOS a umožnit uživateli rychle a snadno upravovat a sdílet toto video z aplikace.

Další informace najdete na webu Apple Going Social with ReplayKit a Game Center video a jejich DemoBots: Building a Cross Platform Game with SpriteKit and GameKit sample app.

SceneKit

Sada scén je rozhraní API pro graf 3D scény, které zjednodušuje práci s 3D grafikou. Poprvé byla představena v OS X 10.8 a nyní přišla na iOS 8. Díky sadě Scene Kit vytvářející imerzivní 3D vizualizace a neformální 3D hry nevyžadují odborné znalosti v OpenGL. Sada Scene Kit s využitím běžných konceptů grafů scény abstrahuje složitosti OpenGL a OpenGL ES, což usnadňuje přidávání 3D obsahu do aplikace. Pokud jste však odborníkem na OpenGL, sada Scene Kit má skvělou podporu pro vázání přímo s OpenGL. Zahrnuje také celou řadu funkcí, které doplňují 3D grafiku, jako je fyzika, a integruje se velmi dobře s několika dalšími architekturami Apple, jako je Core Animation, Core Image a Sprite Kit.

Další informace najdete v naší dokumentaci k souboru SceneKit .

Změny sady SceneKit

Apple přidal do sady SceneKit pro iOS 9 následující nové funkce:

  • Xcode teď nabízí Editor scén, který umožňuje rychle vytvářet hry a interaktivní 3D aplikace úpravou scén přímo z Xcode.
  • Třídy SCNView lze SCNSceneRenderer použít k povolení vykreslování počítačů (na podporovaných zařízeních s iOSem).
  • SCNNode Třídy SCNAudioPlayer lze použít k přidání prostorových zvukových efektů, které automaticky sledují pozici přehrávače do aplikace pro iOS.

Další informace najdete v naší dokumentaci k SceneKitu a referenční informace k architektuře SceneKit společnosti Apple a Fox: Sestavení hry SceneKit pomocí ukázkového projektu editoru scén Xcode.

SpriteKit

Sprite Kit, 2D herní architektura od Společnosti Apple, má některé zajímavé nové funkce v iOS 8 a OS X Yosemite. Patří mezi ně integrace se sadou Scene Kit, podpora shaderu, osvětlení, stíny, omezení, normální generování map a vylepšení fyziky. Zejména nové fyzikální funkce usnadňují přidání realistických efektů do hry.

Další informace najdete v naší dokumentaci k SpriteKitu .

Změny sady SpriteKit

Společnost Apple přidala do SpriteKitu pro iOS 9 následující nové funkce:

  • Prostorový zvukový efekt, který automaticky sleduje pozici přehrávače s SKAudioNode třídou.
  • Xcode teď nabízí Editor scén a Editor akcí pro snadné vytváření 2D her a aplikací.
  • Snadná podpora posouvání her s novými objekty Kamera Nodes (SKCameraNode).
  • Na zařízeních s iOSem, která podporují Metal, ji SpriteKit automaticky použije k vykreslování, i když jste už používali vlastní shadery OpenGL ES.

Další informace najdete v naší dokumentaci ke SpriteKit Frameworku společnosti Apple spriteKit Framework a jejich DemoBots: Vytvoření hry pro různé platformy pomocí SpriteKit a ukázkové aplikace GameKit .

Shrnutí

Tento článek se zabývá novými funkcemi hraní her, které iOS 9 poskytuje pro vaše aplikace Xamarin.iOS. Představila herníkit a vstupně-výstupní operace modelu; hlavní vylepšení kovu; a nové funkce SceneKitu a SpriteKitu.