Flex、AIR、Java、Androidなど

1月19日 2011

【Android】AndEngineとOpenFeintを組み合わせて使うサンプル

Posted by: tachibana In: Android| プログラミング

AndEngineを使ってゲームを作って(iPhoneのを移植)しようとしているのですが、エミュレーターだとFPSが出なくてどうにもならないので順番を変えて先にOpenFeintを組み込んでみます。

一番面倒な世界ハイスコアランキングやSNSへの投稿等が簡単にできるので、ゲームが作り易くなると思います。

◆ プロジェクト作成

まず、EclipseでAndroidプロジェクトを作成し、andengine.jarをビルドパスに追加します。ゲーム画面は恐らくBaseGameActivityでしょうから、起動時に呼ばれるActivityをBaseGameActivityに変更し、IGameInterfaceに定義されているメソッドを追加します。(BaseGameActivity extends BaseActivity implements IGameInterfaceなので。詳しくはBaseGameActivityにカーソル合わせてF3)この時点でのソースは以下。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
package com.hoge.AndEngineAndOpenFeintSample;

import org.anddev.andengine.engine.Engine;
import org.anddev.andengine.entity.scene.Scene;
import org.anddev.andengine.ui.activity.BaseGameActivity;

import android.os.Bundle;

public class GameActivity extends BaseGameActivity {

    @Override
    public Engine onLoadEngine() {
        return null;
    }
   
    @Override
    public void onLoadResources() {
   
    }
   
    @Override
    public Scene onLoadScene() {
        return null;
    }
   
    @Override
    public void onLoadComplete() {

    }
}

◆ AndEngineのコード

ここに、ゲームに必要なTexture等を貼っていき、画面をタップした回数を数えるところまでコードを追加します。AndEngineに関してはざっとソース読んだ感じで理解したことをコメントで書いときますが、まだソースとかパフォーマンスTipとか読んでないので適当です。以下。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
package com.hoge.AndEngineAndOpenFeintSample;

import org.anddev.andengine.engine.Engine;
import org.anddev.andengine.engine.camera.Camera;
import org.anddev.andengine.engine.options.EngineOptions;
import org.anddev.andengine.engine.options.EngineOptions.ScreenOrientation;
import org.anddev.andengine.engine.options.resolutionpolicy.RatioResolutionPolicy;
import org.anddev.andengine.entity.scene.Scene;
import org.anddev.andengine.entity.sprite.Sprite;
import org.anddev.andengine.entity.text.ChangeableText;
import org.anddev.andengine.entity.util.FPSLogger;
import org.anddev.andengine.input.touch.TouchEvent;
import org.anddev.andengine.opengl.font.Font;
import org.anddev.andengine.opengl.texture.Texture;
import org.anddev.andengine.opengl.texture.TextureOptions;
import org.anddev.andengine.opengl.texture.region.TextureRegion;
import org.anddev.andengine.opengl.texture.region.TextureRegionFactory;
import org.anddev.andengine.ui.activity.BaseGameActivity;

import android.graphics.Color;
import android.graphics.Typeface;

public class GameActivity extends BaseGameActivity {
   
    // 描画するエリアの指定。縦横比を保ったまま表示できる最大のサイズにスケールしてくれる。
    private static final int CAMERA_WIDTH = 480;//800;
    private static final int CAMERA_HEIGHT = 320;//480;
   
    // 描画エリア。
    Camera mCamera;
    // フォントの展開場所みたいなもん?
    Texture mFontTexture;
    // フォントの実体?
    Font mFont;
   
    // 画像の展開場所みたいなもん?
    Texture mTexture;
    // 画像の実体?
    TextureRegion mTouchAreaTextureRegion;
    TextureRegion mSendAreaTextureRegion;
    TextureRegion mDashboardAreaTextureRegion;
   
    int mTapCount = 0;
    ChangeableText mTapCountText;
   
