< コードレビュー > 反省・改善点

コードレビューを受けての反省・改善点のまとめ

コメントアウトについて

// コメントアウト

通常コメントアウトは上記のように行うと思いますが、
文字形式によっては上記のように行うと
正しくコメントアウトだと認識してもらえないことがあります。

UTF-8の場合、文字バイトが以下のようになっています。
1Byte : 1~9 , A~Z etc...
2Byte : 漢字 etc...
3Byte : "能" etc...

1.2Byteは問題ありませんが、3Byte文字の場合問題が発生する可能性があります。
この問題を解決・未然に防ぐ方法が、コメントアウトの最後に " . "を付けるということです。

// コメントアウト.

基本的にはあまり起きることはないかと思いますが、癖づけておくにこしたことはないと思います。

・コメントを書く場所について

コメントを書くのはなぜかというと、
・時間がたってからコードを見たときに素早く解釈できるようにするため。
・ほかの人が見たときに理解しやすいように。
が基本にあると思います。

だからといって、以下のようなコメントの付け方はあまりよろしくないです。

// データ格納変数
int data = 0;

// データを格納
if(data == 0)
{
 data = getData();
}

基本的に見ればわかるようなところにはコメントは書かない。
if文やfor文などになぜこのようにするのかと書くのが良い。

・変数/関数名について

所謂、命名規則というものです。

プロジェクトによっていろいろ決まっていると思いますので
その形に合わせて作るのが一般的です。

・関数の粒度について

関数を作成し処理を作っていくうちに、関数の中身が多機能化してしまう。
そして関数の粒度がばらばらになってしまい結果的に汚いソースコードになってしまいます。

基本的には、関数一つにつき処理は一つ。
ソースコードの長さとしては70ラインが目安です。

関数の中で処理を複数行う場合は、一つ一つを関数にし
関数内でif文・for文などを極力使わない。

これにより、コードがきれいになります。

・PublicとPrivateについて

オブジェクト指向としては関数内部で呼ぶものはPrivate、外から呼ぶものはPublic。

Publicの関数からPublicの関数を呼ぶというのは基本的にはおかしく
その場合は呼ぶ関数はPrivateのほうが正しい。

外部からも内部からも同一の関数呼ぶ場合は
関数をPrivateにし、外から呼ぶときにはPublicにその関数を呼ぶ関数を用意するというのが正しいことがある。

< Cocos2d-x > カードをめくるようなアニメーション

Cocos2d-x バージョン:3.8.1


まずはどのようなものかご覧ください。


https://youtu.be/TgCKhkd9Oy0youtu.be


このような動きを行うために使用したのがActionと呼ばれるものです。

Actionを組み合わせることによりいかにもカードをめくっているかのように見せています。


組み合わせるときに使うのが以下のものになります。


Sequence
 …順番にActionを実行していく


Spawn
 …同時に複数Actionを実行していく


ソースコードは以下の通りです。

--- Trump.h ---

#ifndef __TRUMP_SCENE_H__
#define __TRUMP_SCENE_H__

#include "cocos2d.h"
#include <random>

// トランプクラス
class Trump : public cocos2d::Layer
{
public:
	enum
	{
		BACK,
		SELECT,
		RESULT,
	};


	CREATE_FUNC(Trump);
	static cocos2d::Scene* createScene();
	virtual bool init();

	bool onTouchBegan(cocos2d::Touch* pTouch, cocos2d::Event* pEvent);
	void onTouchEnded(cocos2d::Touch* pTouch, cocos2d::Event* pEvent);

	void openTrump(int tag);
};

#endif // __TRUMP_SCENE_H__

--- Trump.cpp ---


#include "Trump.h"

// cocos2d を省略
USING_NS_CC;

static const int MAX_TRUMP = 3;
static const int TRUMP_SIZE = 250;

// クリエイトメソッド
Scene* Trump::createScene()
{
	auto scene = Scene::create();
	auto layer = Trump::create();
	scene->addChild(layer);

	return scene;
}

