Android-pelien kehityksen ABC: t: Animoi sprites

Jos olet seurannut tämän sarjan mukana Android-pelien kehityksessä, tiedät, että meillä on nyt pelisarja ja spritit paikoillaan. Seuraava askel on animoida spritit pelilaudan ympärillä. (Pelimme tavoitteena on säätää lautasen vauhtia välttääksesi asteroidin osumien purkautumista. Projekti sisältää yksinkertaisen yksinkertaisuuden, mutta sisältää videopelin kaikki olennaiset näkökohdat: kankaan, spritit, animaation, törmäyksen havaitsemisen ja käyttäjän syöttämä.)

Animaatio on yksi videopelin tärkeimmistä näkökohdista. Yleensä on olemassa kahdenlaisia ​​sprite-animaatioita: Ensimmäinen tyyppi siirtää kuvan paikasta toiseen, kun taas toinen tyyppi johtaa seuraavan kehyksen toistettavien animaatioiden sarjaan.

Spriten liikuttaminen on helppoa käsittää, koska sprite kuljetetaan fyysisesti näytön paikasta toiseen. Toinen animaatiotyyppi on vähän vähemmän suoraviivainen. Kun olet ollut lapsi, piirtitkökö koskaan piirrossarjoja muistikirjan jokaisen sivun nurkkaan, selasit sitten sivuja peukalolla saadaksesi logon näyttämään siltä, ​​että se oli elossa? Jos on, niin me yritämme tehdä, kun animoimme kehyksiä spriteissä - lisää jonkin verran elämää peliobjektiihimme.

Jotkut peleissä olevat pelit käyttävät vain yhden tyyppisiä animaatioita, kun taas jotkut voivat käyttää molempia. Pelissämme käytämme ensimmäisen tyyppistä animaatiota UFO: llamme ja ensimmäistä ja toista tyyppistä animaatiota asteroidillamme. Vaikutus näyttää siltä, ​​että asteroidi liikkuu ja pyörii.

Koska tämä on demo ja haluamme selittää konseptin mahdollisimman yksinkertaisesti, emme ota käyttöön fysiikkaa tai painovoimaa pelissämme. Laiva liikkuu vakionopeudella (toistaiseksi), kun taas asteroidi liikkuu satunnaisella nopeudella, joka alustetaan aina, kun nollauspainiketta painetaan. Jos jokin spritistä osuu kankaamme rajoihin, käännämme x ja y kääntäen, oleellisesti tekemällä siitä "pomppia" takaisin peliin ( kuva A ). Kuvio A

Kuva kahdesta erillisestä sprite-animaation tyypistä.

Animoi spritejä

Tämä opetusohjelma perustuu siihen, mitä loimme toisessa osassa. Jotta todella ymmärrämme mitä tapahtuu, se auttaa näkemään koodin kokonaisuudessaan. Siksi opetusohjelman koodiluettelosta tulee täydellinen työpohjamme, jossa uusi koodi kommentoidaan rivillä. Voit seurata vaiheittaisia ​​ohjeita tai ladata ja tuoda koko projektin Eclipse-ohjelmaan.

1. Luo uusi Android-projekti Eclipse-sovellukseen. Kohdista Android 2.1 tai uudempi. Muista nimetä käynnistystoiminta Main.java ja sitä vastaava asettelu main.javaksi.

2. Vaikka manifestitiedostossamme tai asettelussa ei ole muutoksia toisen osan jälkeen, olen sisällyttänyt molemmat alla täydellisyyden vuoksi.

AndroidManifest.xml

 "Http://schemas.android.com/apk/res/android" 
 package = "com.authorwjf.gamedevtut03" 
 android: versionCode = "1" 
 android: versionName = "1.0" > 
 android: minSdkVersion = "7" 
 android: targetSdkVersion = "15" /> 
 android: icon = "@ piirrettävä / ic_launcher" 
 android: label = "@ merkkijono / sovelluksen_nimi" 
 android: theme = "@ style / AppTheme" > 
 android: name = ".Pääministeri" 
 android: label = "@ string / title_activity_main" 
 android: screenOrientation = "muotokuva" 
 android: configChanges = "orientation | keyboardHidden" > 
 "android.intent.action.MAIN" /> 
 "android.intent.category.LAUNCHER" /> 