    // Activity呼び出し時、最初に呼ばれるメソッド。以下onLoadResources(),
    // onLoadScene(), onLoadComplete()の順。
    @Override
    public Engine onLoadEngine() {
        // mCameraをインスタンス化、EngineにmCameraをセットして返す。
        this.mCamera = new Camera(0, 0, CAMERA_WIDTH, CAMERA_HEIGHT);
        return new Engine(new EngineOptions(true, ScreenOrientation.LANDSCAPE, new RatioResolutionPolicy(CAMERA_WIDTH, CAMERA_HEIGHT), this.mCamera));
    }
   
    @Override
    public void onLoadResources() {
        // フォント用のTextureを用意。256*256で収まる。
        this.mFontTexture = new Texture(256, 256, TextureOptions.BILINEAR_PREMULTIPLYALPHA);
        // フォント画像をイニシャライズ、フォントTextureに格納。
        this.mFont = new Font(this.mFontTexture, Typeface.create(Typeface.DEFAULT, Typeface.BOLD), 32, true, Color.WHITE);

        // EngineのTextureManagerにフォントTextureをセット
        this.mEngine.getTextureManager().loadTexture(this.mFontTexture);
        // FontManagerにフォントをセット。
        this.mEngine.getFontManager().loadFont(this.mFont);

        // 画像格納用Textureを初期化。画像のサイズは336*54
        this.mTexture = new Texture(512, 512, TextureOptions.BILINEAR_PREMULTIPLYALPHA);
        // 画像を格納。は同じTextureに格納される為、画像が重ならないよう座標を調節している。Paddingを取った方がいいとか。
        // 画像はassets/gfx以下。
        mTouchAreaTextureRegion = TextureRegionFactory.createFromAsset(this.mTexture, this, "gfx/taparea_bg.png", 0, 0);
        mSendAreaTextureRegion = TextureRegionFactory.createFromAsset(this.mTexture, this, "gfx/send_bg.png", 0, 55);
        mDashboardAreaTextureRegion = TextureRegionFactory.createFromAsset(this.mTexture, this, "gfx/dashboard_bg.png", 0, 110);
        // TextureManagerに画像Textureをセット
        this.mEngine.getTextureManager().loadTexture(this.mTexture);
    }

    @Override
    public Scene onLoadScene() {
        // FPS Loggingを有効化。adb logcatで見れるように。
        this.mEngine.registerUpdateHandler(new FPSLogger());
        // Sceneを初期化。引数はScene上のレイヤーの数。
        final Scene scene = new Scene(1);
       
        // テキストエリアを表示。
        mTapCountText = new ChangeableText(CAMERA_WIDTH / 2, CAMERA_HEIGHT / 2 - 110, this.mFont, Integer.toString(mTapCount), 10);
        //mTapCountText.setWidth(200);
        mTapCountText.setPosition(CAMERA_WIDTH / 2 - mTapCountText.getWidth() / 2, CAMERA_HEIGHT / 2 - 110);
        scene.getBottomLayer().addEntity(mTapCountText);
       
        // 座標とTextureRegionを指定してSpriteをインスタンス化。
        // 座標はデフォルトでスクリーン左上が(0,0)、スプライトの座標の基準点(anchorPoint)も左上。
        // 同時にタップされた時のListenerを登録、タッチエリアをSceneに登録。
        Sprite btnSprite = new Sprite(CAMERA_WIDTH / 2 - mTouchAreaTextureRegion.getWidth() / 2, CAMERA_HEIGHT / 2 -  20, mTouchAreaTextureRegion){
            @Override
            public boolean onAreaTouched(final TouchEvent pSceneTouchEvent, final float pTouchAreaLocalX, final float pTouchAreaLocalY) {
                if(pSceneTouchEvent.getAction() == TouchEvent.ACTION_DOWN) {
                    mTapCount++;
                    mTapCountText.setText(Integer.toString(mTapCount));
                    mTapCountText.setPosition(CAMERA_WIDTH / 2 - mTapCountText.getWidth() / 2, CAMERA_HEIGHT / 2 - 110);
                }
                return true;
            };
        };
        scene.getBottomLayer().addEntity(btnSprite);
        scene.getBottomLayer().registerTouchArea(btnSprite);
       
        Sprite sendSprite = new Sprite(CAMERA_WIDTH / 2 - mSendAreaTextureRegion.getWidth() / 2, CAMERA_HEIGHT / 2 + 40, mSendAreaTextureRegion){
            @Override
            public boolean onAreaTouched(final TouchEvent pSceneTouchEvent, final float pTouchAreaLocalX, final float pTouchAreaLocalY) {
                if(pSceneTouchEvent.getAction() == TouchEvent.ACTION_DOWN) {
                    mTapCount = 0;
                    mTapCountText.setText(Integer.toString(mTapCount));
                    mTapCountText.setPosition(CAMERA_WIDTH / 2 - mTapCountText.getWidth() / 2, CAMERA_HEIGHT / 2 - 110);
                }
                return true;
            };
        };
        scene.getBottomLayer().addEntity(sendSprite);
        scene.getBottomLayer().registerTouchArea(sendSprite);
       
        Sprite dashboardSprite = new Sprite(CAMERA_WIDTH / 2 - mDashboardAreaTextureRegion.getWidth() / 2, CAMERA_HEIGHT / 2 + 100, mDashboardAreaTextureRegion){
            @Override
            public boolean onAreaTouched(final TouchEvent pSceneTouchEvent, final float pTouchAreaLocalX, final float pTouchAreaLocalY) {
                if(pSceneTouchEvent.getAction() == TouchEvent.ACTION_DOWN) {
                   
                }
                return true;
            };
        };
        scene.getBottomLayer().addEntity(dashboardSprite);
        scene.getBottomLayer().registerTouchArea(dashboardSprite);
       
        return scene;
    }
   
