あなたのコード、激遅ぷんぷん丸?今すぐできる7つのチェック項目 PHP編

php_logo

みなさん、こんにちは。

GeNERACEのピンキリエンジニアこと、ひろゆきです。

ここのところPHPを書いてるんですが、同じ処理を書くとしても、どの関数を使えば良いのか分からないことがありました。

たとえば、繰り返し処理を書くにしてもfor, foreach, whileと3種類もあります。

いったいどれを使えば良いの?(´・ω・`)

分からないなら調べれば良い。

ということで、弊社環境にて処理速度の検証してみました。

(この辺ってググってみても、ソースが古かったりしてたので、あえて調べました)

Continue reading

大規模サービスでプログラマが注意すること(基礎)

blog_20130517

みなさん、こんにちは。

GeNERACEのピンキリエンジニアのひろゆきです。

いきなりですが、少しだけ自己紹介をしますと、前職やら何やらで比較的、大規模とよばれるサービスの開発、運用していました。

今回はその経験から得たノウハウ的なものをご紹介させて頂きたいと思います。

既にそういったサービスを経験されている方には当たり前のことかもしれませんが、これから参加される方、または、参加したばかりの方のお役に少しでもなれば幸いです。
Continue reading

【2週間で3万円!!】無課金から課金ユーザになるまで ~ソーシャルゲーム体験記~

kunshiro

こんにちは。ピンキリエンジニアのひろゆきです。

本日は技術的な話ではなく身近にソーシャルゲームにハマってた人@弊社プロデューサーがいたので、どうやってそういった状態になったかを聞いてきた話を書いてみます。

ユーザー心理的なもので何かのお役に立てたら幸いです。

ちなみに僕は前職でソーシャルゲーム開発をしていたため、純粋なユーザー目線というのは持てなくなってる気がしていましたが

今回の話を聞いて、忘れていた気持ちを思い出しました。

ソーシャルゲームをそれほどやりこんでいない状態から、ついつい課金までしてしまうところまでいっちゃう感じが新鮮でした。

回復する時間に合わせて、タイマーをかけてプレイしている様子はハマってるなーって感じです。

さて、以下からが聞いてきた話です

Continue reading

CakePHPでMongoDBを使う基本

こんにちは、ピンキリエンジニアのひろゆきです。

最近は久しぶりにPHPを書いており、MongoDBも始めてみたので、CakePHPとMongoDBについて少し書いてみたいと思います。

今回はちょこっと触った程度の、CakePHPからMongoDBを使用するための内容になります。

※CakePHPは1.xの時に少し使った、MongoDBはほぼ初心者な状態です

今回使用した環境は

・AmazonEC2のRedhat
・PHP 5.3.3
・Apache 2.2.15
・MongoDB 2.2.3
・CakePHP 2.3

になってます。

これでCakePHPからMongoDBを操作してみたいと思います。

まずはMongoDBをインストールします。

リポジトリの追加

sudo vi /etc/yum.repos.d/10gen.repo

リポジトリ設定

[10gen]
name=10gen Repository
baseurl=http://downloads-distro.mongodb.org/repo/redhat/os/x86_64
gpgcheck=0
enabled=0

インストール

sudo yum install mongo-10gen-server.x86_64 mongo-10gen.x86_64 --enablerepo=10gen

起動

sudo /etc/init.d/mongod start

これでMongoDBの準備はOKです。

次はこれをCakePHPから操作します。

CakePHPではデフォルトでいくつかのDBを使用でき、簡単にWEBサイトを構築出来ますが、
MongoDBについてはichikawayさんが提供しているPluginを使用することで可能になります。

https://github.com/ichikaway/cakephp-mongodb
※githubから

cloneするかもしくは別の方法で

app/Plugin/MongoDB

に配置します。

次にdatabase.phpを変更してMongoDBへの接続を定義します。

public $default = array(
	'datasource' => 'Mongodb.MongodbSource',
	'host' => 'localhost',
	'database' => 'your_database_name',
	'port' => '27017',
	'encoding' => 'utf8',
);

では、実際に操作をしてみます。

データを登録する

$data = array();
$data['value1'] = 1;
$data['value2'] = array(1,2,3);
$data['value3'] = array('a' => 1, 'b' => 2, 'c' =>3);
$data['value4'] = array('a' => array(1,2,3), 'b' => array(4,5,6));
$this->Sample->save($data);

発行されたクエリ

db.samples.insert( {"value1":1,"value2":[1,2,3],"value3":{"a":1,"b":2,"c":3},"value4":{"a":[1,2,3],"b":[4,5,6]},"modified":"MongoDate(0.39200000 1363326797)","created":"MongoDate(0.39200000 1363326797)","_id":ObjectId ("5142b74d2dc6b69371000002")} , true)

登録された内容

{ "_id" : ObjectId("5142b74d2dc6b69371000002"),
  "value1" : 1, 
  "value2" : [ 1, 2, 3 ], 
  "value3" : { "a" : 1, "b" : 2, "c" : 3 }, 
  "value4" : { "a" : [ 1, 2, 3 ], "b" : [ 4, 5, 6 ] }, 
  "modified" : ISODate("2013-03-15T05:17:21.393Z"), 
  "created" : ISODate("2013-03-15T05:17:21.393Z") }

データを取得する

$this->Sample->find('all');

発行されたクエリ

db.samples.find( [], [] ).sort( [] ).limit( 0 ).skip( 0 )

取得した内容

array(1) { 
 [0]=> array(1) {
  ["Sample"]=> array(7) { 
   ["value1"]=> int(1) 
   ["value2"]=> array(3) { [0]=> int(1) [1]=> int(2) [2]=> int(3) } 
   ["value3"]=> array(3) { ["a"]=> int(1) ["b"]=> int(2) ["c"]=> int(3) } 
   ["value4"]=> array(2) { ["a"]=> array(3) { [0]=> int(1) [1]=> int(2) [2]=> int(3) } ["b"]=> array(3) { [0]=> int(4) [1]=> int(5) [2]=> int(6) } } 
   ["modified"]=> object(MongoDate)#38 (2) { ["sec"]=> int(1363325551) ["usec"]=> int(106000) } 
   ["created"]=> object(MongoDate)#39 (2) { ["sec"]=> int(1363325551) ["usec"]=> int(106000) } 
   ["id"]=> string(24) "5142b74d2dc6b69371000002"
  }
 }
}

データが作成されました。

今回はidを指定せず自動で生成しています。

データを更新する

$list = $this->Sample->find('all');
$data = $list[0]['Sample'];
$data['value1'] = 100;
$data['value5'] = 'Hello World';
$this->Sample->save($data);

発行されたクエリ

db.samples.update( {"_id":ObjectId ("5142b74d2dc6b69371000002")}, {"$set":{"value1":100,"value2":[1,2,3],"value3":{"a":1,"b":2,"c":3},"value4":{"a":[1,2,3],"b":[4,5,6]},"modified":"MongoDate(0.39200000 1363326797)","created":"MongoDate(0.39200000 1363326797)","value5":"Hello World"}}, {"multiple":false} )

変更後の内容

array(1) {
 [0]=> array(1) {
  ["Sample"]=> array(8) {
   ["created"]=> object(MongoDate)#38 (2) { ["sec"]=> int(1363326797) ["usec"]=> int(392000) } 
   ["modified"]=> object(MongoDate)#39 (2) { ["sec"]=> int(1363326797) ["usec"]=> int(392000) } 
   ["value1"]=> int(100) 
   ["value2"]=> array(3) { [0]=> int(1) [1]=> int(2) [2]=> int(3) } 
   ["value3"]=> array(3) { ["a"]=> int(1) ["b"]=> int(2) ["c"]=> int(3) } 
   ["value4"]=> array(2) { ["a"]=> array(3) { [0]=> int(1) [1]=> int(2) [2]=> int(3) } ["b"]=> array(3) { [0]=> int(4) [1]=> int(5) [2]=> int(6) } } 
   ["value5"]=> string(11) "Hello World" 
   ["id"]=> string(24) "5142b74d2dc6b69371000002" } } }

CakePHPを使用しているので、同idがデータに存在する場合は更新にしてくれます。
新しく追加したカラム「value5」もちゃんと反映されています。

データを削除する

$list = $this->Sample->find('all');
$data = $list[0]['Sample'];
$this->Sample->delete($data['id']);

発行されたクエリ

db.samples.remove( {"_id":ObjectId ("5142b74d2dc6b69371000002")} )

指定されたidのデータが削除されました。

上記でCRUDについての操作が行えました。

Pluginのおかげで、これくらいであればサクッと簡単にできちゃいます。

まだまだ基本的な部分を触りながら確認している状況ですので、もう少し慣れたら詳しくメモも含めてログを残したいと思ってます。

MongoDBならではの操作方法についてとか書いておくと良いかなー、と。

以上、ありがとうございました!!

Andengineを使ってみる その1

GeNERACE laboを御覧の皆様、はじめまして。

ピンキリエンジニアのひろゆきです。

先日からAndengineを使っていますが、日本語の紹介があんまりないので書いてみます。

少しでもお役に立てば幸いです。

本家はここ→ http://www.andengine.org/

用意したものはAndroid開発環境があるMac、Eclipse、DLしたAndengine。

プロジェクト作成などはこちらを参考にしてください。

では、簡単ではありますが、サンプルを記載します。

※SampleScene.javaを作成して動かしています

文字を出力する。

// フォントを指定
Texture texture = new BitmapTextureAtlas(activity.getTextureManager(), 480, 800, TextureOptions.BILINEAR_PREMULTIPLYALPHA);
Font font = new Font(activity.getFontManager(), texture, Typeface.DEFAULT_BOLD, 30, true, Color.WHITE);
activity.getTextureManager().loadTexture(texture);
activity.getFontManager().loadFont(font);

// 出力する文字を設定
String str = "hello andengine!!";
Text text = new Text(0, 0, font, str, str.length(), new TextOptions(HorizontalAlign.LEFT), activity.getVertexBufferObjectManager());
attachChild(text);

まずはTextureの生成から使用したいFontを指定します。
それをActivityに設定して、Textにて文字を生成します。

画像を表示する

// 使用する画像名
String fileName = "button.png";

// 使用する画像の設定
BitmapTextureAtlas bta = new BitmapTextureAtlas(activity.getTextureManager(), 100, 100, TextureOptions.BILINEAR_PREMULTIPLYALPHA);
activity.getEngine().getTextureManager().loadTexture(bta);
ITextureRegion btr = BitmapTextureAtlasTextureRegionFactory.createFromAsset(bta, activity, fileName, 0, 0);
Sprite sprite = new Sprite(0, 0, btr, activity.getVertexBufferObjectManager());
sprite.setBlendFunction(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA);
attachChild(sprite);

ボタン画像を表示する

// 使用する画像名
String btnName = "button.png";
String btnPressName = "button_press.png";

// 使用する画像の設定
BuildableBitmapTextureAtlas bta = new BuildableBitmapTextureAtlas(activity.getTextureManager(), 100, 200);
ITextureRegion trBtn = BitmapTextureAtlasTextureRegionFactory.createFromAsset(bta, activity, btnName);
ITextureRegion trPresseBtn = BitmapTextureAtlasTextureRegionFactory.createFromAsset(bta, activity, btnPressName);
try {
    bta.build(new BlackPawnTextureAtlasBuilder<IBitmapTextureAtlasSource, BitmapTextureAtlas>(0, 0, 0));
    bta.load();
} catch (TextureAtlasBuilderException e) {</em>
    Debug.e(e);
}

// 通常時と押された時の画像を指定する
ButtonSprite buttonSprite = new ButtonSprite(0, 0, trBtn, trPresseBtn, activity.getVertexBufferObjectManager());
buttonSprite.setBlendFunction(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA);
attachChild(buttonSprite);

ボタン画像を押した時に処理を行う

public class SampleScene extends Scene implements ButtonSprite.OnClickListener {

ButtonSprite.OnClickListenerを定義します。

// 識別タグ
buttonSprite.setTag(1);
// リスナー
buttonSprite.setOnClickListener(this);
// 認識するエリア登録
registerTouchArea(buttonSprite);

上記で表示したボタン画像に対して、この処理を加えます。

@Override
public void onClick(ButtonSprite pButtonSprite, float pTouchAreaLocalX, float pTouchAreaLocalY) {
    if (pButtonSprite.getTag() == 1) {
        // ボタン画像を大きくする
        buttonSprite.setScale(1.2f);
    }
}

どのボタン画像が押されたかはTagで識別します。

画像を動かす

// Handloerを定義する
public TimerHandler timeHandler = new TimerHandler(1f / 60f, true, new ITimerCallback() {
    @Override
    public void onTimePassed(TimerHandler pTimerHandler) {
        // Y軸に移動させる
        sprite.setPosition(sprite.getX() ,sprite.getY() + 1);
        // 拡大させる
        sprite.setScale(sprite.getScaleX() * 1.01f, sprite.getScaleY() * 1.01f);
        // 透明にする
        sprite.setAlpha(sprite.getAlpha() * 0.99f);
    }
});

これだけでは画像は動きません。
Handlerは登録する必要があります。

registerUpdateHandler(timeHandler);

動きを止めたいときは

unregisterUpdateHandler(timeHandler);

とします。
慣れてないときは、これを忘れて動かない!ということが多々ありました。

Sceneを遷移させる

NextScene scene = new NextScene(activity);
activity.getEngine().setScene(scene);

SceneからActivityを遷移させる

activity.startActivity(new Intent(activity, NextActivity.class));
activity.finish();

現在のActivityを終了して、次のActivityを呼び出します。

他にAndengineの機能は多々ありますが、調べきれていない部分などもありますので、次回に続きたいと思います。

ご覧頂きありがとうございました。