main.xml

 "Http://schemas.android.com/apk/res/android" 
 android: layout_width = "fill_parent" 
 android: layout_height = "fill_parent" 
 android: orientation = "pystysuora" > 
 android: layout_width = "wrap_content" 
 android: layout_height = "wrap_content" 
 android: layout_gravity = "yläosa | keskusta" 
 android: text = "Android Game Dev: n ABC: t" /> 
 android: id = "@ + id / the_button" 
 android: layout_width = "wrap_content" 
 android: layout_height = "wrap_content" 
 android: layout_gravity = "keskusta" 
 android: painovoima = "keskusta" 
 android: käytössä = "false" 
 android: text = "Nollaa" /> 
 android: layout_width = "wrap_content" 
 android: layout_height = "wrap_content" 
 android: layout_gravity = "keskusta" 
 android: text = "Sprite Speed ​​(?, ?)" 
 android: id = "@ + id / the_label" /> 
 android: layout_width = "wrap_content" 
 android: layout_height = "wrap_content" 
 android: layout_gravity = "keskusta" 
 android: text = "Viimeinen törmäys XY (?, ?)" 
 android: id = "@ + id / the_other_label" /> 
 android: layout_width = "fill_parent" 
 android: layout_height = "fill_parent" 
 android: layout_margin = "20dip" 
 android: id = "@ + id / the_canvas" /> 

3. Käytä kahta kuvaa / res / piirrettävässä kansiossa olevia kuvia. Nämä molemmat on esitetty alla.

4. Tee muutama muutos GameBoard-luokkaan, joka on paketissa com.authorwjf.drawing. Muutoksia kommentoidaan alla olevassa tekstissä ja ne koostuvat muutamasta avainkohdasta. Ensinnäkin olen lisännyt uusia yksityisiä muuttujia; tämä on niin, että voimme asettaa rajat kuvillemme main.java-luokassa. Uusien getterien / setterien lisäämisen lisäksi muutin myös joitain nykyisiä lisälaitteita toimimaan primitiivien kanssa Java-luokan sijasta; Tämän tarkoituksena on varmistaa, että spritejämme ei kuljeta tahattomasti referenssin kautta ja että niitä ei käsitellä suoraan ohjaimessa. Se voi kiertää synkronointia. Lopuksi tarkista on-line-ohitus. Käytämme nyt matriisia kääntääksesi asteroidin; tämä saavuttaa kehrävän animaatiomme melko helposti.