    @Override
    public void onLoadComplete() {
       
    }
}

◆ AndroidManifest.xmlの編集

1
<uses-permission android:name="android.permission.WAKE_LOCK"/>

を追加してください。

◆ OpenFeintを組み込む

“Send score to OpenFeint”をタップするとハイスコアサーバーへ送信、OpenDashboardをタップするとダッシュボードを表示する部分を書きます。

(1) OpenFeintへの登録(無料)
https://api.openfeint.com/ddから開発者登録、アプリの登録、leaderboardの最低一つ作ります。上のDownloadsからSDKを落とします。

(2) OpenFeintが使うクラス群のライブラリ化
ここはSDK同梱のREADMEを読んでやってもできません。自分の環境では以下の手順で通しました。

  • Eclipseで空のワークスペースを指定して開く。
  • SDKの中のOpenFeintAPIフォルダをインポート。自動的にビルド走るんで多分エラー出ます。
  • genフォルダが無ければ作ります。その段階でR.javaが生成されエラーは消えます。
  • genフォルダがあるのにビルドが通らない方はメニューバー > 自動的にビルドのチェックを外してからgenを作って再度チェック入れてみたり、クリーンしたりしてビルドが通る様にしてください。
  • プロジェクトのプロパティー > Androidの中のIs Libraryにチェックを入れます、これで同ワークスペースの他のプロジェクトからライブラリとしてインポートできるようになります。

(3) AndroidManifest.xmlの編集
Eclipseのワークスペースをもとの場所に戻し、(2)で作ったプロジェクトをインポートします。ゲームプロジェクトのプロパティー > Androidと辿り、ライブラリー >追加でOpenFeintAPIを追加します。これでゲームからOpenFeintのAPIが叩けるようになります。README.html を開き、Integrate OpenFeint into your gameをクリックしてその通りにして下さい。

(4) ゲームの初回起動時にOpenFeintの有効化を促す画面を出す
これはどんなゲームでも必ずやらないといけません。OpenFeintが利用するアプリIDやsecretKey等を定数で定義し、onCreate()内で呼びます。51行目〜63行目辺り。

(5) ボタンタップでOpenFeintのハイスコアサーバーへスコアを登録する
130行目〜140行目辺り。

(5) OpenFeintのダッシュボードを開く
160行目辺り。

出来上がったソースが以下。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
package com.hoge.AndEngineAndOpenFeintSample;

