Bagikan melalui


API Game iOS di Xamarin.iOS

Artikel ini membahas peningkatan game baru yang disediakan oleh iOS 9 yang dapat digunakan untuk meningkatkan fitur grafis dan audio game Xamarin.iOS Anda.

Apple telah melakukan beberapa peningkatan teknologi pada API game di iOS 9 yang memudahkan penerapan grafis dan audio game di aplikasi Xamarin.iOS. Ini termasuk kemudahan pengembangan melalui kerangka kerja tingkat tinggi dan memanfaatkan kekuatan GPU perangkat iOS untuk meningkatkan kecepatan dan kemampuan grafis.

Contoh aplikasi yang menjalankan flocking

Ini termasuk GameplayKit, ReplayKit, Model I/O, MetalKit dan Metal Performance Shaders bersama dengan fitur baru yang disempurnakan dari Metal, SceneKit dan SpriteKit.

Artikel ini akan memperkenalkan semua cara untuk meningkatkan game Xamarin.iOS Anda dengan peningkatan game baru iOS 9:

Memperkenalkan GameplayKit

Kerangka kerja GameplayKit baru Apple menyediakan serangkaian teknologi yang memudahkan untuk membuat game untuk perangkat iOS dengan mengurangi jumlah kode umum berulang yang diperlukan untuk implementasi. GameplayKit menyediakan alat untuk mengembangkan mekanika game yang kemudian dapat dengan mudah dikombinasikan dengan mesin grafis (seperti SceneKit atau SpriteKit) untuk dengan cepat memberikan game yang lengkap.

GameplayKit mencakup beberapa, umum, algoritma permainan seperti:

  • Simulasi agen berbasis perilaku yang memungkinkan Anda menentukan gerakan dan tujuan yang akan ditempuh AI secara otomatis.
  • Kecerdasan buatan minmax untuk permainan berbasis giliran.
  • Sistem aturan untuk logika game berbasis data dengan penalaran fuzzy untuk memberikan perilaku yang muncul.

Selain itu, GameplayKit mengambil pendekatan blok bangunan untuk pengembangan game dengan menggunakan arsitektur modular yang menyediakan fitur-fitur berikut:

  • Mesin status untuk menangani sistem berbasis kode prosedural yang kompleks dalam permainan.
  • Alat untuk menyediakan permainan acak dan tidak dapat diprediksi tanpa menyebabkan masalah penelusuran kesalahan.
  • Arsitektur berbasis entitas yang dapat digunakan kembali dan digabungkan.

Untuk mempelajari lebih lanjut tentang GameplayKit, silakan lihat Panduan Pemrograman Gameplaykit Apple dan Referensi Kerangka Kerja GameplayKit.

Contoh GameplayKit

Mari kita lihat sekilas mengimplementasikan beberapa mekanisme bermain game sederhana di aplikasi Xamarin.iOS menggunakan kit bermain game.

Pathfinding

Pathfinding adalah kemampuan untuk elemen AI dari permainan untuk menemukan jalan di sekitar papan permainan. Misalnya, musuh 2D yang menemukan jalannya melalui labirin atau karakter 3D melalui medan dunia penembak orang pertama.

Pertimbangkan peta berikut:

Contoh peta pathfinding

Menggunakan pathfinding kode C# ini dapat menemukan cara melalui peta:

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));

Sistem Pakar Klasik

Cuplikan kode C# berikut menunjukkan bagaimana GameplayKit dapat digunakan untuk mengimplementasikan sistem ahli klasik:

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;
}

Berdasarkan seperangkat aturan tertentu (GKRule) dan serangkaian input yang diketahui, sistem ahli (GKRuleSystem) akan membuat output yang dapat diprediksi (fizzbuzz misalnya di atas).

Berbondong

Flocking memungkinkan sekelompok entitas game yang dikendalikan AI untuk bertingkah sebagai kawanan, di mana grup merespons gerakan dan tindakan entitas utama seperti kawanan burung dalam penerbangan atau sekolah ikan berenang.

Cuplikan kode C# berikut mengimplementasikan perilaku flocking menggunakan GameplayKit dan SpriteKit untuk tampilan grafis:

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}");
        }
    }
}

Selanjutnya, terapkan adegan ini dalam pengontrol tampilan:

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);
    }
}

Ketika dijalankan, "Boid" animasi kecil akan berbondong-bondong di sekitar ketukan jari kita:

