2014年9月19日金曜日

複数でセットになるスイッチ

スイッチA、スイッチB、スイッチC…というように、
スイッチが複数(3つ以上)あって、
Aを押したらAをONに、A以外をOFFに
Bを押したらBをONに、B以外をOFFに、という具合に、
あるスイッチの状態を他のスイッチとも連動して反映させるにはどうしたら良いか。


要するに、



こーいう、セレクト画面をボタン機能で作りたいって話です。
簡単に仕様をまとめると、以下のような感じだろうか。

■仕様
・押されているスイッチは常に一つのみ
・あるスイッチを押すと、他のスイッチは全てOFFになる
 (複数押された状態にならない)
・同じボタンを連続で押した場合は、ON→OFFにはならない
 (どこも押されていない状態が存在しない=他のボタンを押して切り替える)
・押されているスイッチによって処理を分岐(メイン画像を差し替えるなど)

cocos2dxにおけるスイッチやトグルの作り方はよく見かけるのだけど、
こういうセレクトスイッチの作り方はみかけない…ので、適当に考えてみた。

例題としてスイッチABCの三つを使い、三つで一セットの
ステージセレクトボタンをつくる。
AをONにしたらA以外(BC)をOFFにする。
※画像はPlistから読み込む仕様

//まずはボタンを作成する
stButtonMake("スイッチA_off画像名","スイッチA_on画像名", 置く場所:X座標, 置く場所:Y座標, STAGE01);
stButtonMake("スイッチB_off画像名","スイッチB_on画像名", 置く場所:X座標, 置く場所:Y座標, STAGE02);
stButtonMake("スイッチC_off画像名","スイッチC_on画像名", 置く場所:X座標, 置く場所:Y座標, STAGE03);

//スイッチ作成用の関数//
void MainMenu::stButtonMake(const char *imageA, const char *imageB, float xlength,float ylength, int theTag)
{
 //画面の幅を取得
 Size winSize = Director::sharedDirector()->getWinSize();
 //一ブロックのサイズを定義する
 int Block_x = winSize.width/10;
 int Block_y = winSize.height/10;

 //off_通常時
 Sprite* st_off = Sprite::createWithSpriteFrameName(imageA);
 st_off->setColor(ccc3(130, 120, 111));
 //off_オーバー時
 Sprite* st_off_ov = Sprite::createWithSpriteFrameName(imageB);
 st_off_ov->setColor(ccc3(130, 120, 111));
 auto* st_off_Item = MenuItemSprite::create(st_off, st_off_ov, NULL);
 //on_通常時
 Sprite* st_on = Sprite::createWithSpriteFrameName(imageA);
 //on_オーバー時
 Sprite* st_on_ov = Sprite::createWithSpriteFrameName(imageB);
 auto* st_on_Item = MenuItemSprite::create(st_on, st_on_ov, NULL);

 auto* stToggleItem = MenuItemToggle::createWithTarget(
   this, menu_selector(MainMenu::Test), st_off_Item, st_on_Item, NULL);

 //一番最初のトグルだけトグルの初期値をonから始める
 if (theTag == STAGE01) stToggleItem->setSelectedIndex(1); //0でoff(初期値)

 stToggleItem->setTag(theTag);        //トグルに対してタグをつける (※STAGE01〜03という変数名で渡す)
 stToggleItem->setPosition(ccp(Block_x * xlength, Block_y * ylength));
 this->addChild(stToggleItem);       //★重要★あとでgetChildByTagしたいのでここでaddChildしておく

 auto* stToggleMenu = Menu::create(stToggleItem, NULL);
 stToggleMenu->setPosition(CCPointZero);
 this->addChild(stToggleMenu);

※全てのスイッチにタグをふる。
 また、ToggleItemの時点で一度addChildしないと、後でgetTagできないっぽい。
 で、上のスイッチを押すとコールバックとして"Test"という関数を呼ぶので、
 以降その処理。

void MainMenu::Test(Ref* pSender)
{
 int Tag = dynamic_cast(pSender)->getTag();            //押されたボタンのタグを取得
 if (Tag == STAGE01) //押されたボタンのタグがSTAGE01ならStageSelect(クラスのメンバ変数)を1に
 {
  StageSelect = 1;
 } else if (Tag == STAGE02) {//押されたボタンのタグがSTAGE02ならStageSelectを2に
  StageSelect = 2;
 } else if (Tag == STAGE03) {
  StageSelect = 3;
 }

 //ここで全てのスイッチを一度全部OFFに 
 for (int i = STAGE01; i < STAGE03 +1; i++)
 {
  auto* stToggleItem = (MenuItemToggle *)this->getChildByTag(i);
  stToggleItem->setSelectedIndex(0);
 }

 //押されたボタンだけ再度ONに
 dynamic_cast(pSender)->setSelectedIndex(1);

}

cocos2dxのMenuItemクラスを使用したスイッチは、コールバック時に
Node情報を持っているので、押されたボタンのタグなどを取得できる。
まずは押されたスイッチのタグを取得。全てのスイッチをいったんOFFに。
(全てのスイッチをオフにせずとも、
 押されたスイッチのタグ以外のスイッチを条件分岐でOFFにできると思う。
 時間がある時にちょっと手直したい。)

押されたスイッチだけ再度ONにする
この関数の中で最後にスイッチの状態を必ず1(On)にしているので、
同じ場所をクリックしてもOFFにならない。
で、ifで押されたスイッチのタグに合わせて、次のシーンへの処理を分岐させる
今回の場合、予めStageSelectという変数をつくっておき、
StageSelectが1ならAステージへ…という感じで
シーン作成時に分岐させる、という感じ。

こんなかんじでいかがですかねぇ。
なんか細かいところで無駄があるような気がするけど、
とりあえずちゃんと動いてるようなので、よしとする!!



☆★というわけでcocos2d-xで制作しました★☆
☆★複数でセットになるスイッチはステージセレクトで使用してます★☆

レッド・ザ・パニッシャー ―スタイリッシュレトロアクション―
カテゴリ: アクション
Google Playで詳細を見る

今なら(永久に)無料! 今すぐチェック!!

0 件のコメント:

コメントを投稿