NGUIのWrapContentでスロットみたいなの

ayumegu(プログラマー)
よろしくお願いします。

はい、こんにちは〜あゆめぐです。
NGUIでいくつか記事をまとめてかくよ〜^^
最初はNGUI ScrollViewとWrapContentでスロットみたいなものをつくってみた。
こんなの

左側のボタンでスロット回転、スロットの下のボタンで一個ずつリールが止まるだけのシンプルなもの
止まったときに上のラベルに数字が表示されます

##シーンの構成 シーンはこんな感じです

1つのリールはScrollViewオブジェクトににUIScroll Viewをアタッチ  

その下のUIWrap Contentを下図のように設定

UIWrapContentが下の要素をループさせるもの
UICenterOnChildは真ん中に要素を移動させるためのものです。

スロットの数字はそれぞれ下図のように設定
この画像の下にLabelを配置して数字おいています

他は特に特別なことはしていませんので説明を割愛

##スクリプト スクリプトファイルは一つだけ。
resultLabelとreelは該当するものをドラッグで設定する。

using UnityEngine;
using System.Collections;
public class SlotController : MonoBehaviour {
public UILabel resultLabel; // 結果表示のラベル
public UIScrollView[] reel; // スロットの3つのScrollView
private bool isGamePlay; // スロットプレイ中かのフラグ
private bool[] isReelPlay; // 各リールが回っているかのフラグ
private bool[] resenterFlg; // 各リールが止まって中心がセンターに移動したかのフラグ
private string[] resultNo; // 各リールの数字
private const int reelCount = 3; // リールの数
void Awake()
{
// リールが止まったときの真ん中の数値をとるようのイベントをセット
reel[0].transform.FindChild("UIWrap Content").GetComponent<UICenterOnChild>().onCenter = Reel1CenterObj;
reel[1].transform.FindChild("UIWrap Content").GetComponent<UICenterOnChild>().onCenter = Reel2CenterObj;
reel[2].transform.FindChild("UIWrap Content").GetComponent<UICenterOnChild>().onCenter = Reel3CenterObj;
}
void Start () {
isGamePlay = false;
isReelPlay = new bool[reelCount];
resenterFlg = new bool[reelCount];
resultNo = new string[reelCount];
for(int i = 0; i < isReelPlay.Length; i++)
{
isReelPlay[i] = false;
resenterFlg[i] = false;
}
}
void Update () {
if(isGamePlay)
{
for(int i = 0; i < reel.Length; i++)
{
if(isReelPlay[i])
{
// リールをまわす
reel[i].Scroll(5f * Time.deltaTime);
}
else
{
// 一つのマスのサイズを100にしているのでy座標が100にちかくなるところまで動かす
float posy = reel[i].transform.localPosition.y;
float y = 100 - Mathf.Abs(posy % 100);
if(y > 2f && !resenterFlg[i])
{
reel[i].Scroll((float)y / 50f * Time.deltaTime);
}
else
{
if(!resenterFlg[i])
{
// 近くまで動いたら真ん中に合わせる これを呼ぶとonCenterで登録された関数が呼ばれる
reel[i].transform.FindChild("UIWrap Content").GetComponent<UICenterOnChild>().Recenter();
resenterFlg[i] = true;
}
}
}
}
}
}
// スロット開始
void PlayStart()
{
isGamePlay = true;
for(int i = 0; i < isReelPlay.Length; i++)
{
isReelPlay[i] = true;
resenterFlg[i] = false;
resultNo[i] = "";
}
ShowText();
}
// スロット停止
public void Reel1Stop()
{
isReelPlay[0] = false;
}
public void Reel2Stop()
{
isReelPlay[1] = false;
}
public void Reel3Stop()
{
isReelPlay[2] = false;
}
// スロット停止時の中心オブジェクト取得
public void Reel1CenterObj(GameObject go){
string str = go.transform.FindChild("Label").GetComponent<UILabel>().text;
resultNo[0] = str;
ShowText();
}
public void Reel2CenterObj(GameObject go){
string str = go.transform.FindChild("Label").GetComponent<UILabel>().text;
resultNo[1] = str;
ShowText();
}
public void Reel3CenterObj(GameObject go){
string str = go.transform.FindChild("Label").GetComponent<UILabel>().text;
resultNo[2] = str;
ShowText();
}
public void ShowText()
{
resultLabel.text = resultNo[0] + " " + resultNo[1] + " " + resultNo[2];
}
}

##今回の感想 以外と作成するのに苦労した・・・。
リールを停止した際にすぐに().Recenter()を呼ぶと、下の方が真ん中に近ければ下から上に動くことや、距離が遠い場合、回っている速度より早く中心位置に移動したりと、いろいろ問題があって それを改善するために、

float posy = reel[i].transform.localPosition.y;
float y = 100 - Mathf.Abs(posy % 100);
if(y > 2f && !resenterFlg[i])
{
reel[i].Scroll((float)y / 50f * Time.deltaTime);
}

このソースを追加した。もっとうまいやり方があるのかもしれないけれど・・・とりあえず意図した通りに動くようになったのでいったんこれで終了