ABC'erne til Android-spiludvikling: Indlæs og vis sprites

Målet med spillet, vi udvikler i denne Android-app-udviklingsserie, er at justere den flyvende tallerkenes momentum for at undgå at blive smadret til biter af asteroiden. Dette projekt inkluderer alle de væsentlige aspekter af et videospil: et lærred, sprites, animation, kollisionsdetektion og brugerinput.

I første del skabte vi en tegningsflade og en ramme til styring og opdatering af indholdet af det lærred. Vi malede vores rumskala, smadrede den med tilfældige stjerner og fik endda disse stjerner til at pulsere. Det næste logiske trin i opbygningen af ​​vores spil er indlæsning og visning af sprites. I denne sammenhæng er en sprite "en computergrafik, der kan flyttes på skærmen og ellers manipuleres som en enkelt enhed."

I dokumentaren Indie Gamer beskriver en af ​​udviklerne processen med at fremstille et videospil meget som det at lave en film i mini-skala. Hvis du tænker på processen fra dette perspektiv, byggede vi i del et vores scene eller sæt. Sprites er de skuespillere, vi sætter ind i en scene og instruerer dem til at gøre noget interessant. Til vores formål bruger vi kun to sprites: en UFO ( figur A ) og en asteroide ( figur B ). Figur A

Figur B

Bemærk: Billederne ovenfor ser ud til at være en del af det offentlige domæne. Hvis du er kunstneren og kender anderledes, så kontakt mig, så giver jeg dig en attribution.

Indlæsning og visning af sprites

Denne tutorial bygger på det, vi oprettede i del 1. For virkelig at forstå, hvad der foregår, hjælper det med at se koden i sammenhæng med helheden. Derfor vil kodelisten i tutorial være vores komplette arbejdsgrundlag, med den nye kode kommenteret inline. Du kan følge med trinvis vejledning eller downloade og importere hele projektet til Eclipse.

1. Opret et nyt Android-projekt i Eclipse. Sørg for at målrette mod Android 2.1 eller nyere. Omdøb startaktiviteten til Main.java og den tilhørende layoutdefinition til main.xml.

2. Rediger filen AndroidManifest.xml for at tilsidesætte standardhåndteringen af ​​skærmorientering.

AndroidMainfest.xml

 "http://schemas.android.com/apk/res/android" package = "com.authorwjf.gamedevtut02" android: versionCode = "1" android: versionName = "1.0" > 

android: minSdkVersion = "8"

android: targetSdkVersion = "15" />

android: icon = "@ drawable / ic_launcher"

android: label = "@ streng / app_navn"

android: theme = "@ style / AppTheme" >

android: screenOrientation = "portræt"

android: configChanges = "orientering | tastatur skjult "

android: name = ".Main"

android: label = "@ string / title_activity_main" >

"android.intent.action.MAIN" />

"android.intent.category.LAUNCHER" />

3. Selvom der ikke er foretaget ændringer i vores /res/layout/main.xml-definition siden første del, er det igen for fuldstændighedens skyld.

main.xml

 "http://schemas.android.com/apk/res/android" android: layout_width = "fill_parent" android: layout_height = "fill_parent" android: orientering = "lodret" > 

android: layout_width = "wrap_content"

android: layout_height = "wrap_content"

android: layout_gravity = "top | center"

android: text = "ABC'er fra Android Game Dev" />

android: id = "@ + id / the_button"

android: layout_width = "wrap_content"

android: layout_height = "wrap_content"

android: layout_gravity = "center"

android: tyngdekraft = "center"

android: aktiveret = "falsk"

android: text = "Nulstil" />

android: layout_width = "wrap_content"

android: layout_height = "wrap_content"

android: layout_gravity = "center"

android: text = "Sprite Speed ​​(?, ?)"

android: id = "@ + id / the_label" />

android: layout_width = "wrap_content"

android: layout_height = "wrap_content"

android: layout_gravity = "center"

android: text = "Sidste kollision 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" />

4. Nu skal vi oprette en / res / drawable mappe. Her vil vi placere billederne: ufo.png og asteroid.png. Mens jeg bruger en enkelt mappe, der kan tegnes i denne demokode, hvis du frigiver et spil på markedet, vil du oprette flere versioner af disse billeder i forskellige opløsninger og sætte dem i mapperne ldpi, mdpi, hdpi og xhdpi som passende. Hvis dette er din første gang, du arbejder med Android-ressourcer, anbefaler jeg stærkt at du læser Googles dokumentation om understøttelse af flere skærme.

