Acest tutorial oferă o imagine de ansamblu asupra noilor caracteristici ale cadrului SpriteKit introduse în iOS 8. Noile caracteristici sunt concepute pentru a facilita suportul pentru efecte avansate ale jocului și includ suportul pentru shaderele personalizate OpenGL ES, iluminare, umbre, efectele fizice și animațiile și integrarea cu SceneKit. În acest tutorial, veți învăța cum să implementați aceste noi caracteristici.
Înainte de a începe tutorialul, aș dori să-i mulțumesc lui Mélodie Deschans (Wicked Cat) pentru că ne-a oferit arta jocului folosită în această serie.
Acest tutorial presupune că sunteți familiarizat atât cu SpriteKit și Obiectiv-C. Pentru a interacționa cu shader și editorul de scenă fără întârziere de intrare, vă recomandăm să descărcați și să instalați Xcode 6.1 sau o versiune ulterioară. Descărcați proiectul Xcode de la GitHub, dacă doriți să continuați.
Această serie este împărțită în două tutoriale și acoperă cele mai importante caracteristici noi ale cadrului SpriteKit. În prima parte, ne uităm la shadere, iluminare și umbre. În partea a doua, voi vorbi despre fizică și integrarea SceneKit.
În timp ce fiecare parte din această serie se află pe cont propriu, vă recomand să urmați pas cu pas înțelegerea corectă a noilor caracteristici ale cadrului SpriteKit. După ce ați citit ambele părți, veți putea crea atât jocuri simple, cât și mai avansate, utilizând noile caracteristici ale cadrului SpriteKit.
SpriteKit oferă o conductă de randare care poate fi utilizată pentru a anima sprite. Conducta de randare conține o buclă de randare care se alternează între determinarea conținutului și a cadrelor de randare. Dezvoltatorul determină conținutul fiecărui cadru și modul în care acesta se schimbă. SpriteKit utilizează GPU-ul dispozitivului pentru a reda eficient fiecare cadru.
Cadrul SpriteKit este disponibil atât pe iOS cât și pe sistemul de operare OS X și suportă multe tipuri diferite de conținut, inclusiv sprite, text, forme și video.
Noile caracteristici SpriteKit introduse în iOS 8 sunt:
SKSpriteNode
, SKShapeNode
, SKEmitterNode
, SKEffectNode
, și SKScene
.SKNode
instanțe. Realizează conținutul 3D direct în interiorul conductei de redare SpriteKit. Puteți să importați fișiere .dae sau .abc existente SKScene
.Am creat un proiect Xcode pentru a ne începe. Aceasta ne permite să începem imediat utilizarea noilor caracteristici SpriteKit. Cu toate acestea, există câteva lucruri pe care trebuie să le cunoașteți.
SKScene
folosind un fișier scenă SpriteKit, veți folosi întotdeauna unarchiveFromFile:
metodă. Cu toate acestea, este obligatoriu să adăugați pentru fiecare fișier scenă SpriteKit cea corespunzătoare SKScene
clasă.SKScene
obiect fără a utiliza un fișier scena SpriteKit, ar trebui să utilizați initWithSize:
așa cum ați procedat în versiunile anterioare ale iOS.GameViewController
și GameScene
clasele conțin o metodă numită unarchiveFromFile:
. Această metodă transformă obiectele grafice definite într-o scenă SpriteKit și le transformă într-un SKScene
obiect. Metoda utilizează instancetype
, deoarece returnează o instanță a clasei pe care o numește, în acest caz SKScene
clasă.Descărcați proiectul și faceți o clipă pentru a răsfoi dosarele, clasele și resursele acestuia. Construiți și executați proiectul pe un dispozitiv fizic sau în Simulatorul iOS. Dacă aplicația rulează fără probleme, atunci este timpul să începeți să explorați noile caracteristici iOS 8 SpriteKit.
În proiectul Xcode, adăugați un nou Scena SpriteKit fişier. Alege Fişier > Nou > Fişier… și, de la Resursă secțiune, alegeți Scena SpriteKit. Numeste ShaderSceneEditor
și faceți clic pe Crea. Ar trebui să apară o interfață gri.
În SKNode Inspector în dreapta, ar trebui să vedeți două proprietăți, mărimea și Gravitatie. Seteaza mărimea proprietate luând în considerare rezoluția ecranului dispozitivului și setați Gravitatie la 0.0
.
Veți observa că mărimea dreptunghiului galben se modifică pentru a reflecta modificările pe care le-ați făcut. Dreptunghiul galben este interfața dispozitivului virtual. Vă arată cum sunt afișate obiectele pe dispozitiv.
În interiorul Biblioteca de obiecte din dreapta, selectați Color Sprite și trageți-l în dreptunghiul galben.
Selectați sprite de culori și deschideți SKNode Inspector pe dreptul de a vedea proprietățile sale.
Puteți interacționa cu obiectul în timp real. Orice modificări pe care le faceți sunt afișate în editor. Poți să te joci cu Poziţie, mărimea, Culoare, sau Scară, dar ceea ce chiar vrei este Custom Shader opțiune. Cu toate acestea, veți observa că nu există încă un shader disponibil.
Adăugați un nou fișier sursă gol (Fişier > Nou> Fişier… ), alegeți Alte > gol de la iOS și denumiți-o Shader01.fsh. Adăugați următorul cod în fișierul pe care tocmai l-ați creat.
void principal () float currTime = u_time; vec2 uv = v_tex_coord; vec2 circleCenter = vec2 (0,5, 0,5); vec3 cercColor = vec3 (0,8, 0,5, 0,7); vec3 posColor = vec3 (uv, 0,5 + 0,5 * sin (currTime)) * cercColor; float illu = pow (1 - distanța (uv, circleCenter), 4.) * 1.2; illu * = (2. + abs (0.4 + cos (currTime * -20 + 50. * distanța (uv, circleCenter) / 1.5)); gl_FragColor = vec4 (posColor * illu * 2., illu * 2.) * v_color_mix.a;
Blocul de cod de mai sus generează o fuziune de culori, luând în considerare centrul unui cerc și marginea acestuia. Apple a arătat acest shader în sesiunea lor SpriteKit în timpul WWDC 2014.
Reveniți la editor, selectați obiectul de culoare sprite și în Custom Shader selectați shaderul pe care tocmai l-ați creat. Ar trebui să vezi acum umbra în acțiune.
Programarea shadere folosind Xcode și SpriteKit este ușor, deoarece primiți feedback în timp real. Deschide Editor asistent și configurați-o pentru a afișa atât scena SpriteKit, cât și shaderul pe care tocmai l-ați creat.
Să vedem cum funcționează acest lucru. Introduceți o eroare de rulare în shader, de exemplu, schimbând numele unei variabile și salvați modificările pentru a vedea rezultatul.
După cum puteți vedea, Xcode oferă o modalitate rapidă și ușoară de a avertiza dezvoltatorul despre posibilele erori de shader. Avantajul este că nu aveți nevoie să construiți sau să implementați aplicația pe dispozitiv sau pe simulatorul iOS pentru a vedea dacă totul funcționează bine.
Acum este momentul să adăugați un alt shader și să îl programați manual.
În acest pas, veți afla cum să:
În acest pas, veți adăuga un personalizat SKSpriteNode
în poziția robinetului utilizatorului și apoi veți folosi un shader pentru a modifica culoarea texturii SKSpriteNode
.
Primul pas este să adăugați un alt shader. Denumiți noul shader shader02.fsh și adăugați următorul bloc de coduri la fișierul shader:
void principal () gl_FragColor = textură2D (myTexture, v_tex_coord) * vec4 (1, 0,2, 0,2, 1);
Deschideți fișierul de implementare al ShaderScene
clasă. Primul pas este să detectezi dacă utilizatorul a lovit ecranul și a găsit locația robinetului. Pentru aceasta, trebuie să implementăm touchesBegan: withEvent:
metodă. În cadrul acestei metode, adăugați a SKSpriteNode
exemplu la locul robinetului. Puteți folosi orice sprite care vă place. Am folosit-o Spaceship.png, care este deja inclus în proiect.
- (void) atingeBegan: (NSSet *) atinge cu EventEvent: (UIEvent *) eveniment pentru (UITouch * atinge in atinge) CGPoint location = [touch locationInNode: self]; // Creați nodul SKSpriteNode * space = [SKSpriteNode spriteNodeWithImageNamed: @ "Spaceship.png"]; space.position = CGPointMake (locație.x, locație.y); [self addChild: spațiu];
Apoi creăm un SKShader
obiect și inițializați-l folosind shader02.fsh fişier:
SKShader * shader = [SKShader shaderWithFileNamed: @ "shader02.fsh"];
Este posibil să fi observat că fișierul sursă al shader-ului se referă la a myTexture
obiect. Aceasta nu este o proprietate predefinită a shader-ului, ci o referință pe care aplicația trebuie să o treacă la shader. Următorul fragment de cod ilustrează modul în care puteți face acest lucru.
shader.uniforms = @ [[SKUniform uniformă cu nume: @ "myTexture" textură: [SKTexture textureWithImageNamed: @ "Spaceship.png"]]];
Apoi adăugăm shader-ul la SKSpriteNode
obiect.
space.shader = shader;
Aceasta este ceea ce touchesBegan: withEvent:
metoda ar trebui să arate ca:
- (void) atingeBegan: (NSSet *) atinge cu EventEvent: (UIEvent *) eveniment pentru (UITouch * atinge in atinge) CGPoint location = [touch locationInNode: self]; // Creați nodul SKSpriteNode * space = [SKSpriteNode spriteNodeWithImageNamed: @ "Spaceship.png"]; space.position = CGPointMake (locație.x, locație.y); [self addChild: spațiu]; SKShader * shader = [SKShader shaderWithFileNamed: @ "shader02.fsh"]; shader.uniforms = @ [[SKUniform uniformă cu nume: @ "myTexture" textură: [SKTexture textureWithImageNamed: @ "Spaceship.png"]]]; space.shader = shader;
Construiți și conduceți proiectul. Apasă pe Shadere (initWithSize) și atingeți ecranul. De fiecare dată când atingeți ecranul, se adaugă o sprite de navă spațială cu textura modificată.
Folosind această opțiune, veți vedea că primul shader nu este prezentat pe ecran. Acest lucru se întâmplă deoarece acel shader a fost creat și configurat în interiorul editorului Scene SpriteKit. Pentru ao vedea, trebuie să inițializați ShaderScene
clasa folosind unarchiveFromFile:
metodă.
În GameScene.m, ar trebui să vedeți o secțiune care detectează și analizează robinetele utilizatorului touchesBegan: withEvent:
. In secunda dacă
clauză, inițiazăm o ShaderScene
exemplu după cum se arată mai jos.
dacă ([node.name esteEqualToString: @ "buttonShaderCoder"]) ShaderScene * scena = [ShaderScene unarchiveFromFile: @ "ShaderSceneEditor"]; [self.scene.view presentScene: scenă];
Construiți și executați din nou proiectul, atingeți Shadere (initWithCoder) și atingeți ecranul. Ambele shadere sunt acum active într-o singură scenă SpriteKit.
Iluminarea și umbrele sunt două proprietăți care joacă împreună. Scopul acestei secțiuni este de a adăuga mai multe noduri ușoare și sprite, și să se joace cu proprietățile lor.
Deschis LightingSceneEditor.sks și răsfoiți obiectele din interiorul Biblioteca media pe dreapta. În Biblioteca media, puteți vedea resursele incluse în proiect.
Selectați și trageți background.jpg la dreptunghiul galben. Dacă nu ați modificat rezoluția implicită a scenei, imaginea trebuie să se potrivească în interiorul dreptunghiului.
Când selectați sprite, veți observa că are mai multe proprietăți cum ar fi Poziţie, mărimea, Z Poziţie, Mască de iluminare, Mască de mascare a umbrelor, Definiția fizicii, și multe altele.
Simțiți-vă liber să jucați cu aceste proprietăți. Deocamdată, totuși, este important să lăsați proprietățile la valorile implicite. Trageți a Ușoară obiect de la Biblioteca de obiecte pe dreapta pe sprite de fundal. Poziția luminii nu este importantă, dar alte proprietăți ale luminii sunt.
Aveți posibilitatea să configurați Culoare, Umbră, și Înconjurător culoare pentru a configura lumina și umbra. Poziția Z este înălțimea nodului față de nodul părinte. Setați-l la 1. Mască de iluminare definește categoriile la care aparține această lumină. Când o scenă este redată, este o lumină categoryBitMask
proprietatea este comparată cu fiecare nod sprite lightingBitMask
, shadowCastBitMask
, și shadowedBitMask
proprietăți. Dacă valorile se potrivesc, sprite interacționează cu lumina. Aceasta vă permite să definiți și să utilizați mai multe lumini care interacționează cu unul sau mai multe obiecte.
Probabil ați observat că fundalul nu sa schimbat după adăugarea luminii. Acest lucru se întâmplă deoarece masca de iluminare a luminii și a fundalului este diferită. Trebuie să setați masca de iluminare a fundalului la cea a luminii, care este 1 în exemplul nostru.
Actualizați fundalul în SKNode Inspector și apăsați enter. Efectul acestei schimbări este imediat. Lumina luminează acum fundalul în funcție de poziția sa. Puteți modifica poziția luminii pentru a vedea interacțiunea dintre fundal și nodurile luminoase în timp real.
Pentru a crește realismul fundalului sau pentru a accentua una dintre caracteristicile sale, jucați cu Finete și Contrast proprietăți. Redați cu valorile pentru a vedea modificările în timp real.
Acum este momentul să adăugați câteva obiecte care interacționează cu nodul luminos. În Biblioteca media, găsi crochete-o.png și crochete-x.png sprite și adăugați-le la scenă.
Fiecare sprite trebuie să fie configurat individual. Selectați fiecare sprite și setați Mască de iluminare, Shadow Mask Cast, și Poziția Z la 1. Masca de iluminare asigură faptul că sprite este afectată de nodul luminos, în timp ce masca de umbră a umbrei creează o umbră în timp real în funcție de poziția nodului luminos. În cele din urmă, setați Tipul corpului (Definiția fizicii) la Nici unul. Faceți asta pentru ambii sprites.
Ar fi trebuit să observați că, chiar și după setarea proprietăților iluminării și umbrelor, nu puteți vedea interacțiunea dintre lumină și noduri. Pentru aceasta, trebuie să construiți și să executați proiectul pe un dispozitiv fizic sau în Simulator.
Știți deja cum să adăugați luminile utilizând editorul de scenă. Să vedem cum să adăugăm o lumină fără a folosi editorul de scenă.
Deschide LightingScene.m și în interior didMoveToView:
metoda pe care o cream SKSpriteNode
obiect și a SKLightNode
obiect.
Pentru SKSpriteNode
obiect, vom folosi Wicked-Cat.png sprite. Poziția nodului nu este atât de importantă, ci de valorile lui zPosition
, shadowCastBitMask
, și lightingBitMask
sunteți. Deoarece SpriteKit analizează secvențial datele, trebuie să setați nodurile zPosition
la 1
pentru ca acest sprite să fie vizibil, deasupra sprite-ului de fundal. Noi am stabilit shadowCastBitMask
și lightingBitMask
la 1
.
Aceasta este ceea ce didMoveToView:
metoda pare până acum:
- (void) didMoveToView: (SKView *) vizualizați SKSpriteNode * sprite = [SKSpriteNode spriteNodeWithImageNamed: @ "Wicked-Cat.png"]; [sprite setPosition: CGPointMake (auto.frame.size.width / 2, auto.frame.size.height / 2)]; [Sprite setScale: 0,6]; [sprite setZPoziție: 1]; [sprite setShadowCastBitMask: 1]; [sprite setLightingBitMask: 1]; [auto addChild: sprite];
Apoi, să adăugăm SKLightNode
obiect. Ar trebui să acordați o atenție deosebită categoryBitMask
proprietate. Dacă l-ați setat 1
, această lumină va interacționa cu fiecare sprite. Numeste ușoară
și stabilit zPosition
la 1
.
Fragmentul complet pentru SKLightNode
ar trebui să arate astfel:
SKLightNode * light = [[SKLightNode alocare] init]; [light setName: @ "lumină"]; [setPosition ușor: CGPointMake (100, 100)]; [lumină setCategoryBitMask: 1]; [lumină setFalloff: 1,5]; [setZPosition de lumină: 1]; [light setAmbientColor: [Culoarea UICcolor alb]]; [light setLightColor: [[UICcolor alocat] initWithRed: 1.0 verde: 0.0 albastru: 0.0 alpha: .5]]; [light setShadowColor: [[UICcolor alocat] initWithRed: 0.9 verde: 0.25 albastru: 0.0 alpha: .5]]; [auto addChild: lumină];
În acest moment aveți oa doua lumină. Dar să adăugăm o anumită interacțiune cu utilizatorul. Pentru asta, trebuie să adăugați touchesMoved: withEvent:
și schimbați poziția luminii, ținând cont de locația robinetului.
-(void) atingeModed: (NSSet *) atinge cu EventEvent: (UIEvent *) eveniment pentru (UITouch * atinge in atinge) CGPoint location = [touch locationInNode: self]; [self childNodeWithName: @ "light"] Poziție = CGPointMake (location.x, location.y);
In cele din urma,construiți și executați aplicația. Apasă pe Iluminat buton și ar trebui să vedeți ceva similar cu ecranul de mai jos:
Acesta încheie primul tutorial din seriile noastre cu două părți despre noile caracteristici ale SpriteKit introduse în iOS 8. În această parte, ați învățat să creați shadere personalizate și efecte de iluminare utilizând atât editorul SpriteKit Scene, cât și codul. Dacă aveți întrebări sau comentarii, ca întotdeauna, nu ezitați să renunțați la un comentariu.