// 初期化メソッド
bool Trump::init()
{
	if (!Layer::init())
	{
		return false;
	}

	// サイズの取得
	auto size = Director::getInstance()->getVisibleSize();

	// タッチリスナー(シングルタッチ)
	auto touchListener = EventListenerTouchOneByOne::create();
	touchListener->onTouchBegan = CC_CALLBACK_2(Trump::onTouchBegan, this);
	touchListener->onTouchEnded = CC_CALLBACK_2(Trump::onTouchEnded, this);
	this->getEventDispatcher()->addEventListenerWithSceneGraphPriority(touchListener, this);

	// トランプを配置
	// 裏面のトランプを3枚配置します
	for (int i = 0; i < MAX_TRUMP; i++)
	{
		auto sprite = Sprite::create("Trump_Back.png");
		sprite->setPosition(Point(size.width / 2 - TRUMP_SIZE * (i - 1), size.height / 2));
		sprite->setTag(i);
		this->addChild(sprite,Trump::BACK);
	}

	// ボタン
	auto button = MenuItemImage::create("CloseNormal.png",
					    "CloseSelected.png",
					    [this](Ref* ref){				
					    Director::getInstance()->replaceScene(Trump::createScene());
	});

	button->setPosition(Point(size.width - button->getContentSize().width, button->getContentSize().height));

	auto menu = Menu::create(button, NULL);
	menu->setPosition(Point::ZERO);
	this->addChild(menu);

	return true;
}

void Trump::openTrump(int tag)
{
	// 選択された画像の取得
	auto selectTrump = this->getChildByTag(tag);
	this->reorderChild(selectTrump, Trump::SELECT);

	// 移動先の位置
	auto destPos = Director::getInstance()->getVisibleSize() / 2;

	// 表面に表示する画像を乱数で決める
	std::random_device device;
	std::mt19937 mt(device());
	std::uniform_int_distribution<int> dice(1, 3);

	std::stringstream fileName;
	fileName << "Trump_" << dice(mt) << ".png";

	log("%s", fileName.str().c_str());

        // 表面に表示される画像を作成
	auto resultTrump = Sprite::create(fileName.str().c_str());
	resultTrump->setPosition(destPos);
	resultTrump->setScale(1.5f);
        // 180度回転しているように見せるために角度を設定
	resultTrump->setRotationSkewY(-90.0f);
	this->addChild(resultTrump,Trump::RESULT);

	//
	// アニメーション
	//

	// 1 - 選択したトランプを中央に移動・拡大
	auto anim_Move = CallFunc::create([=]{
		auto move = MoveTo::create(0.6f, Vec3(destPos.width, destPos.height, 0.0f));
		auto scale = ScaleTo::create(0.6f, 1.5f);
		auto action = Spawn::create(move, scale ,NULL);
		selectTrump->runAction(action);
	});

	// 2 - 1と同時に選択外のトランプをフェードアウト・非表示
	auto anim_FadeOut = CallFunc::create([=]{
		for (int i = 0; i < MAX_TRUMP; i++)
		{
			// 選択トランプは除外
			if (i == tag)	continue;
			auto trump = this->getChildByTag(i);
			auto fadeOut = FadeOut::create(0.6f);
			auto visible = CallFunc::create([=]{
				trump->setVisible(false);
			});
			auto action = Sequence::create(fadeOut, visible, NULL);
			trump->runAction(action);
		}
	});

	// 3 - ディレイ
	auto delay = DelayTime::create(0.5f);

	// 4 - 選択したトランプを回転(90度)
	auto anim_Rota1 = CallFunc::create([=]{
		auto rota = RotateTo::create(0.3f, 0.0f,90.0f);
		selectTrump->runAction(rota);
	});

	// 5 - 表示するトランプを回転
	auto anim_Rota2 = CallFunc::create([=]{
		auto delay = DelayTime::create(0.3f);
		auto rota = RotateBy::create(0.3f, 0.0f, 90.0f);
		auto action = Sequence::create(delay, rota, NULL);
		resultTrump->runAction(action);
	});

	this->runAction(Sequence::create(anim_Move, anim_FadeOut, delay, anim_Rota1, anim_Rota2, NULL));
}


bool Trump::onTouchBegan(Touch* pTouch, Event* pEvent)
{
	return true;
}

void Trump::onTouchEnded(Touch* pTouch, Event* pEvent)
{
	// タッチ座標の取得
	auto touchPos = pTouch->getLocation();

	// シーンの取得
	// 0にはcocos2d::Cameraが入っているためシーンの取得時は1
	auto scene = Director::getInstance()->getRunningScene()->getChildren().at(1);
	for (int i = 0; i < MAX_TRUMP; i++)
	{
		auto sprite = scene->getChildByTag(i);

                // 表示していない場合はcontinue
		if (sprite->isVisible() != true) continue;

		if (sprite->getBoundingBox().containsPoint(touchPos))
		{
			// タッチした画像があったとき
			openTrump(i);
			break;
		}
	}
}