5. Lad os se på de ændringer, vi foretager i vores /src/GameBoard.Java-klasse. Husk fra første del, denne klasse findes i sin egen pakke: com.authorwjf.drawing.

Først skal vi tilføje private variabler for at holde styr på vores sprite-positioner. Dernæst udsætter vi disse egenskaber for controlleren (Main.java) ved hjælp af en række getters og setters. Derefter indlæser vi i vores konstruktør bitmap-billeder, der repræsenterer vores sprite. Til sidst, i on draw-løkken, maler vi sprites på lærredet. Sprites skal tegnes sidst, så baggrunden ikke skjuler dem.

Nedenfor er hele kildelisten for GameBoard-klassen, med den kode, der er specifik for denne tutorial, fremhævet.

GameBoard.java

 pakke com.authorwjf.drawing; import java.util.ArrayList; import java.util.List; import java.util.Random; import com.authorwjf.gamedevtut02.R; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Point; import android.graphics.Rect; import android.util.AttributeSet; import android.view.View; offentlig klasse GameBoard udvider Vis { privat Paint p; privat liste starField = null ; privat int starAlpha = 80; privat int starFade = 2; 

// Tilføj private variabler for at holde trit med sprite position og størrelse

privat Rect sprite1Bounds = ny Rect (0, 0, 0, 0); privat Rect sprite2Bounds = ny Rect (0, 0, 0, 0); privat punkt sprite1; privat punkt sprite2;

// Bitmaps, der indeholder de faktiske sprite-billeder

privat Bitmap bm1 = null ; privat Bitmap bm2 = null ; privat statisk endelig int NUM_OF_STARS = 25;

// Lad vores controller få og indstille sprite-positioner

// sprite 1 setter

synkroniseret offentligt ugyldigt sætSprite1 (punkt p) {

sprite1 = p;

}

// sprite 1 getter

synkroniseret offentligt punkt getSprite1 () { return sprite1;

}

// sprite 2 setter

synkroniseret offentligt ugyldigt sætSprite2 (punkt p) {

sprite2 = p;

}

// sprite 2 getter

synkroniseret offentligt punkt getSprite2 () { return sprite2;

}

synkroniseret offentligt tomrum resetStarField () {starField = null ;

}

// udsæt sprite-grænser for controller

synkroniseret offentligt int getSprite1Width () { return sprite1Bounds.width ();

}

synkroniseret offentlig int getSprite1Height () { return sprite1Bounds.height ();

}

synkroniseret offentlig int getSprite2Width () { return sprite2Bounds.width ();

}

synkroniseret offentlig int getSprite2Height () { return sprite2Bounds.height ();

}

offentlig GameBoard (kontekstkontekst, AttributeSet aSet) { super (context, aSet); p = ny maling ();

// indlæse vores bitmaps og indstil grænserne for controlleren

sprite1 = nyt punkt (-1, -1); sprite2 = nyt punkt (-1, -1); p = ny maling ();

bm1 = BitmapFactory. dekodeResource (getResources (), R. udtrækkelig. asteroide );

bm2 = BitmapFactory. decodeResource (getResources (), R.drawable. ufo );

sprite1Bounds = ny Rect (0, 0, bm1.getWidth (), bm1.getHeight ()); sprite2Bounds = ny Rect (0, 0, bm2.getWidth (), bm2.getHeight ());

}

private void initializeStars ( int maxX, int maxY) {starField = new ArrayList (); for ( int i = 0; i < NUM_OF_STARS ; i ++) {Tilfældig r = ny tilfældig (); int x = r.nextInt (maxX-5 + 1) +5; int y = r.nextInt (maxY-5 + 1) +5; starField.add ( nyt punkt (x, y));

}

}

@Override

synkroniseret offentligt tomrum onDraw (lærred lærred) {

p.setColor (farve. SORT );

p.setAlpha (255);

p.setStrokeWidth (1);

canvas.drawRect (0, 0, getWidth (), getHeight (), p);

if (starField == null ) {

initialisereStars (canvas.getWidth (), canvas.getHeight ());

}

p.setColor (farve. CYAN );

p.setAlpha (starAlpha + = starFade);

if (starAlpha> = 252 || starAlpha <= 80) starFade = starFade * -1;

p.setStrokeWidth (5);

for ( int i = 0; i < NUM_OF_STARS ; i ++) {

canvas.drawPoint (starField.get (i) .x, starField.get (i) .y, p);

}

// Nu tegner vi vores sprites. Elementer, der tegnes i denne funktion, stables.

// Elementerne, der er trukket øverst på løkken, er i bunden af ​​z-ordren.

// Derfor tegner vi vores sæt, så vores skuespillere og til sidst enhver fx. if (sprite1.x> = 0) {canvas.drawBitmap (bm1, sprite1.x, sprite1.y, null );

}

if (sprite2.x> = 0) {canvas.drawBitmap (bm2, sprite2.x, sprite2.y, null );

}

}

}