GameBoard.java

 paketti com.authorwjf.drawing; 
 tuo java.util.ArrayList; 
 tuo java.util.List; 
 tuo java.util.Random; 
 Tuo com.authorwjf.gamedevtut03.R; 
 tuo android.content.Context; 
 Tuo android.graphics.Bitmap; 
 tuo android.graphics.BitmapFactory; 
 Tuo android.graphics.Canvas; 
 Tuo android.graphics.Color; 
 Tuo android.graphics.Matrix; 
 Tuo android.graphics.Paint; 
 Tuo android.graphics.Point; 
 Tuo android.graphics.Rect; 
 Tuo android.util.AttributeSet; 
 Tuo android.view.View; 
 julkisen luokan GameBoard laajentaa Näytä { 
 yksityinen maali; 
 yksityinen luettelo starField = nolla ; 
 yksityinen int starAlpha = 80; 
 yksityinen int starFade = 2; 
 // Lisää yksityisiä muuttujia pysyäksesi sprite-asemansa ja koon suhteen 
 yksityinen Rect sprite1Bounds = uusi Rect (0, 0, 0, 0); 
 yksityinen Rect sprite2Bounds = uusi Rect (0, 0, 0, 0); 
 yksityinen piste sprite1; 
 yksityinen piste sprite2; 
 // Bittikartat, jotka pitävät todelliset sprite-kuvat 
 yksityinen bittikartta bm1 = nolla ; 
 yksityinen matriisi m = nolla ; 
 yksityinen bittikartta bm2 = nolla ; 
 yksityinen int sprite1Rotation = 0; 
 yksityinen staattinen lopullinen int NUM_OF_STARS = 25; 
 // Anna ohjaimen saada ja asettaa sprite-asemat 
 // sprite 1 setteri 
 synkronoitu julkinen tyhjä setSprite1 ( int x, int y) { 
 sprite1 = uusi piste (x, y); 
 } 
 // sprite 1 getter 
 synkronoitu julkinen int getSprite1X () { 
 paluu sprite1.x; 
 } 
 synkronoitu julkinen int getSprite1Y () { 
 paluu sprite1.y; 
 } 
 // sprite 2 setteriä 
 synkronoitu julkinen tyhjä setSprite2 ( int x, int y) { 
 sprite2 = uusi piste (x, y); 
 } 
 // sprite 2 getter 
 synkronoitu julkinen int getSprite2X () { 
 paluu sprite2.x; 
 } 
 synkronoitu julkinen int getSprite2Y () { 
 paluu sprite2.y; 
 } 
 synkronoitu julkinen tyhjä resetStarField () { 
 starField = nolla ; 
 } 
 // paljasta sprite-rajat ohjaimelle 
 synkronoitu julkinen int getSprite1Width () { 
 paluu sprite1Bounds.width (); 
 } 
 synkronoitu julkinen int getSprite1Height () { 
 paluu sprite1Bounds.height (); 
 } 
 synkronoitu julkinen int getSprite2Width () { 
 paluu sprite2Bounds.width (); 
 } 
 synkronoitu julkinen int getSprite2Height () { 
 paluu sprite2Bounds.height (); 
 } 
 julkinen pelikortti (kontekstiyhteys, AttributeSet aSet) { 
 super (konteksti, aSet); 
 p = uusi maali (); 
 // lataa bittikarttamme ja aseta rajat ohjaimelle 
 sprite1 = uusi piste (-1, -1); 
 sprite2 = uusi piste (-1, -1); 
 // Määritä matriisi, jotta voimme kiertää asteroidia 
 m = uusi matriisi (); 
 p = uusi maali (); 
 bm1 = BitmapFactory. decodeResource (getResources (), R. vetävä. asteroidi ); 
 bm2 = BitmapFactory. decodeResource (getResources (), R.dravable. ufo ); 
 sprite1Bounds = uusi suhde (0, 0, bm1.getWidth (), bm1.getHeight ()); 
 sprite2Bounds = uusi suhteellisuus (0, 0, bm2.getWidth (), bm2.getHeight ()); 
 } 
 yksityinen tyhjä InitizeStars ( int maxX, int maxY) { 
 starField = uusi ArrayList (); 
 varten ( int i = 0; i < NUM_OF_STARS ; i ++) { 
 Random r = uusi Random (); 
 int x = r.sextInt (maxX-5 + 1) +5; 
 int y = r.seuraava (maxY-5 + 1) +5; 
 starField.add ( uusi kohta (x, y)); 
 } 
 } 
 @Ohittaa 
 synkronoitu julkinen tyhjä onDraw (kankaalle) { 
 p.setColor (väri. MUSTA ); 
 p.setAlpha (255); 
 p.setStrokeWidth (1); 
 canvas.drawRect (0, 0, getWidth (), getHeight (), p); 
 if (starField == nolla ) { 
 alustaa tähtiä (canvas.getWidth (), canvas.getHeight ()); 
 } 
 p.setColor (väri. CYAN ); 
 p.setAlpha (starAlpha + = starFade); 
 if (starAlpha> = 252 || starAlpha <= 80) starFade = starFade * -1; 
 p.setStrokeWidth (5); 
 varten ( int i = 0; i < NUM_OF_STARS ; i ++) { 
 canvas.drawPoint (starField.get (i) .x, starField.get (i) .y, p); 
 } 
 // Nyt piirrämme spritejämme. Tässä toiminnossa piirretyt kohteet on pinottu. 
 // Silmukan yläosaan piirretyt tuotteet ovat z-järjestyksen alaosassa. 
 // Siksi piirrämme sarjamme, sitten näyttelijämme ja lopulta minkä tahansa fx: n. 
 if (sprite1.x> = 0) { 
 m.reset (); 
 m.postTranslate (( kellua ) (sprite1.x), ( float ) (sprite1.y)); 
 m.postRotate (sprite1Rotation, 
 ( kelluva ) (sprite1.x + sprite1Bounds.leveys () / 2.0), 
 ( kellua ) (sprite1.y + sprite1Bounds.leveys () / 2.0)); 
 canvas.drawBitmap (bm1, m, nolla ); 
 sprite1Rotation + = 5; 
 if (sprite1Rotation> = 360) sprite1Rotation = 0; 
 } 
 if (sprite2.x> = 0) { 
 canvas.drawBitmap (bm2, sprite2.x, sprite2.y, nolla ); 
 } 
 } 
 } 

