Beginning Android 4 Games Development 정리
채우기 콘텐츠 - 주의
소스 코드
beginning-android-games-2nd-edition (2).vol1.egg
beginning-android-games-2nd-edition (2).vol2.egg
기본 구조
Screen이 Game을 연관
AndroidGame이 Screen을 연관
AndroidGame 생성 이후 Screen이 생성
Listing 3–1. The Input Interface and the KeyEvent and TouchEvent Classes
package com.badlogic.androidgames.framework;
import java.util.List;
public interface Input {
public static class KeyEvent {
public static final int KEY_DOWN = 0;
public static final int KEY_UP = 1;
public int type;
public int keyCode;
public char keyChar;
}
public static class TouchEvent {
public static final int TOUCH_DOWN = 0;
public static final int TOUCH_UP = 1;
public static final int TOUCH_DRAGGED = 2;
public int type;
public int x, y;
public int pointer;
}
public boolean isKeyPressed(int keyCode);
public boolean isTouchDown(int pointer);
public int getTouchX(int pointer);
public int getTouchY(int pointer);
public float getAccelX();
public float getAccelY()
public float getAccelZ();
public List<KeyEvent> getKeyEvents();
public List<TouchEvent> getTouchEvents();
}
Listing 3–3. The Audio Interface
package com.badlogic.androidgames.framework;
public interface Audio {
public Music newMusic(String filename);
public Sound newSound(String filename);
}
Listing 3–4. The Music Interface
package com.badlogic.androidgames.framework;
public interface Music {
public void play();
public void stop();
public void pause();
public void setLooping(boolean looping);
public void setVolume(float volume);
public boolean isPlaying();
public boolean isStopped();
public boolean isLooping();
public void dispose();
}
Listing 3–5. The Sound Interface
package com.badlogic.androidgames.framework;
public interface Sound {
public void play(float volume);
,,,
public void dispose();
}
Listing 3–6. The Graphics Interface
package com.badlogic.androidgames.framework;
public interface Graphics {
public static enum PixmapFormat {
ARGB8888, ARGB4444, RGB565
}
public Pixmap newPixmap(String fileName, PixmapFormat format);
public void clear(int color);
public void drawPixel(int x, int y, int color);
public void drawLine(int x, int y, int x2, int y2, int color);
public void drawRect(int x, int y, int width, int height, int color);
public void drawPixmap(Pixmap pixmap, int x, int y, int srcX, int srcY,
int srcWidth, int srcHeight);
public void drawPixmap(Pixmap pixmap, int x, int y);
public int getWidth();
public int getHeight();
}
Listing 3–7. The Pixmap Interface
package com.badlogic.androidgames.framework;
import com.badlogic.androidgames.framework.Graphics.PixmapFormat;
public interface Pixmap {
public int getWidth();
public int getHeight();
public PixmapFormat getFormat();
public void dispose();
}
Listing 3–6. The Graphics Interface
package com.badlogic.androidgames.framework;
public interface Graphics {
public static enum PixmapFormat {
ARGB8888, ARGB4444, RGB565
}
public Pixmap newPixmap(String fileName, PixmapFormat format);
public void clear(int color);
public void drawPixel(int x, int y, int color);
public void drawLine(int x, int y, int x2, int y2, int color);
public void drawRect(int x, int y, int width, int height, int color);
public void drawPixmap(Pixmap pixmap, int x, int y, int srcX, int srcY,
int srcWidth, int srcHeight);
public void drawPixmap(Pixmap pixmap, int x, int y);
public int getWidth();
public int getHeight();
}
Listing 3–7. The Pixmap Interface
package com.badlogic.androidgames.framework;
import com.badlogic.androidgames.framework.Graphics.PixmapFormat;
public interface Pixmap {
public int getWidth();
public int getHeight();
public PixmapFormat getFormat();
public void dispose();
}
The Game Framework
pseudocode
createWindowAndUIComponent();
Input input = new Input();
Graphics graphics = new Graphics();
Audio audio = new Audio();
Screen currentScreen = new MainMenu();
Float lastFrameTime = currentTime();
while( !userQuit() ) {
float deltaTime = currentTime() – lastFrameTime;
lastFrameTime = currentTime();
currentScreen.updateState(input, deltaTime);
currentScreen.present(graphics, audio, deltaTime);
}
cleanupResources();
Listing 3–8. The Game Interface
package com.badlogic.androidgames.framework;
public interface Game {
public Input getInput();
public FileIO getFileIO();
public Graphics getGraphics();
public Audio getAudio();
public void setScreen(Screen screen);
public Screen getCurrentScreen();
public Screen getStartScreen();
}
Listing 3–9. The Screen Class
package com.badlogic.androidgames.framework;
public abstract class Screen {
protected final Game game;
public Screen(Game game) {
this.game = game;
}
public abstract void update(float deltaTime);
public abstract void present(float deltaTime);
public abstract void pause();
public abstract void resume();
public abstract void dispose();
}
A Simple Example
public class MySuperAwesomeStartScreen extends Screen {
Pixmap awesomePic;
int x;
public MySuperAwesomeStartScreen(Game game) {
super(game);
awesomePic = game.getGraphics().newPixmap("data/pic.png",
PixmapFormat.RGB565);
}
@Override
public void update(float deltaTime) {
x += 1;
if (x > 100)
x = 0;
}
@Override
public void present(float deltaTime) {
game.getGraphics().clear(0);
game.getGraphics().drawPixmap(awesomePic, x, 0, 0, 0,
awesomePic.getWidth(), awesomePic.getHeight());
}
@Override
public void pause() {
// nothing to do here
}
@Override
public void resume() {
// nothing to do here
}
@Override
public void dispose() {
awesomePic.dispose();
}
}
Frame Rate–Independent Movement
Instead of moving our Pixmap (or Mario) by a fixed amount each frame, we specify the movement speed in
units per second.
Say we want our Pixmap to advance 50 pixels per second.
@Override
public void update(float deltaTime) {
x += 50 * deltaTime;
if(x > 100)
x = 0;
}
Chapter 4
Android for Game Developers
Here’s the final AndroidManifest.xml content
<?xml version="1.0" encoding="utf-8"?>
package="com.badlogic.awesomegame"
android:versionCode="1"
android:versionName="1.0"
android:installLocation="preferExternal">
<application android:icon="@drawable/icon"
android:label="Awesomnium"
android:debuggable="true">
<activity android:name=".GameActivity"
android:label="Awesomnium"
android:screenOrientation="landscape"
android:configChanges="keyboard|keyboardHidden|orientation">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<uses-sdk android:minSdkVersion="3" android:targetSdkVersion="9"/>
</manifest>
Listing 4–1.AndroidBasicsStarter.java, Our Main Activity Responsible for Listing and Starting All Our Tests
package com.badlogic.androidgames;
import android.app.ListActivity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.ListView;
public class AndroidBasicsStarter extends ListActivity {
String tests[] = { "LifeCycleTest", "SingleTouchTest", "MultiTouchTest",
"KeyTest", "AccelerometerTest", "AssetsTest",
"ExternalStorageTest", "SoundPoolTest", "MediaPlayerTest",
"FullScreenTest", "RenderViewTest", "ShapeTest", "BitmapTest",
"FontTest", "SurfaceViewTest" };
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setListAdapter(new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1, tests));
}
@Override
protected void onListItemClick(ListView list, View view, int position,
long id) {
super.onListItemClick(list, view, position, id);
String testName = tests[position];
try {
Class clazz = Class.forName("com.badlogic.androidgames." + testName);
Intent intent = new Intent(this, clazz);
startActivity(intent);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
Processing Key Events
Listing 4–5.KeyTest.Java; Testing the Key Event API
package com.badlogic.androidgames;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import android.view.View.OnKeyListener;
import android.widget.TextView;
public class KeyTest extends Activity implements OnKeyListener {
StringBuilder builder = new StringBuilder();
TextView textView;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
textView = new TextView(this);
textView.setText("Press keys (if you have some)!");
textView.setOnKeyListener(this);
textView.setFocusableInTouchMode(true);
textView.requestFocus();
setContentView(textView);
}
@Override
public boolean onKey(View view, int keyCode, KeyEvent event) {
builder.setLength(0);
switch (event.getAction()) {
case KeyEvent.ACTION_DOWN:
builder.append("down, ");
break;
case KeyEvent.ACTION_UP:
builder.append("up, ");
break;
}
builder.append(event.getKeyCode());
builder.append(", ");
builder.append((char) event.getUnicodeChar());
String text = builder.toString();
Log.d("KeyTest", text);
textView.setText(text);
if (event.getKeyCode() == KeyEvent.KEYCODE_BACK)
return false;
else
return true;
}
}
Chapter 7
An Android Game Development Framework
Listing 5–1. AndroidFileIO.java; Implementing the FileIO Interface
package com.badlogic.androidgames.framework.impl;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.AssetManager;
import android.os.Environment;
import android.preference.PreferenceManager;
import com.badlogic.androidgames.framework.FileIO;
public class AndroidFileIO implements FileIO {
Context context;
AssetManager assets;
String externalStoragePath;
public AndroidFileIO(Context context) {
this.context = context;
this.assets = context.getAssets();
this.externalStoragePath = Environment.getExternalStorageDirectory()
.getAbsolutePath() + File.separator;
}
@Override
public InputStream readAsset(String fileName) throws IOException {
return assets.open(fileName);
}
@Override
public InputStream readFile(String fileName) throws IOException {
return new FileInputStream(externalStoragePath + fileName);
}
@Override
public OutputStream writeFile(String fileName) throws IOException {
return new FileOutputStream(externalStoragePath + fileName);
}
public SharedPreferences getPreferences() {
return PreferenceManager.getDefaultSharedPreferences(context);
}
}
Listing 5–2. AndroidAudio.java; Implementing the Audio Interface
package com.badlogic.androidgames.framework.impl;
import java.io.IOException;
import android.app.Activity;
import android.content.res.AssetFileDescriptor;
import android.content.res.AssetManager;
import android.media.AudioManager;
import android.media.SoundPool;
import com.badlogic.androidgames.framework.Audio;
import com.badlogic.androidgames.framework.Music;
import com.badlogic.androidgames.framework.Sound;
public class AndroidAudio implements Audio {
AssetManager assets;
SoundPool soundPool;
public AndroidAudio(Activity activity) {
activity.setVolumeControlStream(AudioManager.STREAM_MUSIC);
this.assets = activity.getAssets();
this.soundPool = new SoundPool(20, AudioManager.STREAM_MUSIC, 0);
}
@Override
public Music newMusic(String filename) {
try {
AssetFileDescriptor assetDescriptor = assets.openFd(filename);
return new AndroidMusic(assetDescriptor);
} catch (IOException e) {
throw new RuntimeException("Couldn't load music '" + filename + "'");
}
}
@Override
public Sound newSound(String filename) {
try {
AssetFileDescriptor assetDescriptor = assets.openFd(filename);
int soundId = soundPool.load(assetDescriptor, 0);
return new AndroidSound(soundPool, soundId);
} catch (IOException e) {
throw new RuntimeException("Couldn't load sound '" + filename + "'");
}
}
Listing 5–3. Implementing the Sound Interface using AndroidSound.java.
package com.badlogic.androidgames.framework.impl;
import android.media.SoundPool;
import com.badlogic.androidgames.framework.Sound;
public class AndroidSound implements Sound {
int soundId;
SoundPool soundPool;
public AndroidSound(SoundPool soundPool, int soundId) {
this.soundId = soundId;
this.soundPool = soundPool;
}
@Override
public void play(float volume) {
soundPool.play(soundId, volume, volume, 0, 0, 1);
}
@Override
public void dispose() {
soundPool.unload(soundId);
}
}
Listing 5–4. AndroidMusic.java; Implementing the Music Interface
package com.badlogic.androidgames.framework.impl;
import android.content.res.AssetFileDescriptor;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnCompletionListener;
import com.badlogic.androidgames.framework.Music;
public class AndroidMusic implements Music, OnCompletionListener {
MediaPlayer mediaPlayer;
boolean isPrepared = false;
public AndroidMusic(AssetFileDescriptor assetDescriptor) {
mediaPlayer = new MediaPlayer();
try {
mediaPlayer.setDataSource(assetDescriptor.getFileDescriptor(),
assetDescriptor.getStartOffset(),
assetDescriptor.getLength());
mediaPlayer.prepare();
isPrepared = true;
mediaPlayer.setOnCompletionListener(this);
} catch (Exception e) {
throw new RuntimeException("Couldn't load music");
}
}
@Override
public void dispose() {
if (mediaPlayer.isPlaying())
mediaPlayer.stop();
mediaPlayer.release();
}
@Override
public boolean isLooping() {
return mediaPlayer.isLooping();
}
@Override
public boolean isPlaying() {
return mediaPlayer.isPlaying();
}
@Override
public boolean isStopped() {
return !isPrepared;
}
@Override
public void pause() {
if (mediaPlayer.isPlaying())
mediaPlayer.pause();
}
@Override
public void play() {
if (mediaPlayer.isPlaying())
return;
try {
synchronized (this) {
if (!isPrepared)
mediaPlayer.prepare();
mediaPlayer.start();
}
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void setLooping(boolean isLooping) {
mediaPlayer.setLooping(isLooping);
}
@Override
public void setVolume(float volume) {
mediaPlayer.setVolume(volume, volume);
}
@Override
public void stop() {
mediaPlayer.stop();
synchronized (this) {
isPrepared = false;
}
}
@Override
public void onCompletion(MediaPlayer player) {
synchronized (this) {
isPrepared = false;
}
}
}