import org.anddev.andengine.engine.Engine;
import org.anddev.andengine.engine.camera.Camera;
import org.anddev.andengine.engine.options.EngineOptions;
import org.anddev.andengine.engine.options.EngineOptions.ScreenOrientation;
import org.anddev.andengine.engine.options.resolutionpolicy.RatioResolutionPolicy;
import org.anddev.andengine.entity.scene.Scene;
import org.anddev.andengine.entity.sprite.Sprite;
import org.anddev.andengine.entity.text.ChangeableText;
import org.anddev.andengine.entity.util.FPSLogger;
import org.anddev.andengine.input.touch.TouchEvent;
import org.anddev.andengine.opengl.font.Font;
import org.anddev.andengine.opengl.texture.Texture;
import org.anddev.andengine.opengl.texture.TextureOptions;
import org.anddev.andengine.opengl.texture.region.TextureRegion;
import org.anddev.andengine.opengl.texture.region.TextureRegionFactory;
import org.anddev.andengine.ui.activity.BaseGameActivity;

import android.app.Activity;
import android.graphics.Color;
import android.graphics.Typeface;
import android.widget.Toast;

import com.openfeint.api.OpenFeint;
import com.openfeint.api.OpenFeintDelegate;
import com.openfeint.api.OpenFeintSettings;
import com.openfeint.api.resource.Leaderboard;
import com.openfeint.api.resource.Score;
import com.openfeint.api.ui.Dashboard;

public class GameActivity extends BaseGameActivity {

    // 描画するエリアの指定。縦横比を保ったまま表示できる最大のサイズにスケールしてくれる。
    private static final int CAMERA_WIDTH = 480;//800;
    private static final int CAMERA_HEIGHT = 320;//480;

    // 描画エリア。
    Camera mCamera;
    // フォントの展開場所みたいなもん?
    Texture mFontTexture;
    // フォントの実体?
    Font mFont;

    // 画像の展開場所みたいなもん?
    Texture mTexture;
    // 画像の実体?
    TextureRegion mTouchAreaTextureRegion;
    TextureRegion mSendAreaTextureRegion;
    TextureRegion mDashboardAreaTextureRegion;

    int mTapCount = 0;
    ChangeableText mTapCountText;

    // OpenFeintのinitialize()に使う定数を定義。アプリごとにOpenFeint管理画面で割り振られる
    static final String gameName = "AndEngine And OpenFeint Sample";
    static final String gameID = "230153";
    static final String gameKey = "x9mRmSJFDfwz4UzGvD2eaQ";
    static final String gameSecret = "wJsCZnrktz9VdRg8KpYI8mw3x8oq4ymlU5f2n3j56I";

    // Activity呼び出し時、最初に呼ばれるメソッド。以下onLoadResources(),
    // onLoadScene(), onLoadComplete()の順。
    @Override
    public Engine onLoadEngine() {
        // OpenFeintのinitialize()。
        // アプリの初回起動時、必ずOpenFeintの有効化を促す画面が表示される。
        OpenFeintSettings settings = new OpenFeintSettings(gameName, gameKey, gameSecret, gameID);
        OpenFeint.initialize(this, settings, new OpenFeintDelegate() {});
        // mCameraをインスタンス化、EngineにmCameraをセットして返す。
        this.mCamera = new Camera(0, 0, CAMERA_WIDTH, CAMERA_HEIGHT);
        return new Engine(new EngineOptions(true, ScreenOrientation.LANDSCAPE, new RatioResolutionPolicy(CAMERA_WIDTH, CAMERA_HEIGHT), this.mCamera));
    }

