2014年12月26日金曜日

土台作りのゴール地点

土台作りのゴール地点をはっきりさせるメモ

2Dプラットフォーマーのゲーム作りは

・アクション(武器など攻撃手段含む)
・エネミー(ボス含む)
・レベルデザイン

をいじりまくることでできるはず。操作性をよくして個性的なエネミーの動きを設定して面白いレベルに適切に配置する。
その時に、例えばエネミーの挙動を設定してる時にプレイヤー操作部分のコードなんていじりたくない。レベルデザインは全部TiledMapEditorでやって、すぐUnityに反映させたい。フットワーク軽くして楽しくいじりたい。今はそのための土台作り。

各項目はできるだけ独立して操作したい。エネミーの挙動制御中にエネミー関連の別のコードをいじるのは我慢できるが、エネミーいじってたらマップにめり込んだからマップコリジョンを作り直すぞ!って展開は萎える。

各項目はできるだけテンプレートに沿って開発したい。エネミー1の挙動を作ったら同じようにエネミー2の挙動を作りたい。上下に移動する床と左右に移動する床の共通部分はサボりたい。

この2つを達成することを意識して土台を作ろう。現状のプレイヤーキャラとエネミーとバレットとアイテムが別のクラスで新しく構成されてるのは明らかにおかしい。そこらへんすっきりさせたい。

12/26配信メモ

マネージャー系のオブジェクトはスタティックにすべき?


135名無しさん sage :2014/12/26(金) 21:40:08
グローバルに使うゲームに必須なインスタンスは Main みたいな分かりやすいクラスの中にまとめておいて

static class Main {

public static GlobalKlassA globalA { get; }
public static GlobalKlassB globalB { get; }

}

とするやり方もある


141名無しさん sage :2014/12/26(金) 21:46:39
MVCはGUI作るためのデザパタだからな
SingletonとかFactoryはUnityとかでも必須



159名無しさん sage :2014/12/26(金) 22:41:05
アジャイルソフトウェア開発のトピックを勉強してください
エクストリーム・プログラミングの本もおすすめ
出てから10年経つが未だ色褪せない


リスナー様様やでほんま

http://warapuri.tumblr.com/post/28972633000/unity-50-tips
UnityTips

2014年12月20日土曜日

SpriteのSliceをスクリプトで行う

UnityのSprite EditorのSliceが勝手に気を利かせるのが困る。


透明部分をスプライトとして切り取らない。透明なスプライトをじゃぶじゃぶ作らないのは便利な反面、TMXファイル内のCSVとスプライトの番号がずれる。ちゃんと16枚に切り取ってほしい。そういう機能があってもいいと思うけど見つからなかったのでスクリプトで自作した。
    public Sprite[] GetTileSprite (string fileName)
    {
        // ピボットは中心
        Vector2 pivot = new Vector2 (0.5f, 0.5f);
        // ファイル名でテクスチャファイルを読み取る(1個しか読み取れない)
        Texture2D texture = Resources.Load<texture2d> (fileName);
        // 左上からTILESIZEで切り取っていく(16*16)
        // 合計何枚スプライトが得られるか
        int arraySize = (texture.height / Global.TILESIZE) * (texture.width / Global.TILESIZE);
        // 必要なだけ配列を確保
        Sprite[] sprites = new Sprite [arraySize];
        for (int y = 0; y < texture.height / Global.TILESIZE; y++)
        {
            for (int x = 0; x < texture.width / Global.TILESIZE; x++)
            {
                // スプライトの切り取る場所をRectで指定
                // 左下が(0,0)なことに注意
                Rect rect = new Rect (x * Global.TILESIZE, texture.height - (y + 1) * Global.TILESIZE, Global.TILESIZE, Global.TILESIZE);
                // 最後の引数はPixel Per Unit(たぶん)
                Sprite sprite = Sprite.Create (texture, rect, pivot, 1f);
                // 確保しておいた配列に代入
                sprites [y * texture.width / Global.TILESIZE + x] = sprite;
            }
        }
        return sprites;
    }

Resouces.Load (string)
Resourcesフォルダ内のファイルを読み込む。

Sprite.Create (texture2D, Rect, Vector2, float)
texture2Dの一部分を切り取ってスプライトを作る。
左下が(0,0)なのに注意。

スプライトの変更はSpriteRenderer.spriteを直接変更すればok。空オブジェクトを作成してスプライトを張り替えることでマップタイルをスクリプトで生成できる。

C#モードの中括弧の自動展開