Boid animasi kecil akan mengepung keran jari

Contoh Apple Lainnya

Selain sampel yang disajikan di atas, Apple telah menyediakan contoh aplikasi berikut yang dapat ditranskodekan ke C# dan Xamarin.iOS:

Metal

Di iOS 9, Apple telah membuat beberapa perubahan dan penambahan pada Metal untuk menyediakan akses overhead rendah ke GPU. Menggunakan Metal, Anda dapat memaksimalkan grafik dan potensi komputasi aplikasi iOS Anda.

Kerangka kerja Metal mencakup fitur baru berikut:

  • Tekstur stensil privat dan kedalaman baru untuk OS X.
  • Kualitas bayangan yang ditingkatkan dengan penjepitan kedalaman dan nilai stensil depan dan belakang yang terpisah.
  • Perbaikan Metal Shading Language dan Metal Standard Library.
  • Shader komputasi mendukung berbagai format piksel yang lebih luas.

Kerangka Kerja MetalKit

Kerangka kerja MetalKit menyediakan serangkaian kelas dan fitur utilitas yang mengurangi jumlah pekerjaan yang diperlukan untuk menggunakan Metal dalam aplikasi iOS. MetalKit menyediakan dukungan di tiga area utama:

  1. Pemuatan tekstur asinkron dari berbagai sumber termasuk format umum seperti PNG, JPEG, KTX, dan PVR.
  2. Akses mudah aset berbasis I/O Model untuk penanganan model khusus Metal. Fitur-fitur ini telah sangat dioptimalkan untuk menyediakan transfer data yang efisien antara jala I/O Model dan buffer Metal.
  3. Tampilan Logam yang telah ditentukan sebelumnya dan manajemen tampilan yang sangat mengurangi jumlah kode yang diperlukan untuk menampilkan penyajian grafis dalam aplikasi iOS.

Untuk mempelajari lebih lanjut tentang MetalKit, silakan lihat Referensi Kerangka Kerja MetalKit Apple, Panduan Pemrograman Logam, Referensi Kerangka Kerja Logam, dan Panduan Bahasa Bayangan Logam.

Kerangka Kerja Shader Performa Logam

Kerangka kerja Metal Performance Shader menyediakan serangkaian grafis dan shader berbasis komputasi yang sangat dioptimalkan untuk digunakan di aplikasi iOS berbasis Metal Anda. Setiap shader dalam kerangka kerja Metal Performance Shader telah disetel secara khusus untuk memberikan performa tinggi pada GPU iOS yang didukung Metal.

Dengan menggunakan kelas Metal Performance Shader, Anda dapat mencapai performa setingkat mungkin pada setiap GPU iOS tertentu tanpa harus menargetkan dan memelihara basis kode individual. Metal Performance Shaders dapat digunakan dengan sumber daya Logam apa pun seperti tekstur dan buffer.

Kerangka kerja Metal Performance Shader menyediakan serangkaian shader umum seperti:

  • Gaussian Blur (MPSImageGaussianBlur)
  • Deteksi Tepi Sobel (MPSImageSobel)
  • Histogram Gambar (MPSImageHistogram)

Untuk informasi selengkapnya, silakan lihat Panduan Bahasa Bayangan Logam Apple.

Memperkenalkan I/O Model

Kerangka kerja I/O Model Apple memberikan pemahaman mendalam tentang aset 3D (seperti model dan sumber daya terkait). Model I/O menyediakan game iOS Anda dengan materi, model, dan pencahayaan berbasis fisik yang dapat digunakan dengan GameplayKit, Metal, dan SceneKit.

Dengan I/O Model, Anda dapat mendukung jenis tugas berikut:

  • Impor pencahayaan, bahan, data jala, pengaturan kamera, dan informasi berbasis adegan lainnya dari berbagai format perangkat lunak dan mesin game populer.
  • Proses atau hasilkan informasi berbasis adegan seperti membuat kubah langit bertekstulasi prosedural atau membuat pencahayaan kue ke dalam jala.
  • Bekerja dengan MetalKit, SceneKit, dan GLKit untuk memuat aset game secara efisien ke dalam buffer GPU untuk penyajian.
  • Ekspor informasi berbasis adegan ke berbagai format perangkat lunak dan mesin game populer.

Untuk mempelajari lebih lanjut tentang I/O Model, silakan lihat Referensi Kerangka Kerja I/O Model Apple