4. Päivittämällä pelipöydän itse, voimme siirtyä tiedostoon /src/Main.java ja asettaa kaiken liikkeelle. Toisen osan jälkeen olemme lisänneet koodia asettaaksemme sprite-nopeuden ja laskemaan uuden sijainnin jokaisella soitolla päivittääksesi kankaan. Jos osoittautuu, että spriten uusi xy-koordinaatti sijoittaisi sen näytöltä, kerrotaan kyseisen akselin nopeus negatiivisella, aiheuttaen esineen pomppimisen.

Main.java

 paketti com.authorwjf.gamedevtut03; 
 tuo java.util.Random; 
 tuo com.authorwjf.drawing.GameBoard; 
 tuo android.os.Bundle; 
 tuo android.os.Handler; 
 Tuo android.view.View; 
 Tuo android.view.View.OnClickListener; 
 tuo android.widget.Button; 
 tuo android.app.Activity; 
 Tuo android.graphics.Point; 
 public class Main laajentaa aktiviteettityökaluja OnClickListener { 
 yksityinen ohjaajakehys = uusi käsittelijä (); 
 // Nopeuteen sisältyy sprite-liikkeemme nopeus ja suunta 
 yksityinen Point sprite1Velocity; 
 yksityinen Point sprite2Velocity; 
 yksityinen int sprite1MaxX; 
 yksityinen int sprite1MaxY; 
 yksityinen int sprite2MaxX; 
 yksityinen int sprite2MaxY; 
 // Jaa kehys 1000: lla laskeaksesi kuinka monta kertaa sekunnissa näyttö päivittyy. 
 yksityinen staattinen lopullinen int FRAME_RATE = 20; // 50 kuvaa sekunnissa 
 @Ohittaa 
 public void onCreate (Bundle savedInstanceState) { 
 super .onCreate (tallennettuInstanceState); 
 setContentView (R.layout. pää ); 
 Käsittelijä h = uusi käsittelijä (); 
 ((Button) findViewById (R.id. The_button )). SetOnClickListener ( tämä ); 
 // Grafiikkaa ei voida alustaa heti, koska asettelunhallinta 
 // on suoritettava ensin, soita sitten sekunnin kuluttua. 
 h.postDelayed ( uusi suoritettava () { 
 @Ohittaa 
 julkinen mitätön ajo () { 
 initGfx (); 
 } 
 }, 1000); 
 } 
 yksityinen piste getRandomVelocity () { 
 Random r = uusi Random (); 
 int min = 1; 
 int max = 5; 
 int x = r.sextInt (max-min + 1) + min; 
 int y = r.sextInt (max-min + 1) + min; 
 palauta uusi kohta (x, y); 
 } 
 yksityinen piste getRandomPoint () { 
 Random r = uusi Random (); 
 int minX = 0; 
 int maxX = findViewById (R.id. the_canvas ) .getWidth () - 
 ((GameBoard) findViewById (R.id. The_canvas )). GetSprite1Width (); 
 int x = 0; 
 int minY = 0; 
 int maxY = findViewById (R.id. the_canvas ) .getHeight () - 
 ((GameBoard) findViewById (R.id. The_canvas )). GetSprite1Height (); 
 int y = 0; 
 x = r.sextInt (maxX-minX + 1) + minX; 
 y = r.seuraava (maxY-minY + 1) + minY; 
 palauta uusi kohta (x, y); 
 } 
 synkronoitu julkinen tyhjä initGfx () { 
 ((GameBoard) findViewById (R.id. The_canvas )) .resetStarField (); 
 // Valitse kaksi satunnaispistettä ensimmäiselle sprite-sijoituksellemme. 
 // Silmukka on vain varmistaa, että emme vahingossa valitse 
 // kaksi päällekkäistä pistettä. 
 Kohta p1, p2; 
 tee { 
 p1 = getRandomPoint (); 
 p2 = getRandomPoint (); 
 } kun (matematiikan abs. (p1.x - p2.x) < 
 ((GameBoard) findViewById (R.id. The_canvas )). GetSprite1Width ()); 
 ((GameBoard) findViewById (R.id. The_canvas )). SetSprite1 (p1.x, p1.y); 
 ((GameBoard) findViewById (R.id. The_canvas )). SetSprite2 (p2.x, p2.y); 
 // Anna asteroidille satunnainen nopeus 
 sprite1Velocity = getRandomVelocity (); 
 // Kiinnitä laivan nopeus vakionopeudella toistaiseksi 
 sprite2Velocity = uusi kohta (1, 1); 
 // Aseta rajamme spritille 
 sprite1MaxX = findViewById (R.id. the_canvas ) .getWidth () - 
 ((GameBoard) findViewById (R.id. The_canvas )). GetSprite1Width (); 
 sprite1MaxY = findViewById (R.id. the_canvas ) .getHeight () - 
 ((GameBoard) findViewById (R.id. The_canvas )). GetSprite1Height (); 
 sprite2MaxX = findViewById (R.id. the_canvas ) .getWidth () - 
 ((GameBoard) findViewById (R.id. The_canvas )). GetSprite2Width (); 
 sprite2MaxY = findViewById (R.id. the_canvas ) .getHeight () - 
 ((GameBoard) findViewById (R.id. The_canvas )). GetSprite2Height (); 
 ((Button) findViewById (R.id. The_button )). SetEnabled ( true ); 
 frame.removeCallbacks (frameUpdate); 
 frame.postDelayed (frameUpdate, FRAME_RATE ); 
 } 
 @Ohittaa 
 synkronoitu julkinen tyhjä onClick (Näytä v) { 
 initGfx (); 
 } 
 private Runnable frameUpdate = new Runnable () { 
 @Ohittaa 
 synkronoitu julkinen tyhjä ajo () { 
 frame.removeCallbacks (frameUpdate); 
 // Hanki ensin kummankin spritin nykyinen sijainti 
 Piste sprite1 = uusi piste 
 (((GameBoard) findViewById (R.id. The_canvas )).) GetSprite1X (), 
 ((GameBoard) findViewById (R.id. The_canvas )). GetSprite1Y ()); 
 Piste sprite2 = uusi piste 
 (((GameBoard) findViewById (R.id. The_canvas )). GetSprite2X (), 
 ((GameBoard) findViewById (R.id. The_canvas )). GetSprite2Y ()); 
 // Laske nyt uudet sijainnit. 
 // Huomaa, jos ylitämme rajan, nopeuden suunta muuttuu. 
 sprite1.x = sprite1.x + sprite1Velocity.x; 
 if (sprite1.x> sprite1MaxX || sprite1.x <5) { 
 sprite1Velocity.x * = -1; 
 } 
 sprite1.y = sprite1.y + sprite1Velocity.y; 
 if (sprite1.y> sprite1MaxY || sprite1.y <5) { 
 sprite1Velocity.y * = -1; 
 } 
 sprite2.x = sprite2.x + sprite2Velocity.x; 
 if (sprite2.x> sprite2MaxX || sprite2.x <5) { 
 sprite2Velocity.x * = -1; 
 } 
 sprite2.y = sprite2.y + sprite2Velocity.y; 
 if (sprite2.y> sprite2MaxY || sprite2.y <5) { 
 sprite2Velocity.y * = -1; 
 } 
 ((GameBoard) findViewById (R.id. The_canvas )). SetSprite1 (sprite1.x, 
 sprite1.y); 
 ((GameBoard) findViewById (R.id. The_canvas )). SetSprite2 (sprite2.x, sprite2.y); 
 ((GameBoard) findViewById (R.id. The_canvas )). Kelpaa (); 
 frame.postDelayed (frameUpdate, FRAME_RATE ); 
 } 
 }; 
 } 

Jälleen kerran meillä on peli vakaassa pisteessä. Parempaa vielä, tällä hetkellä, kun suoritamme laitteella tai emulaattorilla, koodimme on tosiasiassa alkanut näyttää videopeliltä. Mene eteenpäin ja katso itse!

Huomaa kuinka asteroidi kulkee oikein laivan läpi? Se on ongelma. Puhumattakaan olisi kiva, jos sinulla olisi jonkin verran hallintaa lautaselle ja pienelle muukalaiselle kuljettajan istuimella. Käsittelemme molemmat tämän pelin kehityssarjan kahdessa viimeisessä osassa, joten muista tarkistaa se.

© Copyright 2020 | mobilegn.com