うっとうしかったから消した
(defun csharp-insert-open-brace ()
  "Intelligently insert a pair of curly braces. This fn should be
bound to the open-curly brace, with

    (local-set-key (kbd \"{\") 'csharp-insert-open-brace)

{にcsharp-insert-open-braceがバインドされてるという仕組みらしい。
ので、バインドを外した
    (local-set-key (kbd "/") 'csharp-maybe-insert-codedoc)
;;    (local-set-key (kbd "{") 'csharp-insert-open-brace)


2014年12月19日金曜日

Collision

オブジェクト間の当たり判定とその際の処理の管理

旧1
// 各オブジェクトで処理
foreach (Transform child in rootObject.transform){
    Collider collider = child.GetComponent<Collider> ();
    if (collider.gameObject.tag == "Enemy"){
        HitCollider (collider);
    }
}

全てのオブジェクトをrootObjectの子として管理。
全てのオブジェクトは毎フレーム全オブジェクトを相手をチェックする。その際Tagを判定し、関係あるTagならコリジョンチェック。毎フレーム全オブジェクトが全オブジェクトをチェックするのでオブジェクト数が増えると大変なことになりそう。10発の弾丸があったら10^2=100回のチェックが毎フレーム起こる。


旧2
// ObjectManagerが処理
// 以下の空オブジェクトを子に持つ
// 各オブジェクトはタイプに応じて各空オブジェクトを親に持つ
public GameObject player;
public GameObject enemy;
public GameObject playerbullet;
public GameObject enemybullet;
public GameObject item;
public GameObject trigger;
public GameObject map;

//    ...

foreach (Transform mchild in player.transform){
    Collider mcollider = mchild.GetComponent<Collider> ();
    foreach (Transform echild in enemy.transform){
        Collider ecollider = echild.GetComponent<Collider> ();
        HitCollider (mcollider, ecollider);
    }
}

ObjectManagerが各オブジェクトの親オブジェクトを管理。旧1のrootObjectが複数になった形。チェック対象のオブジェクト群のみをチェック。
無関係なオブジェクトはそもそもチェックしないので処理削減。弾丸は敵としか判定が起きないので、弾丸10発と敵が2体なら10*2=20回のチェック。旧1では(10+2)^2=144回のチェック。


最新版

GetComponent ()は重いらしい。
毎フレームGetComponentを呼び出すのはまずそうなので、
1. オブジェクト生成時(Collider生成時)にGetComponent
2. 得られたColliderポインタをObjectManagerがListで保持
3. 旧2の処理をListを辿ることで実現

オブジェクト消滅時にListにnullポインタがごみとして残るへの対処は?

案1 デストラクタを利用
→Unityでは非推奨。
→C#はガベージコレクションがあるためデストラクタの動作タイミングが不定なため?

案2 Destroy時に一緒にリストから削除
→Destroyする側に任せるのは所在が散開してミスの元になりそう

案3 List辿ってnullポインタがあったらその場でListから消せば良くないか
→採用。
→ただし、foreach文中では消せないため、削除用のループを回す必要あり

ガベージコレクションのせいでオブジェクト消去のタイミングが分からない問題は未解決。
Destroy ()したタイミングでList内のポインタはnullになる?

2014年12月18日木曜日

12/18 配信メモ

http://ufcpp.net/study/csharp/oo_construct.html
クラスのデストラクタが呼ばれるタイミングはガベージコレクションのタイミング
オブジェクトを削除→デストラクタで関連する削除処理ってつもりで利用する時超注意

C#の機能で知るべきもの
・デリゲート
・匿名関数
・ラムダ式
あたり

リストからnullを削除
http://www.freeshow.net.cn/ja/questions/17e93fdb62e241c17e6b351c48f5a8f87cc9a693fba5fd3150b3d152b61ffa46/

オブジェクト管理についてメモ

http://www.atmarkit.co.jp/fdotnet/csharp_abc/index/index.html
C#勉強しよう

http://gamesonytablet.blogspot.jp/2012/12/unity_8031.html
Listについて

http://ameblo.jp/sugawara-monolizm/entry-11889665729.html
スクリプト実行順

2014年12月16日火曜日

12/16配信メモ

当たり判定処理のために毎フレームGetComponent()するのは重そう。
各オブジェクトのColliderクラスだけオブジェクト生成時にGetComponentしてリストで保持しておくのが賢そうだし、実装もそんなに難しそうじゃない。要検討。

52名無しさん sage :2014/12/16(火) 02:20:54
オブジェクト指向ガチでやるなら一旦関数型言語にも手を付けてみることをおすすめします

オブジェクト指向関連

http://d.hatena.ne.jp/ryoasai/20110317/1300380540
ドラゴンボール

http://codeiq.hatenablog.com/entry/2013/08/26/155959
完全に理解の届かない世界の話

http://www.oki-osk.jp/esc/go/class.html
参考

UML

http://www.itsenka.com/contents/development/uml/
分かりやすく

クラス設計なんて大層なもの必要ないかもしれないが、頭の中で考えてるのを図示すると考えると初心者にこそ必要なものだと思えてくる。勉強しよ

2014年12月14日日曜日

git-flow

git-flow最強説
http://lablog.lanche.jp/archives/635

・master
大体表に出す用
殆ど更新しなくていいと思う
直接コミットしない

・develop
これにマージしていく
ここから分岐していく
直接コミットしない

・feature
色々な作成工程に応じてブランチを作る
できたらdevelopへマージ

1人開発なら大体これですっきりするはず

リモートはdevelopマージの段階でpushしていこう

オブジェクトの接触時処理をどこに書くか?

プレイヤーが敵と接触した際の処理をどこに記述すればいいのか?

1.プレイヤーのスクリプトに書く
「プレイヤーが敵に接触したのでダメージを受ける」

2.敵のスクリプトに書く
「敵がプレイヤーに接触したのでダメージを与える」

3.オブジェクト管理スクリプトに書く
オブジェクトA(プレイヤー)がオブジェクトB(敵)に接触したのでそれに準ずる処理関数を実行する

4.それ以外の管理方法

1と2だとルールを厳密に決めておかないと関数の場所が分からなくなる。
1と2が混ざるとやばそうだが、例えば「すべて1の書き方」と決めるのも難しそう。「AはB、Cと接触した場合等しくダメージを受ける」という処理が、1の書き方に限定すると「BはAにダメージを与える、CはAにダメージを与える」となって、同じ処理を2箇所に書くことにならないか?

3は直感的に分かりにくい感じがするけど管理は楽そうである。
ただ、敵ごとに異なる処理が必要な場合(ダメージ量とか、クラッシュバンディクーみたいに死亡アニメが異なるとか)には処理を敵ごとに分ける必要がある


4はなんかあるか?


とりあえず3でやってみる。
プレイヤーが敵と接触時ダメージを受ける。敵によって量が異なる。という処理の場合、
・オブジェクト管理スクリプトが接触判定「プレイヤーが敵と接触」
・オブジェクト管理スクリプト内の「プレイヤー敵接触処理」が呼び出される
・敵の持つダメージパラメータを呼び出す
・プレイヤーの「被ダメ処理」関数を呼び出す

って感じになる。

バージョン管理開始

Gitでバージョン管理始めた。
クライアントはSourceTree。ちょっともっさりだけど使い勝手はいい。

http://naichilab.blogspot.jp/2014/01/gitsourcetreegit.html
とても分かりやすかった。

http://www.atmarkit.co.jp/ait/articles/1311/18/news017.html
参考

注意
http://qiita.com/varmil/items/2fb6ba6bd56c9eca5828
一番上の説明に書いてある.ignoreファイルだとシーン状況は保存されない?
ProjectSettigs/*.assetを除外した。
Hierarchy内の階層が重要なプロジェクトでは注意。
ソースコードを前のバージョンに戻すとオブジェクトの階層関係が壊れる(parentが変わる)可能性がある。

2014年12月10日水曜日

12/10配信メモ

・自作クラスColliderがUnityの既存クラスColliderを隠ぺいしちゃってる
どうしよう
警告がうっとうしい

http://qiita.com/2dgames_jp/items/495dc59c78930e284707
Instantiate()したオブジェクトの初期化方法
Instantiate()の戻り値のGameObjectからスクリプトを辿る

http://ft-lab.ne.jp/cgi-bin-unity/wiki.cgi?page=unity_script_change_hierarchy_gameobject
Instantiate()したオブジェクトのHierarchy内の位置を指定する
transform.parentをいじればok

2014年12月9日火曜日

12/9配信メモ

・ブレーキ時のアニメもほしい ← あんま気にならんかも
・アニメの長さは色変更(変えない)時間で調整したがまだ気になる
・当たり判定はステージとオブジェクトで別物にしてしまってもいいと思う
→動く床はオブジェクト扱いになると思う

2014年12月8日月曜日

16*16

ドット絵むずすぎわろた


絵から音楽から効果音までチープなのを自作するのも面白いかもしれん