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
スクリプト実行順