6. Rediger Main.java for at tildele start x- og y-koordinater til vores sprites. Metoden getRandomPoint () returnerer en tilfældig x og y, der falder inden for lærredets grænser. Vi bruger derefter et stykke tidsløkke for at sikre, at den oprindelige placering af vores sprites ikke overlapper hinanden.

Main.java

 pakke com.authorwjf.gamedevtut02; import java.util.Random; import com.authorwjf.drawing.GameBoard; import android.os.Bundle; import android.os.Handler; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.app.Aktivitet; import android.graphics.Point; public class Main udvider Aktivitetsimplementerer OnClickListener { private Handler frame = new Handler (); 

// Del rammen med 1000 for at beregne, hvor mange gange i sekundet skærmen opdateres.

privat statisk endelig int FRAME_RATE = 20; // 50 billeder i sekundet

@Override

public void onCreate (Bundle gemtInstanceState) { super .onCreate (gemtInstanceState);

setContentView (R.layout. main );

Håndterer h = ny Håndterer (); ((Knap) findViewById (R.id. The_button )). SetOnClickListener ( dette );

// Vi kan ikke initialisere grafikken med det samme, fordi layoutadministratoren

// har brug for at køre først, så ring tilbage på et sekund. h.postDelayed ( nyt Runnable () {

@Override

offentlig annullering () {

initGfx ();

}

}, 1000);

}

privat punkt getRandomPoint () {Tilfældig r = ny Tilfældig (); 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.nextInt (maxX-minX + 1) + minX;

y = r.nextInt (maxY-minY + 1) + minY;

returnere nyt punkt (x, y);

}

synkroniseret offentligt tomrum initGfx () {

((GameBoard) findViewById (R.id. The_canvas )). ResetStarField ();

// Vælg to tilfældige punkter til vores indledende sprite-placering.

// Løkken er bare for at sikre, at vi ikke ved et uheld vælger

// to punkter, der overlapper hinanden.

Punkt p1, p2;

gør {

p1 = getRandomPoint ();

p2 = getRandomPoint ();

} while (Math. abs (p1.x - p2.x) <

((GameBoard) findViewById (R.id. The_canvas )). GetSprite1Width ());

((GameBoard) findViewById (R.id. The_canvas )). SetSprite1 (p1);

((GameBoard) findViewById (R.id. The_canvas )). SetSprite2 (p2);

((Knap) findViewById (R.id. The_button )). SetEnabled ( sand );

frame.removeCallbacks (frameUpdate);

frame.postDelayed (frameUpdate, FRAME_RATE );

}

@Override

synkroniseret offentligt tomrum onClick (Vis v) {

initGfx ();

}

private Runnable frameUpdate = new Runnable () {

@Override

synkroniseret offentligt tomrumsløb () {

frame.removeCallbacks (frameUpdate);

// foretage eventuelle opdateringer til skærmobjekter her

// påkald derefter on-draw ved at ugyldige lærredet

((GameBoard) findViewById (R.id. The_canvas )). Ugyldig ();

frame.postDelayed (frameUpdate, FRAME_RATE );

}

};

}

Vores spilkode har nået et godt stoppunkt. Du kan indlæse den på din enhed eller emulator. Denne gang når du trykker på nulstillingsknappen, tager vores skuespillere deres plads.

Hold øje med del 3 af denne tutorial, hvor instruktøren vil råbe "action", og vi begynder at animere spilobjekterne.

© Copyright 2021 | pepebotifarra.com