Memperkenalkan ReplayKit

Kerangka kerja ReplayKit baru Apple memungkinkan Anda untuk dengan mudah menambahkan rekaman permainan game ke game iOS Anda dan memungkinkan pengguna untuk mengedit dan membagikan video ini dengan cepat dan mudah dari dalam aplikasi.

Untuk informasi selengkapnya, silakan lihat video Apple's Going Social with ReplayKit dan Game Center dan DemoBots mereka: Membangun Game Lintas Platform dengan aplikasi sampel SpriteKit dan GameplayKit.

SceneKit

Scene Kit adalah API grafik adegan 3D yang menyederhanakan bekerja dengan grafik 3D. Ini pertama kali diperkenalkan di OS X 10.8, dan sekarang telah hadir di iOS 8. Dengan Scene Kit menciptakan visualisasi 3D imersif dan game 3D kasual tidak memerlukan keahlian dalam OpenGL. Membangun konsep grafik adegan umum, Scene Kit mengabstraksi kompleksitas OpenGL dan OpenGL ES, sehingga sangat mudah untuk menambahkan konten 3D ke aplikasi. Namun, jika Anda seorang ahli OpenGL, Scene Kit memiliki dukungan besar untuk mengikat langsung dengan OpenGL juga. Ini juga mencakup banyak fitur yang melengkapi grafis 3D, seperti fisika, dan terintegrasi dengan sangat baik dengan beberapa kerangka kerja Apple lainnya, seperti Core Animation, Core Image dan Sprite Kit.

Untuk informasi selengkapnya, silakan lihat dokumentasi SceneKit kami.

Perubahan SceneKit

Apple telah menambahkan fitur baru berikut ke SceneKit untuk iOS 9:

  • Xcode sekarang menyediakan Editor Adegan yang memungkinkan Anda untuk dengan cepat membangun game dan aplikasi 3D interaktif dengan mengedit adegan langsung dari dalam Xcode.
  • Kelas SCNView dan SCNSceneRenderer dapat digunakan untuk mengaktifkan rendering Logam (pada perangkat iOS yang didukung).
  • Kelas SCNAudioPlayer dan SCNNode dapat digunakan untuk menambahkan efek audio spasial yang secara otomatis melacak posisi pemutar ke aplikasi iOS.

Untuk informasi selengkapnya, silakan lihat Dokumentasi SceneKit dan Referensi Kerangka Kerja SceneKit Apple dan Fox: Membangun Game SceneKit dengan proyek sampel Editor Adegan Xcode.

SpriteKit

Sprite Kit, kerangka kerja game 2D dari Apple, memiliki beberapa fitur baru yang menarik di iOS 8 dan OS X Yosemite. Ini termasuk integrasi dengan Scene Kit, dukungan shader, pencahayaan, bayangan, batasan, pembuatan peta normal, dan peningkatan fisika. Secara khusus, fitur fisika baru membuatnya sangat mudah untuk menambahkan efek realistis pada permainan.

Untuk informasi selengkapnya, silakan lihat dokumentasi SpriteKit kami.

Perubahan SpriteKit

Apple telah menambahkan fitur baru berikut ke SpriteKit untuk iOS 9:

  • Efek audio spasial yang secara otomatis melacak posisi pemutar dengan SKAudioNode kelas .
  • Xcode sekarang memiliki Editor Adegan dan Editor Tindakan untuk pembuatan aplikasi dan game 2D yang mudah.
  • Dukungan permainan gulir yang mudah dengan objek simpul (SKCameraNode) Kamera baru.
  • Pada perangkat iOS yang mendukung Metal, SpriteKit akan secara otomatis menggunakannya untuk penyajian, bahkan jika Anda sudah menggunakan shader OpenGL ES kustom.

Untuk informasi selengkapnya, silakan lihat Referensi Kerangka Kerja SpriteKit Dokumentasi SpriteKit Apple dan DemoBots mereka: Membangun Game Lintas Platform dengan aplikasi sampel SpriteKit dan GameplayKit.

Ringkasan

Artikel ini telah membahas fitur Gaming baru yang disediakan iOS 9 untuk aplikasi Xamarin.iOS Anda. Ini memperkenalkan GameplayKit dan Model I/O; peningkatan utama untuk Metal; dan fitur baru SceneKit dan SpriteKit.