SlideShare a Scribd company logo
Cocos2d-x ハンズオン#1
簡単なゲームを作ってみよう
• 経歴
-株式会社コナミデジタルエンタテインメント(プログラマ)
-ポノス株式会社 開発2部(エンジニア)
• 担当:クライアントエンジニア
• 趣味:お菓子作り、フットサル、旅行
• その他:Cocos2d-x 関西支部長()
山野 真吾
やること
• Cocos2d-xの簡単な使い方
• 初歩的なゲームロジック
• 説明はXcodeで行う
やらないこと
• 画面遷移(E.g. タイトル画面 → ゲームメイン画面)
• アニメーション
• マルチ解像度対応
• プログラムの効率性について
• C++やSTLの説明
• Cocos2d-xの細かい仕様の説明
ゲームを作ることが目的!!
ライブコーディングしながら説明します
今回はこれだけでゲームが完成します
1. 画像の表示
2. 画像の制御
3. 画面サイズの取得
4. タッチイベントの取り方
5. 簡単なイベント処理
画像の表示手順
画像ファイルの読み込み
画像の位置設定
画像をシーンへ追加
※ 画像を読み込んだだけでは表示されない!!
画像を表示してみる
// 画面サイズを取得する
auto winSize = Director::getInstance()->getWinSize();
// 画像ファイルを読み込み
auto cardSprite = Sprite::create("h1.png");
// 画像の位置を設定する
cardSprite->setPosition(Vec2(winSize.width * 0.5f, winSize.height * 0.5f));
// 画像をシーンに追加する
addChild(cardSprite);
アンカーポイントを移動させる
// ファイル名を指定して画像を生成する
auto cardSprite = Sprite::create("h1.png");
// アンカーポイントを左下へ設定する
cardSprite->setAnchorPoint(Vec2::ANCHOR_BOTTOM_LEFT);
アンカーポイントについて
原点(0,0)
アンカーポイント
(デフォルトは中央)
y
x
アンカーポイントと画像の位置
原点(0,0)
setPosition(x’, y’)
y’
y
x
x’
左下にアンカーポイントを移動させる
原点(0,0)
y’
y
x
x’
setAnchorPoint(Vec2::ANCHOR_BOTTOM_LEFT)
EventListenerTouchOneByOne
• シングルタッチのイベントリスナー
• タッチイベント
• onTouchBegan (タッチ開始時)
• onTouchMoved (タッチ開始後、タッチ位置を移動した時)
• onTouchEnded (タッチ正常終了時)
• onTouchCancelled (タッチ異常終了時)
EventListenerTouchOneByOneの使い方
イベントリスナーの生成
タッチイベントを記述
イベントリスナーを登録
EventListenerTouchOneByOneの使い方
// シングルタッチのイベントリスナー生成
auto listener = EventListenerTouchOneByOne::create();
// タッチ開始時にコールされるイベント(今回はこのイベントしか使わない)
listener->onTouchBegan = [this](Touch* touch, Event* event) {
/* ここにタッチ開始時の処理を書く */
return true;
};
// イベントリスナーの登録
auto dispatcher = Director::getInstance()->getEventDispatcher();
dispatcher->addEventListenerWithSceneGraphPriority(listener, this);
神経衰弱を作ってみる!!
プロジェクトのダウンロード
• 時間の都合上、プロジェクト設定の説明は省略
• XcodeとAndroid Studio共に環境設定済み
プロジェクト構成
GameManagerクラス
・神経衰弱の制御クラス
Cardクラス
・カード制御クラス
Resources > images
・カード画像群
ゲームの初期化:カード読み込み〜配置
カード画像の読み込み
カード情報を生成する
カードを配置する
カード読み込み、表示する
• 1〜9までのハートとダイヤのカードがある
• 上記以外のカードは裏面用がある
カード読み込み、表示する
※ 数字カード種類数 = MAX_CARD_NUMBER = 9
GameManager.cpp
// カードをロードする関数
void GameManager::loadCards()
{
for (int i = 1; i <= MAX_CARD_NUMBER; i++) {
// ハート柄のカードをロードする
auto heart = Sprite::create(StringUtils::format("h%d.png", i));
heart->setAnchorPoint(Vec2::ANCHOR_BOTTOM_LEFT);
addChild(heart);
// ダイヤ柄のカードをロードする
auto diamond = Sprite::create(StringUtils::format("d%d.png", i));
diamond->setAnchorPoint(Vec2::ANCHOR_BOTTOM_LEFT);
addChild(diamond);
}
}
カード読み込み、表示する
実行すると、以下の様になる
カードを動的配列に入れる
Spriteを動的配列に格納する場合
cocos2d::Vector<cocos2d::Sprite*> cards;
・使い方はstd::vectorとほぼ同じ
GameManager.h
class GameManager : public cocos2d::Layer {
/* 省略 */
private:
// 動的配列を宣言する
cocos2d::Vector<cocos2d::Sprite*> cards{};
};
カードを動的配列に入れる
GameManager.cpp
void GameManager::loadCards()
{
for (int i = 1; i <= MAX_CARD_NUMBER; i++) {
auto heart = Sprite::create(StringUtils::format("h%d.png", i));
heart->setAnchorPoint(Vec2::ANCHOR_BOTTOM_LEFT);
addChild(heart);
// 動的配列へ追加
cards.pushBack(heart);
auto diamond = Sprite::create(StringUtils::format("d%d.png", i));
diamond->setAnchorPoint(Vec2::ANCHOR_BOTTOM_LEFT);
addChild(diamond);
// 動的配列へ追加
cards.pushBack(diamond);
}
}
Cardクラスを作る
• 数字情報(1〜9)
• 画像の管理(表面 and 裏面)
• 現在の状態(オープン or クローズ)
必要な変数
必要な関数
• オープン or クローズ制御
• カードを表示有無を制御
• 現在の状態を取得
• カードサイズの取得
• 数字情報の取得
Cardクラス ~必要な変数~
// cocos2d::Vectorで管理するために、cocos2d::Nodeを継承させる
class Card : public cocos2d::Node {
/* 省略 */
private:
uint8_t number{ 0 }; //カードの数字
cocos2d::Sprite* frontSprite{ nullptr }; // 表面の画像
cocos2d::Sprite* backSprite{ nullptr }; // 裏面の画像
bool bOpen{ false }; // カードの状態管理
};
Card.h
Cardクラス ~実装する関数~
class Card : public cocos2d::Node {
protected:
Card() = default;
~Card();
bool init(const uint8_t cardNumber, const std::string& cardFrontSpriteName,
const std::string& cardBackSpriteName);
public:
static Card* create(const uint8_t cardNumber, const std::string&
cardFrontSpriteName, const std::string& cardBackSpriteName);
void open(); // カードをオープンする
void close(); // カードをクローズする
void visible(); // カードを表示する
void invisible(); // カードを非表示する
bool isOpen() const; // カードがオープン状態か判定する
uint8_t getCardNumber() const; // カードの数字を取得する
cocos2d::Size getCardSize() const; // カードサイズを取得する
/* 省略 */
};
Card.h
今回のカード制御ロジックについて
上面下面 重ねて表示する
Open
カード状態
Close
非表示
非表示 表示
表示
時間の都合上、
画像の削除は行わない
spriteの表示設定
// カードをオープンする
void Card::open()
{
frontSprite->setVisible(true);
backSprite->setVisible(false);
bOpen = true;
}
Spriteの表示設定を変更する関数
sprite->setVisible(bool visible)
close()、invisible()、visible()も上記を参考にして作成する
Card.cpp
init関数とcreate関数について
init関数
create関数
• 初期化関数
• メンバー変数はこの関数内で初期値を束縛する…ことが多い
• インスタンスを生成する関数
• 関数内でinit関数をコールする
コードを参照しながら説明します
Cardクラスを動的配列で管理する
#include “Card.h” // カードクラスのインクルード
class GameManager : public cocos2d::Layer {
/* 省略 */
private:
// 動的配列を宣言する(変更)
cocos2d::Vector<Card*> cards{};
};
cocos2d::Nodeクラスを継承しているため、
cocos2d::Vectorで管理することが可能!!
GameManager.h
loadCards関数の修正
GameManager.cpp
void GameManager::loadCards()
{
for (int i = 1; i <= MAX_CARD_NUMBER; i++) {
auto heart = Card::create(i, StringUtils::format(“h%d.png", i), “back_red.png”);
heart->setAnchorPoint(Vec2::ANCHOR_BOTTOM_LEFT);
addChild(heart);
// 動的配列へ追加
cards.pushBack(heart);
auto diamond = Card::create(i, StringUtils::format(“d%d.png", i),
“back_red.png”);
diamond->setAnchorPoint(Vec2::ANCHOR_BOTTOM_LEFT);
addChild(diamond);
// 動的配列へ追加
cards.pushBack(diamond);
}
}
create関数をSpriteからCardに変更するだけ
カードを均等に配置する
• カードサイズの取得 → sprite->getContentSize()
• 画面サイズの取得 → Director::getInstance()->getWinSize()
• 縦、横に並べるカード数 → 今回は3x6で並べる
カードを均等に配置する
縦x横 = 2x3で考えみる
カードを均等に配置する
縦方向のマージン
横方向のマージン
= (画面縦幅 - カード縦幅 * 縦方向の枚数) / (縦方向の枚数 + 1)
= (画面横幅 - カード横幅 * 横方向の枚数) / (横方向の枚数 + 1)
カードを均等に配置する
縦方向のマージン
横方向のマージン
= (画面縦幅 - カード縦幅 * 縦方向の枚数) / (縦方向の枚数 + 1)
= (画面横幅 - カード横幅 * 横方向の枚数) / (横方向の枚数 + 1)
カードを均等に配置する
横方向の枚数 = MAX_CARD_ROWS とする
縦方向の枚数 = MAX_CARD_COLS
// カードを配置する関数
void GameManager::arrangeCards()
{
const Size windowSize = Director::getInstance()->getWinSize();
const Size cardSize = cards.back()->getCardSize(); // カードサイズは全て同じ
const Size margin((windowSize.width - cardSize.width * MAX_CARD_ROWS) / (MAX_CARD_ROWS +
1),
(windowSize.height - cardSize.height * MAX_CARD_COLS) / (MAX_CARD_COLS +
1));
int row = 0;
int col = 0;
for (auto& card : cards) {
card->setPosition((cardSize.width + margin.width) * row + margin.width,
(cardSize.height + margin.height) * col + margin.height);
row++;
if (row % MAX_CARD_ROWS == 0) {
row = 0;
col++;
}
}
}
GameManager.cpp
カードの配置順序
原点(0,0)
カードへのタッチ判定
タッチ位置の取得
カードへのタッチ判定
カードをオープンする
タッチ位置の取得:getLocation()
// シングルタッチのイベントリスナー生成
auto listener = EventListenerTouchOneByOne::create();
// タッチ開始時にコールされるイベント(今回はこのイベントしか使わない)
listener->onTouchBegan = [this](Touch* touch, Event* event) {
// タッチ位置の取得
auto loc = touch->getLocation()
return true;
};
// イベントリスナーの登録
auto dispatcher = Director::getInstance()->getEventDispatcher();
dispatcher->addEventListenerWithSceneGraphPriority(listener, this);
GameManager.cpp > init関数
カードへのタッチ判定方法
指定した位置がRect(カード)内に存在するか判定する関数
rect.containsPoint(const Vec2& point) const
Rectの作成方法
Rect rect(originのXY座標, rectのサイズ)
カード座標 カードサイズ
getPosition() sprite->getContentSize()
cocos2d::Rectについて
origin
width
height
heightorigin.y+( )origin.x+width,
カードへのタッチ判定
// タッチ位置がカード内に存在するか判定する
bool Card::inside(const cocos2d::Vec2& loc) const
{
auto position = getPosition();
auto contentSize = frontSprite->getContentSize();
Rect rect(position, contentSize);
return rect.containsPoint(loc);
}
Card.cpp
class Card : public cocos2d::Node {
/* 省略 */
void invisible(); // カードを非表示する
bool inside(const cocos2d::Vec2& loc) const; // カード内へのタッチか判定する
/* 省略 */
};
Card.h
CREATE_FUNCマクロについて
• create関数を生成するマクロ
• 仮引数は設定できない
• init関数は定義する必要がある
仮引数が必要なcreate関数はCardクラスのように
独自実装する必要がある
ゲームの処理ロジック
1枚目のカードを開く
2枚目のカードを選択
カードのマッチング判定
ゲームのリセット
カードが全てマッチングした場合
繰り返し処理
ゲーム管理に必要な変数
• オープンしたカードのインデックス
• 残りのカードペア数
• 現在のゲーム進行状態管理
class GameManager : public cocos2d::Layer {
static constexpr int MAX_CARD_NUMBER = 9;
static constexpr int MAX_CARD_ROWS = 6;
static constexpr int MAX_CARD_COLS = 3;
/* 省略 */
private:
cocos2d::Vector<Card*> cards{};
int selectedFirstCardIndex{ 0 };
int selectedSecondCardIndex{ 0 };
int remainingNumberOfPairs{ MAX_CARD_NUMBER };
GameState gameState{ GameState::OpenFirstCard };
};
GameManager.h
ゲームの進行状態管理
• 1枚目のカードをオープンする
• 2枚目のカードをオープンする
• オープンしたカードをチェックする
• ゲームをリセットする
→ enum classでゲーム状態を管理する
必要なゲーム状態
どうやってゲーム状態を管理するか
ゲームの進行状態管理:enum class
class GameManager : public cocos2d::Layer {
static constexpr int MAX_CARD_NUMBER = 9;
static constexpr int MAX_CARD_ROWS = 6;
static constexpr int MAX_CARD_COLS = 3;
enum class GameState {
OpenFirstCard, // 1枚目のカードを選択
OpenSecondCard, // 2枚目のカードを選択
CheckPair, // カードのマッチングを行う
ResetGame, // ゲームをリセットする
};
/* 省略 */
};
GameManager.h
ゲーム状態毎の処理方法
switch (gameState) {
// 1枚目のカードを選択
case GameState::OpenFirstCard:
/* 処理 */
break;
// 2枚目のカードを選択
case GameState::OpenSecondCard:
/* 処理 */
break;
// カードのペアチェック
case GameState::CheckPair:
/* 処理 */
break;
// ゲームをリセットする
case GameState::ResetGame:
/* 処理 */
break;
}
GameManager.cpp > init関数 > listener->onTouchBeganのラムダ式内
カード選択の処理
switch (gameState) {
case GameState::OpenFirstCard:
for (int i = 0; i < cards.size(); i++) {
// カードがクローズしているかつタッチポイントがカード内に存在する場合
if (!cards.at(i)->isOpen() && cards.at(i)->inside(loc)) {
cards.at(i)->open();
selectedFirstCardIndex = i;
gameState = GameState::OpenSecondCard;
break;
};
}
break;
/* 省略 */
}
GameManager.cpp > init関数 > listener->onTouchBeganのラムダ式内
GameState::OpenSecondCardも同様にして記述する
カードペアチェックの処理
switch (gameState) {
/* 省略 */
case GameState::CheckPair:
// ペアが成立した場合
if (cards.at(selectedFirstCardIndex)->getCardNumber() ==
cards.at(selectedSecondCardIndex)->getCardNumber()) {
cards.at(selectedFirstCardIndex)->invisible();
cards.at(selectedSecondCardIndex)->invisible();
// 残りのペア数を減らす
remainingNumberOfPairs--;
}
// ペアが成立しなかった場合
else {
cards.at(selectedFirstCardIndex)->close();
cards.at(selectedSecondCardIndex)->close();
}
/* 省略 */
}
GameManager.cpp > init関数 > listener->onTouchBeganのラムダ式内
カードペアチェックの処理
switch (gameState) {
/* 省略 */
case GameState::CheckPair:
/* 省略*/
// 残りのペアが無くなった場合、ゲームをリセットする
if (remainingNumberOfPairs == 0) {
gameState = GameState::ResetGame;
}
else {
gameState = GameState::OpenFirstCard;
}
break;
/* 省略 */
}
GameManager.cpp > init関数 > listener->onTouchBeganのラムダ式内
ゲームリセットの処理
switch (gameState) {
/* 省略 */
case GameState::ResetGame:
remainingNumberOfPairs = MAX_CARD_NUMBER;
// カードの状態をリセットする
for (auto& card : cards) {
card->visible();
card->close();
}
// カードの再配置
arrangeCards();
// 新しいゲームを開始する
gameState = GameState::OpenFirstCard;
break;
}
GameManager.cpp > init関数 > listener->onTouchBeganのラムダ式内
カードをシャッフルする
このままだと、いつも同じ並びでカードが配置される
→ カード配列自体をシャッフルして再配置する
動的配列(cards)をシャッフルする方法
std::shuffle(cards.begin(), cards.end(), std::mt19937())
cardsのイテレータ 乱数生成器(メルセンヌ・ツイスタ)
※何度実行しても同じようにシャッフルされる
→ 完全ランダムにシャッフルする方法はあります!!
【祝】ゲーム完成 (๑•̀ㅂ•́)‫✧و‬
改良案
• カードをめくるアニメーションの追加
• BGMやSEの追加
• スコアや制限時間を追加
• オンライン対戦できるようにする
• マルチ解像度対応
ゲームの解答
• https://github.com/sngymn/cocos2dx-handson1

More Related Content

PPT
Cocos2d
PDF
㉕cocos2dを覚えよう!初級編③
PDF
2012 03-03-titanium plusquicktigame2d
PPTX
Aiwolf seminar 2019_ja
PDF
㉒初期プロジェクトを改造!
PDF
【TechBuzz】第9回cocos2d-x勉強会「シェーダ書いてますか?」
PDF
PF部2011年12月勉強会.androidsola
PDF
Rubyコードの最適化
Cocos2d
㉕cocos2dを覚えよう!初級編③
2012 03-03-titanium plusquicktigame2d
Aiwolf seminar 2019_ja
㉒初期プロジェクトを改造!
【TechBuzz】第9回cocos2d-x勉強会「シェーダ書いてますか?」
PF部2011年12月勉強会.androidsola
Rubyコードの最適化

Viewers also liked (12)

PDF
Presentation to Governor Walker (3.14.2017 final)
PPTX
IBM cognitive service introduction
PDF
Freedom Comes from Within
PPTX
なぜなにリアルタイムレンダリング
PDF
The Art of Social Media Infographic
PDF
13 Slack Tips and Use Cases For Sales Teams On Slack
PDF
Sage Gold Inc. Corporate Presentation
PDF
データ分析を支えるクローリング環境の構築
PDF
The Data Revolution - Serena Capital
DOC
Coming of age
PPTX
MTAM Connected Technologies Campus
PDF
01 commonsense political thinking booklet
Presentation to Governor Walker (3.14.2017 final)
IBM cognitive service introduction
Freedom Comes from Within
なぜなにリアルタイムレンダリング
The Art of Social Media Infographic
13 Slack Tips and Use Cases For Sales Teams On Slack
Sage Gold Inc. Corporate Presentation
データ分析を支えるクローリング環境の構築
The Data Revolution - Serena Capital
Coming of age
MTAM Connected Technologies Campus
01 commonsense political thinking booklet
Ad

Similar to Cocos2d-xハンズオン#1 in 大阪 (20)

PDF
Cocos2d xで簡単なゲームを作ってみよう!
PDF
Cocos2d-x実践講座 in 鹿児島
PDF
Cocos2d-x公開講座 in 鹿児島
PDF
cocos2d-xハンズオン勉強会 in 名古屋
PDF
Cocos2dx step2 アプリケーション基本
PDF
Cocos2d-x v3.2を利用してシューティングゲームを作ろう!
PPTX
Cocos2d-x 3.0を使ったゲーム “消滅都市” の開発事例
KEY
Introduction for cocos2d
PDF
cocos2d-xにおけるBox2Dの利用方法および便利なツール
PDF
cocos2d-x公開講座 in 鹿児島
PDF
Cocos2dを使ったi phoneゲーム開発手法
KEY
Cocos2d xをさわってみよう!
PDF
Cocos2d/2d-x/html5 [Objective-C/C++/JavaScript] 好みの言語はどれですか?
PDF
Cocos2d-x勉強会 2014/10/05
PDF
cocos2d-xとCocosBuilderでゲームを作ってみよう
PDF
㉞cocos2d-xの開発環境をインストールしてみよう
PDF
㊱タイルマップに挑戦
PDF
cocos2dxことはじめ(2.2.5)
PDF
プログラム初心者がCocos2d xで ゲームを作った話
PDF
cocos2d-xとCocosBuilder
Cocos2d xで簡単なゲームを作ってみよう!
Cocos2d-x実践講座 in 鹿児島
Cocos2d-x公開講座 in 鹿児島
cocos2d-xハンズオン勉強会 in 名古屋
Cocos2dx step2 アプリケーション基本
Cocos2d-x v3.2を利用してシューティングゲームを作ろう!
Cocos2d-x 3.0を使ったゲーム “消滅都市” の開発事例
Introduction for cocos2d
cocos2d-xにおけるBox2Dの利用方法および便利なツール
cocos2d-x公開講座 in 鹿児島
Cocos2dを使ったi phoneゲーム開発手法
Cocos2d xをさわってみよう!
Cocos2d/2d-x/html5 [Objective-C/C++/JavaScript] 好みの言語はどれですか?
Cocos2d-x勉強会 2014/10/05
cocos2d-xとCocosBuilderでゲームを作ってみよう
㉞cocos2d-xの開発環境をインストールしてみよう
㊱タイルマップに挑戦
cocos2dxことはじめ(2.2.5)
プログラム初心者がCocos2d xで ゲームを作った話
cocos2d-xとCocosBuilder
Ad

Cocos2d-xハンズオン#1 in 大阪

Editor's Notes

  • #3: コナミはAC機の開発で、キッズ向けや麻雀なんとか作ってた。 その前は、自称メディアアーティスト()してました。 ポノスではにゃんこ大戦争のセキュリティ強化や今からお話するガルズモンをやってました。 お菓子作りはプロラミングに通じるものがある… フットサルは部活です