AppStoreにアップする(8)

 で、いよいよオーナー候補の画像を貼付けてサイコロを回すわけですが…
 オーナー候補が6人以上の場合、どうするか?

 そこがコンピュータ上のサイコロのいいところ。
 回転させてる最中に、どんどんサイコロの側面の画像を差し替えていっちゃえばいいわけですよ。

$テン*シー*シー-1

 特に、ダイスを回せ!の場合、横着して真正面から見た状態で回転させてるので、見える面の最大数は2でしかないんですな。

$テン*シー*シー-3
3面見えることはない

 なので、回転して出てくる新しい面のテクスチャの画像を逐次差し替えれば、必要なテクスチャは2つ(tx0、tx1)って事になる。

$テン*シー*シー-2

 これが前回、まだ使われないって言ってたDiceGLクラスのdrawPlane:メソッドでの
if (maxIndex == 0) {
// サイコロ描画
glBindTexture(GL_TEXTURE_2D, texture[part]);
} else {
glBindTexture(GL_TEXTURE_2D, texture[(part % 2)]);
}

 て処理なわけです。6面をtexture[0]かtexture[1]で表示してる。
 ちなみに
 part % 2

 はpartを2で割った余りっす。当然0か1になる。

 オーナー候補の人達の画像は、DiceGL.hで用意したphotosに保持させます。で人数はmaxIndexに保存。まあ、[photos count]ってやってもいいんだけど…
 こいつらを設定するメソッドとして以下を用意。
 以前にphotosに確保していたUIImageをremoveAllObjectsで解放してから再設定。
 initImage呼んでるのはmaxに0を指定された時のためです。
 同じようにif (maxIndex == 1)はmaxが1の場合、texture[1]がサイコロの絵のままになっちゃうので、その対応。
 movingPhaseは当然movingPhase_Idle状態に設定。
 angleは初期位置として45度を指定して右左2面が表示される状態にしてる。
-(void)setImages:(UIImage**)images max:(int)max {
movingPhase = movingPhase_Idle;
angle = 45;
curtImageIndex[0] = 0;
curtImageIndex[1] = 1;
[photos removeAllObjects];
[self initImage];
maxIndex = max;
for (int i = 0; i < maxIndex; i++) {
[photos addObject:images[i]];
if (i < 4) {
[self map:images[i] texture:texture[i]];
}
}
if (maxIndex == 1) {
[self map:[photos objectAtIndex:0] texture:texture[1]];
}
}

 で、今回新しく追加してるのがcurtImageIndexインスタンス変数。
 こいつにtexture[0]、texture[1]、それぞれに何番目の画像が貼られているかを記憶させます。

 でもって、drawメソッドで現在の回転角から表示されている面のtextureに表示されるべき画像が貼られているか判断し、貼られていない時はtextureを更新、それが
-(void)draw {


if (maxIndex > 0) {
int image_index = (int)angle / 90;
int tx_index = image_index % 2;
tx_index = 1 ^ tx_index;
image_index++;
image_index = image_index % maxIndex;
if (curtImageIndex[tx_index] != image_index) {
[self map:[photos objectAtIndex:image_index]
texture:texture[tx_index]];
curtImageIndex[tx_index] = image_index;
}
}


 て部分なわけです。

 まず
int image_index = (int)angle / 90;

 で、現在、左側に表示されるべき画像の番号を決定。

$テン*シー*シー-4

 そのまま対応するtextureのインディックスを計算(image_indexをmaxIndex以上にならないように調整する前に使ってる事に注意)
int tx_index = image_index % 2;

 ただし、左側は前のdraw処理時に設定済みのなので、放っておいて右側のtextureのインディックスを計算
tx_index = 1 ^ tx_index;

 とし
if (curtImageIndex[tx_index] != image_index) {

 でテクスチャに設定されてる画像が違っていれば
[self map:[photos objectAtIndex:image_index]
texture:texture[tx_index]];

 として更新しとるわけです。
ブール演算
 1 ^ tx_index
というのは1とtx_indexのXORというブール演算。両方の値が一緒の場合0になる
 1 ^ 0 = 1
 1 ^ 1 = 0
 0 ^ 1 = 1
 0 ^ 0 = 0
という規則で計算される。
 なので、tx_indexが1の時は計算結果が0になり、0の時は1になる。

 う~ん、ここまで書いて気づいたけど、左側が設定済ってのは、前のdrawの時からのangleの変化が90度以内でないと成り立たないね~。
 試しにrotationメソッドでangleに加算する角度を200とかにして、デバッガでコマ送りしてみたらキッチリ間違っとりました。
-(void)rotation {
angle += 200;
}

 1/60秒に200度は超高速回転なんで、肉眼だと気づけなかったのね。
 まあ、画面上の問題で、オーナー決め計算には影響しないのでよしとしておきましょう。
 こだわるなら
// 左側テクスチャのチェック
int image_index = (int)angle / 90;
int tx_index = image_index % 2;
image_index = image_index % maxIndex;
if (curtImageIndex[tx_index] != image_index) {
[self map:[photos objectAtIndex:image_index] texture:texture[tx_index]];
curtImageIndex[tx_index] = image_index;
}
// 右側テクスチャのチェック
tx_index = 1 ^ tx_index;
image_index++;
image_index = image_index % maxIndex;
if (curtImageIndex[tx_index] != image_index) {
[self map:[photos objectAtIndex:image_index] texture:texture[tx_index]];
curtImageIndex[tx_index] = image_index;
}

 ですな。

 あとは、ThrowDiceViewController.mのviewDidLoadメソッドで
UIImage* images[] = {
[UIImage imageNamed:@"img1.png"],
[UIImage imageNamed:@"img2.png"],
[UIImage imageNamed:@"img3.png"],
[UIImage imageNamed:@"img4.png"],
[UIImage imageNamed:@"img5.png"],
[UIImage imageNamed:@"img6.png"],
[UIImage imageNamed:@"img7.png"]
};
[[glView dice] setImages:images max:7];

 とやって実行。
 ダミー画像として、img1.png~img7.pngを組み込んどります。

$テン*シー*シー-5

 次回は、回転速度を落としつつ、オーナーのところで止める処理。

------------
サンプルプロジェクト:Dev20100321.zip