ããã«ã¡ã¯ãHabrã®äœæ°ïŒ
仿¥ã¯ãAndroidåãã®ã²ãŒã ã䟿å©ã«éçºããããã®Mechanic Frameworkãšãããã¬ãŒã ã¯ãŒã¯ãäœæããŸãã

å¿
èŠãªãã®ïŒ
- Eclipseããã³Android SDKãã€ã³ã¹ããŒã«ãããŠãã
- JavaãŸãã¯å¥ã®Cã©ã€ã¯ãªèšèªã«é¢ããååãªç¥èã æè¯ã®äŸ-CïŒ
- å¿è
ãŸãããããžã§ã¯ããäœæããŸãã
ãã¡ã€ã«-æ°èŠ-ãã®ä»-Androidã¢ããªã±ãŒã·ã§ã³ãããžã§ã¯ã

[æ°ããAndroidã¢ããªã±ãŒã·ã§ã³]ãŠã£ã³ããŠã衚瀺ãããŸãã ä»»æã®ååïŒããšãã°ãMechanicïŒãå
¥åããããã±ãŒãžã«ååãä»ããŠãã¢ããªã±ãŒã·ã§ã³ã®æå°ããŒãžã§ã³ã®Androidãšã¿ãŒã²ããããŒãžã§ã³ãéžæãã[次ãž]ãã¯ãªãã¯ããŸãã

次ãžãã¯ãªãã¯ããŸãã

ã¢ã€ã³ã³ãéžæããŸãïŒAndroidã¢ã€ã³ã³ãæ°ã«å
¥ããªãå Žåã¯ã[ã¯ãªããã¢ãŒã-äœããéžæããŠéžæãã]ãã¯ãªãã¯ããããç¬èªã®ã¢ã€ã³ã³ãé
眮ããŸãïŒã

次ãžãã¯ãªãã¯ããŸãã

ã¢ã¯ãã£ããã£ã®ååïŒMyGameãªã©ïŒãéžæãã[å®äº]ãã¯ãªãã¯ããŸãã
.xmlããžã¥ã¢ã«ç·šéãŠã£ã³ããŠãéããéããŸãã
AndroidManifest.xmlãéããå¿
èŠã«å¿ããŠã«ã¹ã¿ãã€ãºããŸãã

å¯èœãªå Žåã¯ã²ãŒã ãã¡ã¢ãªã«ãŒãã«ã€ã³ã¹ããŒã«ããããã€ã¹ã®å
éšã¡ã¢ãªãæ±æããªãããã«ããã«ã¯ãmanifestãã£ãŒã«ãã«æžã蟌ã¿ãŸã
android:installLocation="preferExternal"
ãããã°ã®ããã«ã¢ããªã±ãŒã·ã§ã³ã«ã¢ã¯ã»ã¹ã§ããããã«ããã«ã¯ãapplicationãã£ãŒã«ãã«æžã蟌ã¿ãŸã
android:debuggable="true"
ã¢ããªã±ãŒã·ã§ã³ãããŒãã¬ãŒãã¢ãŒããŸãã¯ã©ã³ãã¹ã±ãŒãã¢ãŒãïŒãã®å Žåã¯ã©ã³ãã¹ã±ãŒãã¢ãŒãïŒã«åºå®ããã«ã¯ãã¢ã¯ãã£ããã£ãã£ãŒã«ãã«æ¬¡ã®ããã«èšè¿°ããŸãã
android:screenOrientation="landscape"
ãšãã¥ã¬ãŒã¿äžã®ã¢ããªã±ãŒã·ã§ã³ãããŒããŒãã¢ã¯ã·ã§ã³ãåŠçããããã«ãåããã£ãŒã«ãã«æžã蟌ã¿ãŸã
android:configChanges="keyboard|keyboardHidden|orientation"
Google Playããã¢ããªã±ãŒã·ã§ã³ãããŠã³ããŒããããšãã¢ããªã±ãŒã·ã§ã³ãã¡ã¢ãªã«ãŒã/ã€ã³ã¿ãŒããããªã©ã«ã¢ã¯ã»ã¹ããå¿
èŠãããããšã«æ°ã¥ããŸãããã®ãããã¡ã¢ãªã«ãŒããå¶åŸ¡ããã¢ã€ãã«æã«ç»é¢ãããã¯ãããªãããã«ããããã«ã
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.WAKE_LOCK"/>
ãããã§ã¹ãã¯æ¬¡ã®ããã«ãªããŸã
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.frame" android:versionCode="1" android:versionName="1.0" android:installLocation="preferExternal"> <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="18" /> <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" android:debuggable="true" > <activity android:name="com.frame.MyGame" android:screenOrientation="landscape" android:configChanges="keyboard|keyboardHidden|orientation" android:label="@string/app_name" > <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"/> </manifest>
ãããã§ã¹ããéããŸã
ããã§ããã¬ãŒã ã¯ãŒã¯ãã¬ãŒã ã¯ãŒã¯ãäœæããå¿
èŠããããŸããããã¯ãå
¥åãã°ã©ãã£ãã¯ã¹ã®ã¬ã³ããªã³ã°ãªã©ãå¶åŸ¡ããåŸã§ãã¹ãŠã®ã€ã³ã¿ãŒãã§ã€ã¹ãå®è£
ããã€ã³ã¿ãŒãã§ã€ã¹ã§ãã