    @Override
    public void onLoadResources() {
        // フォント用のTextureを用意。256*256で収まる。
        this.mFontTexture = new Texture(256, 256, TextureOptions.BILINEAR_PREMULTIPLYALPHA);
        // フォント画像をイニシャライズ、フォントTextureに格納。
        this.mFont = new Font(this.mFontTexture, Typeface.create(Typeface.DEFAULT, Typeface.BOLD), 32, true, Color.WHITE);

        // EngineのTextureManagerにフォントTextureをセット
        this.mEngine.getTextureManager().loadTexture(this.mFontTexture);
        // FontManagerにフォントをセット。
        this.mEngine.getFontManager().loadFont(this.mFont);

        // 画像格納用Textureを初期化。画像のサイズは336*54
        this.mTexture = new Texture(512, 512, TextureOptions.BILINEAR_PREMULTIPLYALPHA);
        // 画像を格納。は同じTextureに格納される為、画像が重ならないよう座標を調節している。Paddingを取った方がいいとか。
        // 画像はassets/gfx以下。
        mTouchAreaTextureRegion = TextureRegionFactory.createFromAsset(this.mTexture, this, "gfx/taparea_bg.png", 0, 0);
        mSendAreaTextureRegion = TextureRegionFactory.createFromAsset(this.mTexture, this, "gfx/send_bg.png", 0, 55);
        mDashboardAreaTextureRegion = TextureRegionFactory.createFromAsset(this.mTexture, this, "gfx/dashboard_bg.png", 0, 110);
        // TextureManagerに画像Textureをセット
        this.mEngine.getTextureManager().loadTexture(this.mTexture);
    }

    @Override
    public Scene onLoadScene() {
        // FPS Loggingを有効化。adb logcatで見れるように。
        this.mEngine.registerUpdateHandler(new FPSLogger());
        // Sceneを初期化。引数はScene上のレイヤーの数。
        final Scene scene = new Scene(1);

        // テキストエリアを表示。
        mTapCountText = new ChangeableText(CAMERA_WIDTH / 2, CAMERA_HEIGHT / 2 - 110, this.mFont, Integer.toString(mTapCount), 10);
        //mTapCountText.setWidth(200);
        mTapCountText.setPosition(CAMERA_WIDTH / 2 - mTapCountText.getWidth() / 2, CAMERA_HEIGHT / 2 - 110);
        scene.getBottomLayer().addEntity(mTapCountText);

        // 座標とTextureRegionを指定してSpriteをインスタンス化。
        // 座標はデフォルトでスクリーン左上が(0,0)、スプライトの座標の基準点(anchorPoint)も左上。
        // 同時にタップされた時のListenerを登録、タッチエリアをSceneに登録。
        Sprite btnSprite = new Sprite(CAMERA_WIDTH / 2 - mTouchAreaTextureRegion.getWidth() / 2, CAMERA_HEIGHT / 2 -  20, mTouchAreaTextureRegion){
            @Override
            public boolean onAreaTouched(final TouchEvent pSceneTouchEvent, final float pTouchAreaLocalX, final float pTouchAreaLocalY) {
                if(pSceneTouchEvent.getAction() == TouchEvent.ACTION_DOWN) {
                    mTapCount++;
                    mTapCountText.setText(Integer.toString(mTapCount));
                    mTapCountText.setPosition(CAMERA_WIDTH / 2 - mTapCountText.getWidth() / 2, CAMERA_HEIGHT / 2 - 110);
                }
                return true;
            };
        };
        scene.getBottomLayer().addEntity(btnSprite);
        scene.getBottomLayer().registerTouchArea(btnSprite);

        Sprite sendSprite = new Sprite(CAMERA_WIDTH / 2 - mSendAreaTextureRegion.getWidth() / 2, CAMERA_HEIGHT / 2 + 40, mSendAreaTextureRegion){
            @Override
            public boolean onAreaTouched(final TouchEvent pSceneTouchEvent, final float pTouchAreaLocalX, final float pTouchAreaLocalY) {
                if(pSceneTouchEvent.getAction() == TouchEvent.ACTION_DOWN) {
                    Score s = new Score(mTapCount, null);
                    Leaderboard l = new Leaderboard("623094");
                    s.submitTo(l, new Score.SubmitToCB() {
                        @Override
                        public void onSuccess(boolean newHighScore) {
                            Toast.makeText(GameActivity.this, "Success!", Toast.LENGTH_LONG).show();
                        }
                        @Override
                        public void onFailure(String exceptionMessage) {
                            Toast.makeText(GameActivity.this, "Failed...", Toast.LENGTH_LONG).show();
                        }
                    });
                    // スコア確認の為LeaderboardのIDを指定してダッシュボードを開く
                    Dashboard.openLeaderboard("623094");

                    mTapCount = 0;
                    mTapCountText.setText(Integer.toString(mTapCount));
                    mTapCountText.setPosition(CAMERA_WIDTH / 2 - mTapCountText.getWidth() / 2, CAMERA_HEIGHT / 2 - 110);
                }
                return true;
            };
        };
        scene.getBottomLayer().addEntity(sendSprite);
        scene.getBottomLayer().registerTouchArea(sendSprite);

        Sprite dashboardSprite = new Sprite(CAMERA_WIDTH / 2 - mDashboardAreaTextureRegion.getWidth() / 2, CAMERA_HEIGHT / 2 + 100, mDashboardAreaTextureRegion){
            @Override
            public boolean onAreaTouched(final TouchEvent pSceneTouchEvent, final float pTouchAreaLocalX, final float pTouchAreaLocalY) {
                if(pSceneTouchEvent.getAction() == TouchEvent.ACTION_DOWN) {
                    Dashboard.open();
                }
                return true;
            };
        };
        scene.getBottomLayer().addEntity(dashboardSprite);
        scene.getBottomLayer().registerTouchArea(dashboardSprite);

        return scene;
    }