使用した画像名
Trump_Back.png
Trump_1.png
Trump_2.png
Trump_3.png

< Unity >LineRendererについて

Unity バージョン : 5.3.2


まず、Unityには線を描く機能が2つほどあります。

一つがオブジェクトの移動軌跡を描くTrailRenderer。

もう一つが今回のお話のLineRenderer。

後者のLineRendererは軌跡ではなく任意の座標を指定し線を描くものになります。

▼始点が(0.0f,0.0f,0.0f) 終点が(3.0f,3.0f,0.0f)
f:id:MTIMSNO:20160608222152j:plain

上の画像は、始点・終点の2点でしたが
これを3点にすると…

f:id:MTIMSNO:20160608222249j:plain

このような感じで始点から2点目にかけてが細くなってしまいます。
ゲームを作っている際にこの仕様?に出会ってしまいめちゃくちゃ悩みました。

色々調べてみた結果、折れ曲がった線を引きたい場合は
LineRendererを2つ使うというのが解決策らしいです。

実際LineRendererを2つ使うと下のようになります。
f:id:MTIMSNO:20160608222319j:plain

ソースコードは以下の通りです。

void Start() {

 // Line1
 CreateLine(Vector3.zero, new Vector3(3.0f,3.0f,0.0f));

 // Line2
 CreateLine(new Vector3(3.0f,3.0f,0.0f), new Vector3(3.0f,-3.0f,0.0f));

}

/// <summary>
/// ライン作成関数
/// </summary>
/// <param name="start">始点</param>
/// <param name="end">終点</param>
private void CreateLine(Vector3 start,Vector3 end)
{

 // オブジェクトの作成
 GameObject newObj = new GameObject();
 // 親子関係設定
 newObj.transform.parent = transform;
 // ラインの作成
 LineRenderer newLine = new LineRenderer();

 // --- 重要 --- //
 newLine = newObj.AddComponent<LineRenderer>();
 // --- 重要 --- //

 // ラインの色
 newLine.SetColors(Color.red,Color.red);
 // ラインの幅
 newLine.SetWidth(0.25f,0.25f);
 // ラインの頂点数?
 newLine.SetVertexCount(2);
 // 始点の設定
 newLine.SetPosition(0, start);
 // 終点の設定
 newLine.SetPosition(1, end);

}

このような方法で曲がっても一定の太さのラインを描くことが出来ます。

ラインとラインのつなぎ目が気になりますが
細くなるよりはマシかと思います。

上記の方法だと、ラインが手前側に表示されない場合がありますので
以下の二つの方法をお試しください。

1・レイヤーの指定

newLine.sortingLayerName = "Line";

のように新しくレイヤーを追加してあげる。

2・z座標の指定
ラインの始点・終点位置のz座標をカメラ側に近づけてあげる。

< Unity >透過処理した画像について

Unity バージョン : 5.3.2

 

Unityに透過処理をした画像を追加すると、下のような画像になります。

 

f:id:MTIMSNO:20160608221058j:plain

 

この画像をオブジェクトに追加すると黒い部分まで表示されてしまいます。

せっかく透過処理を施したのに黒くなってしまっては意味がありません。

そこで、オブジェクトに追加した際に作られるMaterialのShaderを変えることで

透過処理が施された画像にすることが出来ます。

 

Shader → Unlit → Transparent

この手順でShaderを変更することによりオブジェクトが透過されます。

▼Shaderが初期状態のとき

f:id:MTIMSNO:20160608221155j:plain

 

▼ShaderがUnlit/Transparentのとき

f:id:MTIMSNO:20160608221310j:plain

 

普通に透過処理をした画像が使いたいだけならこれでもいいかもしれません。

しかし、この状態でスクリプト上からオブジェクト自身の透過処理を行っても

”A”という文字はこのままで一切透過されません。

そこでShaderを変えることによって

「 オブジェクトの透過 + "A"という文字の透過 」

もできるようになります。

 

Shader → Legacy Shaders → Transparent → Diffuse

この手順を行ったうえでスクリプト上からオブジェクトの透過度を変えると

”A”という文字まで透過してくれます。

▼上記の方法でShader変更後にスクリプトでオブジェクトを透過。

f:id:MTIMSNO:20160608221506j:plain

 

このような感じでShaderを変えることにより透過処理が可能になります。