å
¥ã
com.mechanic.inputãšããæ°ããããã±ãŒãžãäœæããŸã
ãã®ããã±ãŒãžã«å
¥åã€ã³ã¿ãŒãã§ã€ã¹ãäœæãããã®ãã©ãŒã ã«è¿œå ããŸã
public interface Input { public static class MechanicKeyEvent { public static final int KEY_DOWN = 0, KEY_UP = 1; public int Type; public int KeyCode; public char KeyChar; } public static class MechanicTouchEvent { public static final int TOUCH_DOWN = 0, TOUCH_UP = 1, TOUCH_DRAGGED = 2; public int Type; public int X, Y; public int Pointer; } public boolean IsKeyPressed(int KeyCode); public boolean IsKeyPressed(char KeyChar); 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<MechanicTouchEvent> GetTouchEvents(); public List<MechanicKeyEvent> GetKeyEvents(); }
GetKeyDown-ããŒã«å€ãããŒã³ãŒããåãå
¥ãããã¿ã³ãæŒããããštrueãè¿ããŸã
GetTouchDown-ããŒã«å€ãç»é¢ãæŒããããštrueãè¿ãããã®é¢æ°ã¯ç»é¢ãæŒããæã®çªå·ãååŸããŸãã å€ãããŒãžã§ã³ã®Androidã¯ãã«ãã¿ããããµããŒãããŠããŸããã
GetTouchX-æŒãããããŒã®X座æšãè¿ããŸã
GetTouchY-æŒãããããŒã®Y座æšãè¿ããŸã
äž¡æ¹ã®æåŸã®æ©èœã¯æã®çªå·ãåãå
¥ã
GetAccelXãGetAccelYãGetAccelZ-å é床èšã®ä»»æã®åº§æšã§å é床ãè¿ããŸãã æºåž¯é»è©±ã瞊æ¹åã«åçŽã«ä¿æãããšãYè»žã«æ²¿ã£ãå é床ã¯9.6 m / s2ã«ãªããX軞ãšZè»žã«æ²¿ã£ãŠ0 m / s2ã«ãªããŸãã
MechanicKeyEventãšMechanicTouchEventãã芧ãã ãã
æåã®ã¯ã©ã¹ã«ã¯ãäž»èŠãªã€ãã³ãæ
å ±ãæ ŒçŽãããŸãã ã¿ã€ãã¯åžžã«KEY_DOWNãŸãã¯KEY_UPã®ããããã§ãã KeyCodeãšKeyCharã¯ãããããæ°å€ãšæååã§ããŒå€ãä¿åããŸãã
2çªç®ã®ã¯ã©ã¹ã§ã¯ãXãšYã¯ç»é¢ãæŒãæã®åº§æšã§ãããã€ã³ã¿ãŒã¯æã®çªå·ã§ãã TOUCH_DRAGGEDã¯ãæãåããããšãæå³ããŸãã
æ°ãæ£ãããŠãå
¥åã€ã³ã¿ãŒãã§ã€ã¹ãã©ã®ããã«èª¿æŽããããã«ã€ããŠè©±ã䟡å€ããããŸãã
å é床èšãããŒããŒããããã³ç»é¢ã®ã¿ããã®å Žåã責任ãããã®ã¯å
¥åãå®è£
ããã¯ã©ã¹ã§ã¯ãªããããããå é床èšãããŒããŒããããã³ã¿ããã€ã³ã¿ãŒãã§ã€ã¹ãå®è£
ããã¯ã©ã¹ã§ãã å
¥åã¯ãããã®ã¯ã©ã¹ã®ã€ã³ã¹ã¿ã³ã¹ãä¿åããã ãã§ãã ãã¶ã€ã³ãã¿ãŒã³ã«ç²ŸéããŠããå ŽåãåçŽãªããã¡ãµãŒãããã¿ãŒã³ããã®æ¹æ³ã§å®è£
ãããŠããããšãç¥ã£ãŠããå¿
èŠããããŸãã
ãããã¯ã€ã³ã¿ãŒãã§ãŒã¹ã§ã
public interface Accelerometer extends SensorEventListener { public float GetAccelX(); public float GetAccelY(); public float GetAccelZ(); }
public interface Keyboard extends OnKeyListener { public boolean IsKeyPressed(int keyCode); public List<KeyEvent> GetKeyEvents(); }
public interface Touch extends OnTouchListener { public boolean IsTouchDown(int pointer); public int GetTouchX(int pointer); public int GetTouchY(int pointer); public List<TouchEvent> GetTouchEvents(); }
Inputã¯åã«ã¡ãœãããä»ã®ã¯ã©ã¹ã«ãªãã€ã¬ã¯ãããã ãã§ããããããã¯æ£çŽã«åäœããçµæãã¬ã€ã¢ãŠããããšæšæž¬ããã®ã¯ç°¡åã§ãã
ãã¡ã€ã«
ãã¡ã€ã«ãæäœããæéã§ãã Fileã¯ã©ã¹ãæ¢ã«ååšãããããã€ã³ã¿ãŒãã§ã€ã¹ã¯FileIOãšåŒã°ããŸãã
æ°ããããã±ãŒãžcom.mechanic.fileioãšãã®äžã«æ°ããã€ã³ã¿ãŒãã§ãŒã¹ãäœæããŸã
public interface FileIO { public InputStream ReadAsset(String name) throws IOException; public InputStream ReadFile(String name) throws IOException; public OutputStream WriteFile(String name) throws IOException; }
éåžžããã¹ãŠã®ç»åãé³å£°ããã®ä»ã®ãã¡ã€ã«ã¯ãããžã§ã¯ãã¢ã»ãããã©ã«ããŒã«ä¿åããŸãã æåã®é¢æ°ã¯ãã¢ã»ããããæå®ãããååã®ãã¡ã€ã«ãéããAssetsManagerã§ã®äžå¿
èŠãªãã©ãã«ãåé¿ããŸãã æåŸã®2ã€ã®æ©èœã¯ãããšãã°ã¬ã³ãŒããä¿åããããã«å¿
èŠã§ãã ããŒã¿ãä¿åãããšããããã€ã¹ã®ã¹ãã¬ãŒãžã«æ
å ±ãå«ãããã¹ããã¡ã€ã«ãæžã蟌ã¿ããããèªã¿åããŸãã 念ã®ãããããmechanicsaveããªã©ããfile.txtãããããªãªãžãã«ã®ãã¡ã€ã«åãèããŠã¿ãŠãã ãã-ãããå¯èœã§ãã
é³
ããã±ãŒãžcom.mechanic.audioãšæ°ãããªãŒãã£ãªã€ã³ã¿ãŒãã§ã€ã¹ãäœæããŸã
public interface Audio { public Music NewMusic(String name); public Sound NewSound(String name); }
ãµãŠã³ãã®ä¿åãšåçã«ã¯2ã€ã®ãªãã·ã§ã³ããããŸãã æåã®ãªãã·ã§ã³ã¯ããµãŠã³ããããŒãããŠåçãããšãã®éåžžã®ãªãã·ã§ã³ã§ãããã»ãšãã©ã®å Žåããã®ã¢ãããŒãã¯ã·ã§ãããççºã®ãããªå°ããªãµãŠã³ãã«é©ããŠãããããã¯ã°ã©ãŠã³ããã¥ãŒãžãã¯ã®ãããªå€§ããªãµãŠã³ããã¡ã€ã«ã«ã¯ãµãŠã³ããå®å
šã«ããŒãããæå³ããããŸãããåçã«ãµãŠã³ããèªã¿èŸŒãã§åçããŸãã æåãš2çªç®ã®ãªãã·ã§ã³ã§ã¯ããµãŠã³ããšé³æ¥œã®ã€ã³ã¿ãŒãã§ã€ã¹ããããã責任ãè² ããŸãã å®çŸ©ã¯æ¬¡ã®ãšããã§ã
public interface Sound { public void Play(float volume); public void Close(); }
public interface Music extends OnCompletionListener { public void Close(); public boolean IsLooping(); public boolean IsPlaying(); public boolean IsStopped(); public void Play(); public void SetLooping(boolean loop); public void SetVolume(float volume); public void Stop(); }
ã°ã©ãã£ãã¯ã¹
ããã±ãŒãžcom.mechanic.graphicsãäœæããŸã
ã°ã©ãã£ãã¯ã¹ã€ã³ã¿ãŒãã§ã€ã¹ã¯ãäž»ã«ã°ã©ãã£ãã¯ã¹ãæ
åœããŸãã
ããã«åœŒã®å®çŸ©ããããŸã
public interface Graphics { public static enum ImageFormat { ARGB_8888, ARGB_4444, RGB_565 } public Image NewImage(String fileName); 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 DrawImage(Image image, int x, int y, int srcX, int srcY, int srcWidth, int srcHeight); public void DrawImage(Image image, int x, int y); public int GetWidth(); public int GetHeight(); }
ImageFormatã¯ãç»åã®ããŒãæ¹æ³ãç°¡åã«éžæã§ããåæåã§ãã å®éãç¹å¥ãªããšã¯äœãããŸãããã圢åŒãæž¡ãå Žæã®åæã«ã¯ãäžèŠãªã¡ãœãããšäžèŠãªååConfigãããããããã®ã§ãããããŸãã
NewImageã¯æ°ããç»åãè¿ããŸãã倿°ã«ä¿åããŠæç»ããŸã
Draw ...ãšããååã®ã¡ãœããã¯ããèªäœã衚ããŠãããæåã®DrawImageã¡ãœããã¯ç»åã®äžéšã®ã¿ãæç»ãã2çªç®ã®ã¡ãœããã¯ç»åå
šäœãæç»ããŸãã
GetWidthãšGetHeightã¯ãç»åãæãããã£ã³ãã¹ãã®ãµã€ãºãè¿ããŸã
å¥ã®ã€ã³ã¿ãŒãã§ã€ã¹ããããŸã-åççš
public interface Image { public int GetWidth(); public int GetHeight(); public ImageFormat GetFormat(); public void Dispose(); }
ãã¹ãŠãååã«éåŒã§ã
äžå
åãããã²ãŒã 管ç
ããã±ãŒãžcom.mechanic.gameãäœæããŸã
ã¢ããªã±ãŒã·ã§ã³å
šäœã®æäœããµããŒãããæåŸãã2çªç®ã®éèŠãªã€ã³ã¿ãŒãã§ãŒã¹ããããŸã-ã²ãŒã
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(); }
éå»ã®ç« ã®ããŒã-ç§ãã¡ã¯ã¡ããã©ããã«ã€ã³ã¿ãŒãã§ã€ã¹ãçªãåºããŸãã
ããããã¹ã¯ãªãŒã³ãšã¯äœã§ããïŒ
æ°ãåãããŠãã ããã ã»ãšãã©ãã¹ãŠã®ã²ãŒã ã¯ãã¡ã€ã³ã¡ãã¥ãŒãèšå®ã¡ãã¥ãŒããã€ã¹ã³ã¢ç»é¢ããã¹ãŠã®ã¬ãã«ãªã©ãããã€ãã®ãç¶æ
ãã§æ§æãããŠããŸãã ãªã© å°ãªããšã5ã€ã®ç¶æ
ããµããŒãããããšã§ãã³ãŒãã®æ·±byã«æµžãããšãã§ããã®ãäžæè°ã§ã¯ãããŸããã ç»é¢æœè±¡ã¯ã©ã¹ã¯ç§ãã¡ãæããŸã
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(); }
åç»é¢ã®åå«ïŒMainMenuScreenãSettingsScreenïŒã¯ããã®ãç¶æ
ããæ
åœããŸãã ããã€ãã®æ©èœããããŸãã
æŽæ°-æŽæ°
çŸåš-ã°ã©ãã£ãã¯ã®è¡šç€ºïŒäŸ¿å®äžãå°å
¥ããããã®ã§ãå®éããã®é¢æ°ã¯åã®ãã®ãšåæ§ã«åŒã³åºãããŸãïŒ
äžæåæ¢-ã²ãŒã ãäžæåæ¢ããããã³ã«åŒã³åºãããŸãïŒç»é¢ãããã¯ïŒ
åé-äžæåæ¢åŸã®ã²ãŒã ã®ç¶ç¶
ç Žæ£-ããŠã³ããŒãããç»åãªã©ããã¹ãŠã®ãªãœãŒã¹ãè§£æŸããŸã
2ã€ã®é¢æ°ã§æž¡ãããdeltaTimeã«ã€ããŠå°ã話ã䟡å€ããããŸãã
ããæŽç·Žãããã²ãŒã éçºè
ã¯ãã²ãŒã ã®é床ïŒããšãã°ããã¬ã€ã€ãŒã®åãïŒãããã€ã¹ã®é床ã«çŽæ¥äŸåããå Žåãã€ãŸã ãµã€ã¯ã«ããšã«å€æ°xã1ãã€å¢ãããšããããããã¯ãšå·šå€§ãªRAMãæèŒããã³ã³ãã¥ãŒã¿ãŒã§ã²ãŒã ãåãããã«åäœããããšã¯ãããŸããã
ãããã£ãŠãtruããªã¢ã³ãã¯æ¬¡ã®ãšããã§ãã
@Override public void Update(float deltaTime) { x += 150 * deltaTime; }
truããªã¢ã³ãã§ã¯ãããŸããïŒ
@Override public void Update(float deltaTime) { x += 150; }
åºæ¬ãšã©ãŒã1ã€ãããŸã-éåžžã«å€ãã®å Žåãxã1.0f * deltaTimeå¢ãããŸããã0ãã1ã®éæŽæ°ã«æŽæ°ã远å ããŠãçµæãåŸãããªãããšã«æ°ä»ããªãå ŽåããããŸãã
ç»é¢ãã©ã®ããã«å€æŽããŸããïŒ ã²ãŒã ã€ã³ã¿ãŒãã§ãŒã¹ã«æ»ã
SetScreen颿°ã¯ãã¹ãŠã«è²¬ä»»ããããŸãã çŸåšã®ç»é¢ãšéå§ç»é¢ãååŸããæ©èœããããŸãã
ãã®ã³ã¬ã¯ã·ã§ã³å
šäœãå®è£
ããæãæ¥ãŸããïŒ
å
¥åããŠéå§
Inputã€ã³ã¿ãŒãã§ã€ã¹ã«ã¯ãã€ãã³ãã®ãªã¹ããè¿ãGetKeyEventsããã³GetTouchEvents颿°ããããŸããã€ãŸããã€ãã³ããçºçãããšãããã°ã©ã ã¯å€ãã®ãªããžã§ã¯ããäœæããã¬ããŒãžã³ã¬ã¯ã¿ãŒãã¯ãªãŒã³ã¢ããããŸãã Androidã¢ããªã±ãŒã·ã§ã³ã®ãã¬ãŒãããããäž»ãªçç±ã¯äœã§ããïŒ ããã§ã-ã¬ããŒãžã³ã¬ã¯ã¿ãŒãéè² è·ã«ãªã£ãŠããŸãïŒ äœãšãåé¡ãå¶åŸ¡ããå¿
èŠããããŸãã ç¶è¡ããåã«ãPoolã¯ã©ã¹ãäœæããããªããžã§ã¯ãããŒãªã³ã°ããå®è£
ããŸããããã¯ãMario Tsechnerã®åªããæžç±ãProgramming Games for Androidãã§ææ¡ãããŠããŸãã
ãã®æå³ã¯ãã¬ããŒãžã³ã¬ã¯ã¿ãŒãã¢ããªã±ãŒã·ã§ã³ã«å¹²æžããããšãèš±å¯ãããå¿
èŠãªãªãœãŒã¹ãç¡é§ã«ããªãããšã§ãã
public class Pool<T> { public interface PoolFactory<T> { public T Create(); } private final List<T> Objects; private final PoolFactory<T> Factory; private final int MaxSize; public Pool(PoolFactory<T> Factory, int MaxSize) { this.Factory = Factory; this.MaxSize = MaxSize; Objects = new ArrayList<T>(MaxSize); } public T NewObject() { T obj = null; if (Objects.size() == 0) obj = Factory.Create(); else obj = Objects.remove(Objects.size() - 1); return obj; } public void Free(T object) { if (Objects.size() < MaxSize) Objects.add(object); } }
ããŒã«ããŒã«ãªããžã§ã¯ãããããšããŸãã ãããç§ãã¡ã®äœ¿ãæ¹ã§ã
PoolFactory<MechanicTouchEvent> factory = new PoolFactory<MechanicTouchEvent>() { @Override public MechanicTouchEvent Create() { return new MechanicTouchEvent(); } }; TouchEventPool = new Pool<MechanicTouchEvent>(factory, 100);
ããŒã«å®£èš
TouchEventPool.Free(event);
ã€ãã³ããããŒã«ã«ä¿åãã
event = TouchEventPool.NewObject();
ããŒã«ããã€ãã³ããååŸããŸãã ãªã¹ãã空ã®å Žåãã€ãã³ãã䜿çšããåŸã次ã®åŒã³åºããŸã§ããŒã«ã«æ»ãã®ã§ãããã¯æãããšã§ã¯ãããŸããã
ãšãŠãè¯ãããšã§ãïŒ
ã¡ã«ããã¯å é床èš
package com.mechanic.input; import android.content.Context; import android.hardware.Sensor; import android.hardware.SensorEvent; import android.hardware.SensorManager; public class MechanicAccelerometer implements Accelerometer { float accelX, accelY, accelZ; public MechanicAccelerometer(Context context) { SensorManager manager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE); if(manager.getSensorList(Sensor.TYPE_ACCELEROMETER).size() > 0) { Sensor accelerometer = manager.getSensorList(Sensor.TYPE_ACCELEROMETER).get(0); manager.registerListener(this, accelerometer, SensorManager.SENSOR_DELAY_GAME); } } @Override public void onAccuracyChanged(Sensor sensor, int accuracy) { } @Override public void onSensorChanged(SensorEvent event) { accelX = event.values[0]; accelY = event.values[1]; accelZ = event.values[2]; } @Override public float GetAccelX() { return accelX; } @Override public float GetAccelY() { return accelY; } @Override public float GetAccelZ() { return accelZ; } }
å é床èšã«å ããŠããã®ã¯ã©ã¹ã¯SensorEventListenerãå®è£
ããŸããå é床èšã ãã§ãªããã³ã³ãã¹ãæäžé»ç¯ããã®ä»ã®ããã¡ããå¶åŸ¡ããå¿
èŠããããŸãã ãããŸã§ã®ãšãããå é床èšã®ã¿ãå®è¡ããŠããŸãã
ã³ã³ã¹ãã©ã¯ã¿ãŒã§ãã»ã³ãµãŒãããŒãžã£ãŒãååŸããå é床èšãžã®ã¢ã¯ã»ã¹ããããã©ããã確èªããŸãã äžè¬ã«ãçè«çã«ã¯ã1ã€ã§ã¯ãªãè€æ°ã®å é床èšïŒããã¯ãªã¹ãã§ããã1ã€ã®ãªããžã§ã¯ãã§ã¯ãããŸããïŒãå®éã«ã¯åžžã«1ã€ã§ãã å é床èšã®æ°ã0ãã倧ããå Žåãæåã®å é床èšãååŸããŠç»é²ãããã®ã¯ã©ã¹ããªã¹ããŒãšããŠå
¬éããŸãã onAccuracyChangedãå¿
èŠã§ããã»ã³ãµãŒã®ç²ŸåºŠã倱ãããå Žåã䜿çšããŸããã onSensorChangedã¯ãå é床èšã®å€ãå€åãããšåžžã«åŒã³åºãããŸããããã§ã¯ãèªã¿åãå€ãååŸããŸãã
MechanicTouch
package com.mechanic.input; import java.util.ArrayList; import java.util.List; import com.mechanic.input.Input.MechanicTouchEvent; import com.mechanic.input.Pool.PoolFactory; import android.os.Build.VERSION; import android.view.MotionEvent; import android.view.View; public class MechanicTouch implements Touch { boolean EnableMultiTouch; final int MaxTouchers = 20; boolean[] IsTouched = new boolean[MaxTouchers]; int[] TouchX = new int[MaxTouchers]; int[] TouchY = new int[MaxTouchers]; Pool<MechanicTouchEvent> TouchEventPool; List<MechanicTouchEvent> TouchEvents = new ArrayList<MechanicTouchEvent>(); List<MechanicTouchEvent> TouchEventsBuffer = new ArrayList<MechanicTouchEvent>(); float ScaleX; float ScaleY; public MechanicTouch(View view, float scaleX, float scaleY) { if(Integer.parseInt(VERSION.SDK) < 5) EnableMultiTouch = false; else EnableMultiTouch = true; PoolFactory<MechanicTouchEvent> factory = new PoolFactory<MechanicTouchEvent>() { @Override public MechanicTouchEvent Create() { return new MechanicTouchEvent(); } }; TouchEventPool = new Pool<MechanicTouchEvent>(factory, 100); view.setOnTouchListener(this); this.ScaleX = scaleX; this.ScaleY = scaleY; } @Override public boolean onTouch(View v, MotionEvent event) { synchronized (this) { int action = event.getAction() & MotionEvent.ACTION_MASK; @SuppressWarnings("deprecation") int pointerIndex = (event.getAction() & MotionEvent.ACTION_POINTER_ID_MASK) >> MotionEvent.ACTION_POINTER_ID_SHIFT; int pointerId = event.getPointerId(pointerIndex); MechanicTouchEvent TouchEvent; switch (action) { case MotionEvent.ACTION_DOWN: case MotionEvent.ACTION_POINTER_DOWN: TouchEvent = TouchEventPool.NewObject(); TouchEvent.Type = MechanicTouchEvent.TOUCH_DOWN; TouchEvent.Pointer = pointerId; TouchEvent.X = TouchX[pointerId] = (int)(event.getX(pointerIndex) * ScaleX); TouchEvent.Y = TouchY[pointerId] = (int)(event.getY(pointerIndex) * ScaleY); IsTouched[pointerId] = true; TouchEventsBuffer.add(TouchEvent); break; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_POINTER_UP: case MotionEvent.ACTION_CANCEL: TouchEvent = TouchEventPool.NewObject(); TouchEvent.Type = MechanicTouchEvent.TOUCH_UP; TouchEvent.Pointer = pointerId; TouchEvent.X = TouchX[pointerId] = (int)(event.getX(pointerIndex) * ScaleX); TouchEvent.Y = TouchY[pointerId] = (int)(event.getY(pointerIndex) * ScaleY); IsTouched[pointerId] = false; TouchEventsBuffer.add(TouchEvent); break; case MotionEvent.ACTION_MOVE: int pointerCount = event.getPointerCount(); for (int i = 0; i < pointerCount; i++) { pointerIndex = i; pointerId = event.getPointerId(pointerIndex); TouchEvent = TouchEventPool.NewObject(); TouchEvent.Type = MechanicTouchEvent.TOUCH_DRAGGED; TouchEvent.Pointer = pointerId; TouchEvent.X = TouchX[pointerId] = (int)(event.getX(pointerIndex) * ScaleX); TouchEvent.Y = TouchY[pointerId] = (int)(event.getY(pointerIndex) * ScaleY); TouchEventsBuffer.add(TouchEvent); } break; } return true; } } @Override public boolean IsTouchDown(int pointer) { synchronized(this) { if(pointer < 0 || pointer >= MaxTouchers) return false; else return IsTouched[pointer]; } } @Override public int GetTouchX(int pointer) { synchronized(this) { if (pointer < 0 || pointer >= MaxTouchers) return 0; else return TouchX[pointer]; } } @Override public int GetTouchY(int pointer) { synchronized(this) { if (pointer < 0 || pointer >= 20) return 0; else return TouchY[pointer]; } } @Override public List<MechanicTouchEvent> GetTouchEvents() { synchronized (this) { for (int i = 0; i < TouchEvents.size(); i++) TouchEventPool.Free(TouchEvents.get(i)); TouchEvents.clear(); TouchEvents.addAll(TouchEventsBuffer); TouchEventsBuffer.clear(); return TouchEvents; } } }
Touchã«å ããŠãOnTouchListenerãå®è£
ããŸã
ããã€ã¹ãè€æ°ã®æã®æŒäžããµããŒãããŠãããã©ããã倿ããã«ã¯ãEnableMultiTouchãå¿
èŠã§ãã VERSION.SDKã5æªæºã®å ŽåïŒäœããã®çç±ã§ãã®å€æ°ã¯æååãšããŠè¡šç€ºãããŸãïŒããµããŒããããŸããã
MaxTouchers-æã®ââæå€§æ°ã ãããã®20ããããŸããå€ããå°ãªããã
onTouch颿°ã§ã¯ãæã®çªå·ãšã¢ã¯ã·ã§ã³ïŒæŒããæã¡äžãããç§»åïŒãååŸããŸããããããã€ãã³ãã«èšé²ããã€ãã³ãããªã¹ãã«è¿œå ããŸãã
GetTouchEventsã§ã¯ãã€ãã³ãã®ãªã¹ããè¿ããŸããã€ãã³ãã®ãªã¹ãã¯ãã®åŸã¯ãªã¢ããŸãã å¥ã®ãªã¹ããã€ãã³ãã®ãªã¹ããè¿ããŸãã
ããªãã¯ãScaleXãšScaleYã¯äœã«è²¬ä»»ãããã®ã§ããããïŒ ããã«ã€ããŠã¯ãã°ã©ãã£ãã¯ã»ã¯ã·ã§ã³ã§åŸã»ã©èª¬æããŸãã
ã¡ã«ããã¯ããŒããŒã
package com.mechanic.input; import java.util.ArrayList; import java.util.List; import android.view.KeyEvent; import android.view.View; import com.mechanic.input.Input.MechanicKeyEvent; import com.mechanic.input.Pool.PoolFactory; import com.mechanic.input.Pool; public class MechanicKeyboard implements Keyboard { boolean[] PressedKeys = new boolean[128]; Pool<MechanicKeyEvent> KeyEventPool; List<MechanicKeyEvent> KeyEventsBuffer = new ArrayList<MechanicKeyEvent>(); List<MechanicKeyEvent> KeyEvents = new ArrayList<MechanicKeyEvent>(); public MechanicKeyboard(View view) { PoolFactory<MechanicKeyEvent> pool = new PoolFactory<MechanicKeyEvent>() { @Override public MechanicKeyEvent Create() { return new MechanicKeyEvent(); } }; KeyEventPool = new Pool<MechanicKeyEvent>(pool,100); view.setOnKeyListener(this); view.setFocusableInTouchMode(true); view.requestFocus(); } public boolean IsKeyPressed(int KeyCode) { if(KeyCode < 0 || KeyCode > 127) return false; return PressedKeys[KeyCode]; } public List<MechanicKeyEvent> GetKeyEvents() { synchronized(this) { for(int i = 0; i < KeyEvents.size(); i++) KeyEventPool.Free(KeyEvents.get(i)); KeyEvents.clear(); KeyEvents.addAll(KeyEventsBuffer); KeyEventsBuffer.clear(); return KeyEvents; } } @Override public boolean onKey(View v, int keyCode, KeyEvent event) { if(event.getAction() == KeyEvent.ACTION_MULTIPLE) return false; synchronized(this) { MechanicKeyEvent key = KeyEventPool.NewObject(); key.KeyCode = keyCode; key.KeyChar = (char)event.getUnicodeChar(); if(event.getAction() == KeyEvent.ACTION_DOWN) { key.Type = MechanicKeyEvent.KEY_DOWN; if(keyCode > 0 && keyCode < 128) PressedKeys[keyCode] = true; } if(event.getAction() == KeyEvent.ACTION_UP) { key.Type = MechanicKeyEvent.KEY_UP; if(keyCode > 0 && keyCode < 128) PressedKeys[keyCode] = false; } KeyEventsBuffer.add(key); } return false; } }
128åã®ããŒã«å€æ°ã®é
åãäœæãã128åã®ããŒãæŒããããã©ããã«é¢ããæ
å ±ãä¿æããŸãã ãŸãããªããžã§ã¯ãã®ããŒã«ãš2ã€ã®ãªã¹ããäœæããŸãã ãã¹ãŠãã·ã³ãã«ã§ã
MechanicInput
package com.mechanic.input; import java.util.List; import android.content.Context; import android.view.View; public class MechanicInput implements Input { MechanicKeyboard keyboard; MechanicAccelerometer accel; MechanicTouch touch; public MechanicInput(Context context, View view, float scaleX, float scaleY) { accel = new MechanicAccelerometer(context); keyboard = new MechanicKeyboard(view); touch = new MechanicTouch(view, scaleX, scaleY); } @Override public boolean IsKeyPressed(int keyCode) { return keyboard.IsKeyPressed(keyCode); } @Override public boolean IsKeyPressed(char keyChar) { return keyboard.IsKeyPressed(keyChar); } @Override public boolean IsTouchDown(int pointer) { return touch.IsTouchDown(pointer); } @Override public int GetTouchX(int pointer) { return touch.GetTouchX(pointer); } @Override public int GetTouchY(int pointer) { return touch.GetTouchY(pointer); } @Override public float GetAccelX() { return accel.GetAccelX(); } @Override public float GetAccelY() { return accel.GetAccelY(); } @Override public float GetAccelZ() { return accel.GetAccelZ(); } @Override public List<MechanicTouchEvent> GetTouchEvents() { return touch.GetTouchEvents(); } @Override public List<MechanicKeyEvent> GetKeyEvents() { return keyboard.GetKeyEvents(); } }
ããã¡ãµãŒãããã¿ãŒã³ãå®çŸããŸãã
ããã§ããã¡ã€ã«ãæäœããæéã§ãïŒ
ãã¡ã€ã«ãæäœãã
MechanicFileIO
package com.mechanic.fileio; 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.res.AssetManager; import android.os.Environment; public class MechanicFileIO implements FileIO { AssetManager assets; String ExternalStoragePath; public MechanicFileIO(AssetManager assets) { this.assets = assets; ExternalStoragePath = Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator; } public InputStream ReadAsset(String name) throws IOException { return assets.open(name); } public InputStream ReadFile(String name) throws IOException { return new FileInputStream(ExternalStoragePath + name); } public OutputStream WriteFile(String name) throws IOException { return new FileOutputStream(ExternalStoragePath + name); } }
ã¢ã»ãããããŒãžã£ãŒããã¢ã»ãããã©ã«ããŒãããã¡ã€ã«ãåé€ããŸããæåã®é¢æ°ã¯ããã䜿çšãã2çªç®ã®2ã€ã®é¢æ°ã¯Androidã®ç¹å¥ãªããã€ã¹ãã©ã«ããŒãããã¡ã€ã«ãååŸããŸãã ã³ã³ã¹ãã©ã¯ã¿ãŒã§ãã®ãã©ã«ããŒãžã®ãã¹ãååŸããŸãã
ãµãŠã³ããäœæããŸã
é³ãæ±ã
MechanicSound
package com.mechanic.audio; import android.media.SoundPool; public class MechanicSound implements Sound { int id; SoundPool pool; public MechanicSound(SoundPool pool, int id) { this.pool = pool; this.id = id; } public void Play(float volume) { pool.play(id, volume, volume, 0, 0, 1); } public void Close() { pool.unload(id); } }
MechanicAudioã§ã¯ãSoundPoolã䜿çšããŠå°ããªå¹æé³ãä¿æããŸãã MechanicSoundã§ã¯ããµãŠã³ããšãã§ã¯ãçªå·ãšSoundPoolãªããžã§ã¯ãèªäœãæž¡ãããããããµãŠã³ããçæããŸã
MechanicMusic
package com.mechanic.audio; import java.io.IOException; import android.content.res.AssetFileDescriptor; import android.media.MediaPlayer; public class MechanicMusic implements Music { MediaPlayer Player; boolean IsPrepared = false; public MechanicMusic(AssetFileDescriptor descriptor) { Player = new MediaPlayer(); try { Player.setDataSource(descriptor.getFileDescriptor(), descriptor.getStartOffset(), descriptor.getLength()); Player.prepare(); IsPrepared = true; } catch(Exception ex) { throw new RuntimeException(" "); } } public void Close() { if(Player.isPlaying()) Player.stop(); Player.release(); } public boolean IsLooping() { return Player.isLooping(); } public boolean IsPlaying() { return Player.isPlaying(); } public boolean IsStopped() { return !IsPrepared; } public void Play() { if(Player.isPlaying()) return; try { synchronized(this) { if(!IsPrepared) Player.prepare(); Player.start(); } } catch(IllegalStateException ex) { ex.printStackTrace(); } catch(IOException ex) { ex.printStackTrace(); } } public void SetLooping(boolean loop) { Player.setLooping(loop); } public void SetVolume(float volume) { Player.setVolume(volume, volume); } public void Stop() { Player.stop(); synchronized(this) { IsPrepared = false; } } @Override public void onCompletion(MediaPlayer player) { synchronized(this) { IsPrepared = false; } } }
ãµãŠã³ããã¡ã€ã«ãã¹ããªãŒã ã«é
眮ããŠåçããŸãã
IsPreparedã¯ããµãŠã³ããäœæ¥ã®æºåãã§ããŠãããã©ããã瀺ããŸãã
ãã®ã¯ã©ã¹ãçè§£ããããšããå§ãããŸãã
MechanicAudioã«è¡ããŸãã
package com.mechanic.audio; 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; public class MechanicAudio implements Audio { AssetManager assets; SoundPool pool; public MechanicAudio(Activity activity) { activity.setVolumeControlStream(AudioManager.STREAM_MUSIC); this.assets = activity.getAssets(); pool = new SoundPool(20, AudioManager.STREAM_MUSIC, 0); } public Music NewMusic(String name) { try { AssetFileDescriptor descriptor = assets.openFd(name); return new MechanicMusic(descriptor); } catch(IOException ex) { throw new RuntimeException(" " + name); } } public Sound NewSound(String name) { try { AssetFileDescriptor descriptor = assets.openFd(name); int id = pool.load(descriptor, 0); return new MechanicSound(pool, id); } catch(IOException ex) { throw new RuntimeException(" " + name); } } }
ã³ã³ã¹ãã©ã¯ã¿ãŒã§ã¯ãããã€ã¹ããšã«é³æ¥œã調æŽããã¢ã»ãããããŒãžã£ãŒã䜿çšããŠãäžåºŠã«20以äžã®ãµãŠã³ããšãã§ã¯ãããåçã§ããªãSoundPoolãäœæã§ããŸããã»ãšãã©ã®ã²ãŒã ã§ã¯ããã§ååã ãšæããŸããMusicã®äœæã§ã¯ããã¡ã€ã«èšè¿°åãMechanicMusicã³ã³ã¹ãã©ã¯ã¿ãŒã«æž¡ããŸããSoundã§ã¯ããµãŠã³ããsoundPoolã«èªã¿èŸŒã¿ãããŒã«ãšãµãŠã³ãçªå·ãMechanicSoundã³ã³ã¹ãã©ã¯ã¿ãŒã«æž¡ããŸããäœãåé¡ãçºçããå ŽåãäŸå€ãäœæãããŸãã補å³å·¥ãäœããŸãã°ã©ãã£ãã¯ã䜿çšãã
MechanicImage package com.mechanic.graphics; import com.mechanic.graphics.Graphics.ImageFormat; import android.graphics.Bitmap; public class MechanicImage implements Image { Bitmap bitmap; ImageFormat format; public MechanicImage(Bitmap bitmap, ImageFormat format) { this.bitmap = bitmap; this.format = format; } @Override public int GetWidth() { return bitmap.getWidth(); } @Override public int GetHeight() { return bitmap.getHeight(); } @Override public ImageFormat GetFormat() { return format; } @Override public void Dispose() { bitmap.recycle(); } }
ãã®ã¯ã©ã¹ã¯ã€ã¡ãŒãžãã«ããŒã§ãã圌ã¯ç¹å¥ãªããšã¯äœãããã䟿å®äžå°å
¥ãããŸãããMechanicGraphics package com.mechanic.graphics; import java.io.IOException; import java.io.InputStream; import android.content.res.AssetManager; import android.graphics.Bitmap; import android.graphics.Bitmap.Config; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Paint.Style; import android.graphics.Rect; public class MechanicGraphics implements Graphics { AssetManager assets; Bitmap buffer; Canvas canvas; Paint paint; Rect srcRect = new Rect(), dstRect = new Rect(); public MechanicGraphics(AssetManager assets, Bitmap buffer) { this.assets = assets; this.buffer = buffer; this.canvas = new Canvas(buffer); this.paint = new Paint(); } @Override public Image NewImage(String fileName) { ImageFormat format; InputStream file = null; Bitmap bitmap = null; try { file = assets.open(fileName); bitmap = BitmapFactory.decodeStream(file); if (bitmap == null) throw new RuntimeException(" '" + fileName + "'"); } catch (IOException e) { throw new RuntimeException(" '" + fileName + "'"); } finally { try { if(file != null) file.close(); } catch(IOException e) { } } if (bitmap.getConfig() == Config.RGB_565) format = ImageFormat.RGB_565; else if (bitmap.getConfig() == Config.ARGB_4444) format = ImageFormat.ARGB_4444; else format = ImageFormat.ARGB_8888; return new MechanicImage(bitmap, format); } @Override public void Clear(int color) { canvas.drawRGB((color & 0xff0000) >> 16, (color & 0xff00) >> 8, (color & 0xff)); } @Override public void DrawPixel(int x, int y, int color) { paint.setColor(color); canvas.drawPoint(x, y, paint); } @Override public void DrawLine(int x, int y, int x2, int y2, int color) { paint.setColor(color); canvas.drawLine(x, y, x2, y2, paint); } @Override public void DrawRect(int x, int y, int width, int height, int color) { paint.setColor(color); paint.setStyle(Style.FILL); canvas.drawRect(x, y, x + width - 1, y + width - 1, paint); } @Override public void DrawImage(Image image, int x, int y, int srcX, int srcY, int srcWidth, int srcHeight) { srcRect.left = srcX; srcRect.top = srcY; srcRect.right = srcX + srcWidth - 1; srcRect.bottom = srcY + srcHeight - 1; dstRect.left = x; dstRect.top = y; dstRect.right = x + srcWidth - 1; dstRect.bottom = y + srcHeight - 1; canvas.drawBitmap(((MechanicImage)image).bitmap, srcRect, dstRect, null); } @Override public void DrawImage(Image image, int x, int y) { canvas.drawBitmap(((MechanicImage)image).bitmap, x, y, null); } @Override public int GetWidth() { return buffer.getWidth(); } @Override public int GetHeight() { return buffer.getHeight(); } }
泚æããŠãã ããïŒ
ããã¯ã¬ããŒãžã³ã¬ã¯ã¿ãŒã«å¯Ÿããç¯çœªã§ãããããæç»ãããã³ã«Paintããã³Rectãªããžã§ã¯ããäœæããããã§ã¯ãããŸãããã³ã³ã¹ãã©ã¯ã¿ãŒã§ã¯ãBitmapã䜿çšããŸããããã¯ããã¹ãŠãæç»ãããããã¡ãŒã§ããããã£ã³ãã¹ã«ãã£ãŠäœ¿çšãããŸããç»åãèªã¿èŸŒããšãã¢ã»ããããç»åãèªã¿åããããããããã§ãã³ãŒãããŸããããŠã³ããŒããããã¡ã€ã«ãç»åã§ãªãå ŽåããŸãã¯ãã¡ã€ã«ãååšããªãå Žåã¯ãäŸå€ãã¹ããŒããããã¡ã€ã«ã¯éããããŸããæåŸã«ãã€ã¡ãŒãžåœ¢åŒãååŸããŠæ°ããMechanicImageãè¿ããBitmapãšImageFormatãã³ã³ã¹ãã©ã¯ã¿ãŒã«æž¡ããŸãããŸããç»åã®äžéšãæç»ããæåã®DrawImageã¡ãœãããæ³šç®ã«å€ããŸããããã¯ãã¢ãã©ã¹ãšåŒã°ããç»åã®ã°ã«ãŒããã²ãŒã å
ã®åã
ã®ç»åã®ä»£ããã«äœ¿çšãããå Žåã«é©çšãããŸãããã®ãããªã¢ãã©ã¹ã®äŸã¯
次ã®ãšããã§ãïŒinteresnoe.info WebãªãœãŒã¹ããã®ç»åïŒäœçœ®1.1ã§32.32ãã48.48ã®ç»åã®äžéšãæç»ããå¿
èŠããããšããŸãããããããããã DrawImage(image, 1, 1, 32, 32, 16, 16);
æ®ãã®æ¹æ³ã¯ç°¡åã«çè§£ã§ããèå³ã®å¯Ÿè±¡ã§ã¯ãããŸãããã²ãŒã ãšç»é¢ã®ã€ã³ã¿ãŒãã§ã€ã¹ã®æéã§ãïŒç¶è¡ããåã«ãã°ã©ãã£ãã¯ãå¥ã®ã¹ããªãŒã ã«æç»ãããŠãŒã¶ãŒã¹ããªãŒã ãèªã¿èŸŒãŸãªãããã«ããå¿
èŠããããŸããå¥ã®ã¹ã¬ããã§ã°ã©ãã£ãã¯ã¹ãæç»ã§ããSurfaceViewã¯ã©ã¹ãã芧ãã ãããã©ã³ããŒã¯ã©ã¹ãäœæãã package com.mechanic.game; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Rect; import android.view.SurfaceHolder; import android.view.SurfaceView; public class Runner extends SurfaceView implements Runnable { MechanicGame game; Canvas canvas; Bitmap buffer; Thread thread = null; SurfaceHolder holder; volatile boolean running = false; public Runner(Object context, MechanicGame game, Bitmap buffer) { super(game); this.game = game; this.buffer = buffer; this.holder = getHolder(); } public void Resume() { running = true; thread = new Thread(this); thread.start(); } public void run() { Rect dstRect = new Rect(); long startTime = System.nanoTime(); while(running) { if(!holder.getSurface().isValid()) continue; float deltaTime = (System.nanoTime()-startTime) / 1000000000.0f; startTime = System.nanoTime(); game.GetCurrentScreen().Update(deltaTime); game.GetCurrentScreen().Present(deltaTime); canvas = holder.lockCanvas(); canvas.getClipBounds(dstRect); canvas.drawBitmap(buffer, null, dstRect, null); holder.unlockCanvasAndPost(canvas); } } public void Pause() { running = false; while(true) { try { thread.join(); break; } catch (InterruptedException e) { } } } }
MechanicGameã¯ã©ã¹ã¯è¿æ¥å
¬éäºå®ã§ããå¿é
ããªãã§ãã ããããŠãŒã¶ãŒã€ã³ã¿ãŒãã§ã€ã¹ã«ãªãã°ã©ãã£ãã¯ãæç»ããã«ã¯ãSurfaceHolderãªããžã§ã¯ããå¿
èŠã§ããäž»ãªæ©èœã¯ãlockCanvasãšunlockCanvasAndPostã§ããæåã®é¢æ°ã¯Surfaceããããã¯ããäœããæç»ããCanvasïŒãã®å Žåããã£ã³ãã¹ãšããŠæ©èœããBitmapãããã¡ãŒïŒãè¿ããŸããResume颿°ã§ã¯ããã®ã¯ã©ã¹ã§æ°ããã¹ã¬ãããéå§ããŸããrun颿°ã§ã¯ãã¢ããªã±ãŒã·ã§ã³ã®å®è¡äžã«ãæåŸã®ãµã€ã¯ã«ããã®çµéæéãååŸããïŒSystem.nanoTimeã¯ããç§ãè¿ããŸãïŒãã¢ããªã±ãŒã·ã§ã³ã®çŸåšã®ç»é¢ã®æŽæ°ããã³çŸåšã®é¢æ°ãåŒã³åºããããã®åŸãããã¡ãŒãæç»ãããŸãããããMechanicGameã¯ã©ã¹ã§ã package com.mechanic.game; import com.mechanic.audio.Audio; import com.mechanic.audio.MechanicAudio; import com.mechanic.fileio.FileIO; import com.mechanic.fileio.MechanicFileIO; import com.mechanic.graphics.Graphics; import com.mechanic.graphics.MechanicGraphics; import com.mechanic.input.Input; import com.mechanic.input.MechanicInput; import android.app.Activity; import android.content.Context; import android.content.res.Configuration; import android.graphics.Bitmap; import android.graphics.Bitmap.Config; import android.os.Bundle; import android.os.PowerManager; import android.os.PowerManager.WakeLock; import android.view.Window; import android.view.WindowManager; public abstract class MechanicGame extends Activity implements Game { Runner runner; Graphics graphics; Audio audio; Input input; FileIO fileIO; Screen screen; WakeLock wakeLock; static final int SCREEN_WIDTH = 80; static final int SCREEN_HEIGHT = 128; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE); getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); boolean IsLandscape = (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE); int frameBufferWidth = IsLandscape ? SCREEN_HEIGHT : SCREEN_WIDTH; int frameBufferHeight = IsLandscape ? SCREEN_WIDTH : SCREEN_HEIGHT; Bitmap frameBuffer = Bitmap.createBitmap(frameBufferWidth, frameBufferHeight, Config.RGB_565); float scaleX = (float) frameBufferWidth / getWindowManager().getDefaultDisplay().getWidth(); float scaleY = (float) frameBufferHeight / getWindowManager().getDefaultDisplay().getHeight(); runner = new Runner(null, this, frameBuffer); graphics = new MechanicGraphics(getAssets(), frameBuffer); fileIO = new MechanicFileIO(getAssets()); audio = new MechanicAudio(this); input = new MechanicInput(this, runner, scaleX, scaleY); screen = GetStartScreen(); setContentView(runner); PowerManager powerManager = (PowerManager) getSystemService(Context.POWER_SERVICE); wakeLock = powerManager.newWakeLock(PowerManager.FULL_WAKE_LOCK, "Game"); } @Override public Input GetInput() { return input; } @Override public FileIO GetFileIO() { return fileIO; } @Override public Graphics GetGraphics() { return graphics; } @Override public Audio GetAudio() { return audio; } @Override public void SetScreen(Screen screen) { if (screen == null) throw new IllegalArgumentException("Screen null"); this.screen.Pause(); this.screen.Dispose(); screen.Resume(); screen.Update(0); this.screen = screen; } @Override public Screen GetCurrentScreen() { return screen; } @Override public Screen GetStartScreen() { return null; } @Override public void onResume() { super.onResume(); wakeLock.acquire(); screen.Resume(); runner.Resume(); } @Override public void onPause() { super.onPause(); wakeLock.release(); runner.Pause(); screen.Pause(); if(isFinishing()) screen.Dispose(); } }
ãã®ã¯ã©ã¹ã«ã¯ãRunnerãªããžã§ã¯ãããã¹ãŠã®ã€ã³ã¿ãŒãã§ã€ã¹ãšã¯ã©ã¹ãããã³WakeLockãªããžã§ã¯ãïŒã²ãŒã ã®å®è¡äžã«æºåž¯é»è©±ãã¹ãªãŒãç¶æ
ã«ãªããªãããã«ããããã«å¿
èŠïŒãããã2ã€ã®å®æ°ããããŸããããã€ã¹ã«ã¯å€ãã®è§£å床ããããåããã€ã¹ã®ç»åãµã€ãºã®èª¿æŽãå Žæã®èšç®ãªã©ã¯ã»ãšãã©äžå¯èœã§ç¡æå³ã§ãããªã©
ïŒäžèšã®2ã€ã®å®æ°ããïŒ80x128ãã¯ã»ã«ã枬å®ãããŠã£ã³ããŠããããšæ³åããŠãã ããããã®ãŠã£ã³ããŠã«å°ããªçµµãæããŸããããããçªç¶ãããã€ã¹ã®ç»é¢ãµã€ãºããã®ãŠã£ã³ããŠã®ãµã€ãºã«é©åããŸãããã©ããã
ãã¹ãŠãéåžžã«ç°¡åã§ãããŠã£ã³ããŠã®å¹
ãšé·ããšããã€ã¹ã®å¹
ãšé·ãã®æ¯ãåãããã®æ¯ãäžãããããšãã¹ãŠã®çµµãæããŸãããã®çµæãã¢ããªã±ãŒã·ã§ã³èªäœãããã€ã¹ã®ç»é¢äžã§ç»åãæ¡å€§ããŸãããã®ã¯ã©ã¹ã«ã¯Activityãå«ãŸããonCreateãonResumeãããã³onPauseã®ã¡ãœããããããŸããonCreateã§ã¯ãã¢ããªã±ãŒã·ã§ã³ã¯æåã«ãã«ã¹ã¯ãªãŒã³ã¢ãŒãã«ãªããŸãïŒãã®ãããäžéšã«å
é»ãšæéã衚瀺ãããªããªããŸãïŒã次ã«ãé»è©±ã®åãïŒæšªåããŸãã¯çžŠåãïŒã倿ããŸãïŒèšäºã®åé ã§.xmlãã¡ã€ã«ã«æ¢ã«èšè¿°ãããŠããŸãïŒã次ã«ããã®ãŠã£ã³ããŠã®ãµã€ãºã80x128ãã¯ã»ã«ã®åŸ
æã®ãããã¡ãŒãäœæãããŸãããã®ãŠã£ã³ããŠãšããã€ã¹ã®ãµã€ãºã®æ¯çã¯ãMechanicInputã³ã³ã¹ãã©ã¯ã¿ãŒã«æž¡ãããããããªã¬ãŒã·ã§ã³ãMechanicTouchã«æž¡ããŸãããããŠãã-ãã³ãŽïŒçµæã®ç»é¢äžã®ã¿ãããã€ã³ãã¯ãã®æ¯çã§ä¹ç®ããããããã¯ãªãã¯ã®åº§æšã¯ããã€ã¹ã®ãµã€ãºã«äŸåããŸãããæ¬¡ã«ãã€ã³ã¿ãŒãã§ã€ã¹ãäœæããRunnerãšWakeLockãç»é²ããŸããSetScreenã¡ãœããã§ã¯ãçŸåšã®Screenãè§£æŸããå¥ã®ScreenãäœæããŸããèå³ã®ããä»ã®æ¹æ³ã¯æäŸããŸãããããã ãã§ããïŒã¯ãã玳士ããã¬ãŒã ã¯ãŒã¯ã¯æºåãã§ããŠããŸãïŒçµãã£ããããããŠãããšãã°MyGameãªã©ã®ã¡ã€ã³ã¯ã©ã¹ã«ãã¬ãŒã ã¯ãŒã¯ãæ¥ç¶ããæ¹æ³ãæããŠãã ããããã¡ã€ã³ãã¯ã©ã¹ã¯æ¬¡ã®ããã«ãªããŸã public class MyGame extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_my_game); } @Override public boolean onCreateOptionsMenu(Menu menu) {
ãã®ã¯ã©ã¹ã«å€æŽããŸã package com.mechanic; import com.mechanic.game.MechanicGame; import com.mechanic.game.Screen; public class MyGame extends MechanicGame { @Override public Screen GetStartScreen() { return new GameScreen(this); } }
MechanicGameèªäœãActivityããç¶æ¿ãããããJavaã¯ãã®ã¯ã©ã¹ãActivityããã®ç¶æ¿è
ãšããŠèªèããŸããonCreateã¯ãã§ã«ç»é²ãããŠããŸãããã®ã¡ãœããã¯MechanicGameã§nullãè¿ãããšã©ãŒãã¹ããŒãããããGetStartScreenïŒïŒããªãŒããŒã©ã€ãããã ãã§ããGameScreenã¯ã©ã¹ãå®è£
ããããšãå¿ããªãã§ãã ãã:) package com.mechanic; import com.mechanic.game.Game; import com.mechanic.game.Screen; import com.mechanic.graphics.Graphics; import com.mechanic.graphics.Image; public class GameScreen extends Screen { Graphics g = game.GetGraphics(); Image wikitan; float x = 0.0f; public GameScreen(Game game) { super(game); wikitan = g.NewImage("wikipetan.png"); } @Override public void Update(float deltaTime) { if(game.GetInput().IsTouchDown(0)) x += 1.0f * deltaTime; } @Override public void Present(float deltaTime) { g.Clear(0); g.DrawImage(wikitan, (int)x, 0); } @Override public void Pause() { } @Override public void Resume() { } @Override public void Dispose() { wikitan.Dispose(); } }
ããã¯ãWikipe-tanã€ã¡ãŒãžãããŠã³ããŒãããç»é¢ãã¯ãªãã¯ããŠç§»åããScreenå®è£
ã®ç°¡åãªäŸã§ãã
ïŒru.wikipedia.org WebãªãœãŒã¹ããã®ç»åïŒçµæ
倿°xã¯ã0ãã1ã®æ°å€ã远å ããŠãäœãåŸãããªããããæµ®åå°æ°ç¹æ°ãšããŠè¡šãããŸãããã£ã³ãã¹ã®ãµã€ãºã¯80x128ãã¯ã»ã«ãªã®ã§ãWikipe-tanã¯å¢å ããŠæç»ãããŸã質åãšåçïŒ
-ç»åãæ£ããæç»ãããŸãã-90床å転ããŸããïŒ-ããã¯ãxmlãã¡ã€ã«ã§ã³ãã³ããæšªã¢ãŒãã§ã®ã¿åäœããããã«æå®ããããã§ããã¢ãŒããåãæ¿ããã«ã¯ãããŒããŒãã®å³åŽã«ããããŒ7ãæŒããŸã-æ£çŽã«x + = 1.0f * deltaTimeã倿ŽããŸãããç»åãåããªããããã£ããåããŸãã ã©ããã-ãšãã¥ã¬ãŒã¿ãŒã¯éåžžã«é
ããã®ã§ããããã€ã¹äžã®ã¢ããªã±ãŒã·ã§ã³ã®ç¶æ
ã確èªããŸããæ¥œããã§ãã ããïŒåºå
žïŒrghost.ru/49052713github.com/Izaron/MechanicFrameworkæç®ïŒdeveloper.alexanderklimov.ru/androidhabrahabr.ru/post/109944ããªãªã»ãã·ã¥ããŒã®ãAndroidåãã²ãŒã ã®ããã°ã©ãã³ã°ã