    @Override
    public void onLoadComplete() {

    }
}

◆ おわり

こんな感じゲームとハイスコアサーバーを連携させます。簡単ですね。
出来上がったAPKとサンプルプロジェクトを固めて上げておくのでご自由に使ってください。アプリのOpenFeintへの登録もしばらくそのままで置いておきます。ハイスコアを投稿したり、ご自由に使ってください。

AndEngineAndOpenFeintSample.apk
AndEngineAndOpenFeintSample.zip

EasyFreeAds Blog News Facebook Twitter Myspace Friendfeed Technorati del.icio.us Digg Google Yahoo Buzz StumbleUpon

6 Responses to "【Android】AndEngineとOpenFeintを組み合わせて使うサンプル"

1 | yitabashi0913

3月18日 2011 at 7:08 PM

Avatar

ブログとても参考にさせていただきました!ありがとうございます。

現在、AndEngineを使用してアプリを作っているのですが、解像度が端末ごとに違うため、画像をきれいに表示させるのに困っています。
(端末によっては画像が引き伸ばされてしまいます。。)

CAMERA_WIDTH,CAMERA_HEIGHT に、

>描画するエリアの指定。縦横比を保ったまま表示できる最大のサイズにスケールしてくれる。

と書いてあったのですが、スケール(引き伸ばさずに)、画像(png)を綺麗に表示差せる方法を御存知でしたらお教えいただけますと幸いです。

2 | Kaeden

7月23日 2011 at 5:50 PM

Avatar

This is way more helpful than antyhing else I’ve looked at.

3 | muzmax.net

11月13日 2013 at 11:01 PM

Avatar

Whhat i do not understood is in truth how you are noo longer actually much
more well-preferred than you migght be now.

You’re very intelligent. You recognize therefore significantly in relation to this matter, made me for my part believe it from numerous varied angles.
Its like women and men aren’t involved until it is onne thing to do with Girl
gaga! Yoour own stuffs nice. At all times handle iit up!

4 | mcm 財布 レオパード

2月9日 2014 at 8:03 AM

Avatar

Lovely facts, Appreciate it!

5 | Alina Lutjen

3月24日 2014 at 1:38 PM

Avatar

I know this site presents quality based articles or reviews and additional information, is there any other website which offers
these things in quality?

6 | http://www.23hq.com

4月19日 2014 at 4:45 PM

Avatar

Good site you’ve got here.. It’s difficult to find high-quality writing like yours these days.
I truly appreciate individuals like you! Take care!!

Categories

 

2017年11月
« 4月    
 12345
6789101112
13141516171819
20212223242526
27282930  

About

Author: tachibana

  • ちょっとしたことはTwitterに書いています。こっちはアプリの公開等の時に更新されます。
  • 最近はもっぱらJavaとObjective Cです。AS3は飽きました。
  • スクリプト言語ではPerlが好きでしたが最近はGAE/Jで何でもやってます。
  • Linuxは自宅サーバー建てるのがやっとのレベルです。前の会社で何日も徹夜してやったのはいい思い出です。
  • アプリへのご要望などご意見等ありましたらお気軽にご連絡下さい。

Alternative content here