Nanashi-soft

Nanashi-softの活動状況とか雑談です。 Unity3Dでゲーム作っています。

○コライダ(当たり判定)を取り出す
TilePaletteを作成する際に,チップ画像ファイル毎にCollider Typeを設定しました
この値は,一旦TileやAnimatedTileにキャストして,それぞれ取り出す必要があります
        //コライダを取り出す
        if(mapchip[0] is Tile){
            Tile tile=(Tile)mapchip[20];
            if(tile.colliderType == Tile.ColliderType.None){
                Debug.Log("ColliderType.None");
           }else if(tile.colliderType == Tile.ColliderType.Sprite){
                 Debug.Log("ColliderType.Sprite");
            }else if(tile.colliderType == Tile.ColliderType.Grid){
                Debug.Log("ColliderType.Grid");
            }else{
                Debug.Log("Unknown:"+tile.colliderType);
            }
        }else if(mapchip[0] is AnimatedTile){
            AnimatedTile animatedtile=(AnimatedTile)mapchip[0];
            if(animatedtile.m_TileColliderType == Tile.ColliderType.None){
                Debug.Log("ColliderType.None");
            }else if(animatedtile.m_TileColliderType == Tile.ColliderType.Sprite){
                Debug.Log("ColliderType.Sprite");
            }else if(animatedtile.m_TileColliderType == Tile.ColliderType.Grid){
                Debug.Log("ColliderType.Grid");
            }else{
                Debug.Log("Unknown:"+animatedtile.m_TileColliderType);
            }
        }else{
            Debug.Log("Unknown object");
        }

○Tilemap上のコライダを取り出す
Tilemapに配置してあるチップ画像のコライダを取り出す方法です
取り出したい位置をGetTileして,TileBaseに設定してあるColliderTypeを取得する
        //Tilemap上に置いたチップ画像のコライダ取得
        TileBase tilebasechip=tilemap1.GetTile(new Vector3Int(0, 0, 0));
        //コライダを取り出す
        Tile.ColliderType collidertype;
        if(tilebasechip is Tile){
            collidertype=(tilebasechip as Tile).colliderType;
        }else if(tilebasechip is AnimatedTile){
            collidertype=(tilebasechip as AnimatedTile).m_TileColliderType;
        }else{
            //何もない場所なのでコライダも無し
            collidertype=Tile.ColliderType.None;
        }
        //コライダを判別する
        switch(collidertype){
        case Tile.ColliderType.None:
            Debug.Log("ColliderType.None");
            break;
        case Tile.ColliderType.Sprite:
            Debug.Log("ColliderType.Sprite");
            break;
        case Tile.ColliderType.Grid:
            Debug.Log("ColliderType.Grid");
            break;
        default:
            Debug.Log("Unknown:"+collidertype);
            break;
        }
GetTileした後は上と同じですので,コライダ状況の判別を統一するように書いてみました

このエントリーをはてなブックマークに追加

様々な操作をプログラムから行う方法を書いていきます

○Tilemap1にチップ画像を置く
まずはテスト的に,シーン上のTilemap1にチップ画像を置いてみます
        //シーン上のTilemapに並べる(テスト
        //tilemap1コンポーネントを取り出す
        Tilemap tilemap1=GameObject.Find("Tilemap1").GetComponent<Tilemap>();
        //SetTileでTileBaseを置く
        tilemap1.SetTile(new Vector3Int(0, 0, 0), mapchip[0]);

これを実行すると,画面中央にチップ画像が描画されます
描画されない場合は,Scene画面で画像が表示されているか? カメラ位置はそこになっているか? などをチェックする

○Tilemap2にチップ画像を置く
Tilemap2にも置いてみて,きちんと重なって表示されるかをテストする
        //tilemap2コンポーネントを取り出す
        Tilemap tilemap2=GameObject.Find("Tilemap2").GetComponent<Tilemap>();
        //SetTileでTileBaseを置く
        tilemap2.SetTile(new Vector3Int(0, 0, 0), mapchip[1]);

上下関係がおかしい場合は,TilemapのOrder in Layerが正しいかをチェックする
数値が大きいほうが上に来ます

○チップ画像を削除する
マニュアルを見たところRemoveTileなどは存在しません
ではどうするのか?を言うと,nullをSetTileします
        //TileBaseを削除する
        tilemap1.SetTile(new Vector3Int(0, 0, 0), null);

○Tilemapを初期化したい
全部削除するメソッドが用意されています
        //全部クリアする
        tilemap1.ClearAllTiles();

ただ,これだけだと表示されていないだけで描画領域は残ってしまっています
最適化を行います
        //最適化する
        tilemap1.CompressBounds();

○Tile Paletteを最適化したい
色々と操作を行っていると,余計なゴミ領域が残ってしまう場合があります
allPositionsWithinした際にそこも含まれていて,無駄な処理が増えます
それを最適化する方法です

Tile Paletteを開いて,HierarchyのRectangular Paletteの下のLayer1をクリック
Inspectorの『Tilemapの文字の上で』右クリック→Compress Tilemap Bounds

○チップ名で検索したい
.nameに入っています
        //マップチップ名で検索して,配列番号を返す
        string target="Scavengers_SpriteSheet_20"; //探したいチップ名
        int chipnum=-1;
        for(int i=0; i < mapchip.Length; i++){
            if(mapchip[i].name == target){
                chipnum=i;
                break;
            }
        }
        if(chipnum == -1){
            //その名前のチップは無かった
            Debug.Log("Not found target");
        }else{
            //見つけたチップ番号を表示
            Debug.Log("Found chip num:"+chipnum);
        }

これで返ってきた配列番号をSetTileすれば描画できます
        tilemap1.SetTile(new Vector3Int(0, 0, 0), mapchip[chipnum]);

○チップの種類を判別したい
Tile Paletteを作成した際に,1枚絵のスプライトであるTileと,複数枚を入れたAnimatedTileとがあった
このどちらかを判別するには,TileBaseからキャスト可能かを調べれば良いです
        //チップの種類を判定する
        if(mapchip[0] is Tile){
            Debug.Log("Is Tile");
            Tile tile=(Tile)mapchip[0];
        }else if(mapchip[0] is AnimatedTile){
            Debug.Log("Is AnimatedTile");
            AnimatedTile animatedtile=(AnimatedTile)mapchip[0];
        }else{
            Debug.Log("Unknown");
        }
キャスト可能なことをif文で確認しているので,そのままキャストしてそれぞれの固有の処理を行えます

○スプライト化して自由に動かしたい
SetTileだとグリッド単位でしか描画できません
スプライトオブジェクトにして,自由に動かせるようにします

UnityメニューのGameObject→2D Object→Sprites→Square
これにTileをセットする方法です
        //スプライトとして描画する
        //SpriteRendererコンポーネント上のSpriteにセットする
        GameObject spriteobj=GameObject.Find("Square");
        SpriteRenderer spriterenderer=spriteobj.GetComponent<SpriteRenderer>();
        //TileからSpriteを取り出してセットする
        Tile tile=(Tile)mapchip[0];
        spriterenderer.sprite=tile.sprite;

あとは普通のスプライトオブジェクトとして扱えばよいです
例えば,デフォルトのグリッドとは,XY方向に0.5ずれているので合わせる
        spriteobj.transform.position=new Vector3(0.5f, 0.5f, 0f);

このSpriteRendererコンポーネントの設定で,Additional SettingsのOrder Layerを2にするとTilemapよりも上に表示されます
ここの調整で上下関係を操作できます

このエントリーをはてなブックマークに追加

ここからはプログラミングです
何かを作るのでは無く。色々なことのやり方を書いていきます

○新しくシーンを作る
説明の整合性を取るために,新規シーンを作ります
ProjectのAssets以下で右クリック→Create→Scene
シーン名は何でも構いません

ダブルクリックしてシーンを開く
UnityメニューのGameObject→2D Object→Tilemap→Rectangular
するとGridとTilemapオブジェクトが追加されます
そのまま再度,UnityメニューのGameObject→2D Object→Tilemap→Rectangularして,Tilemapオブジェクトを2つする

Grid
|-Tilemap1
|-Tilemap2
Tilemapのnameの後ろに1,2をこのようにつけておく
Tilemap2の方のInspectorで,Tilemap Renderer→Additional Settings→Order Layerを1に設定する
この数値が大きいほうが上に表示されます

○C#ファイルを作る
ProjectのAssets以下の適当な場所で右クリック→Create→C# Script
testtilemapと付けておきます
ちなみに,生成時に付けた名前=クラス名ですので,設定しそこなったら削除して作り直してください。後で変更してはいけません

それをシーン上の適当な場所,例えばGridゲームオブジェクトにドラッグ&ドロップして設定する
説明では,Scriptの場所は関係ない書き方をします

○Tile Paletteをロード
最初にマップチップをセットしたタイルパレットをロードします

上の方に並んでいるusingに以下を追記
using UnityEngine.AddressableAssets; //Addressablesに必要
using UnityEngine.Tilemaps; //Tilemapに必要

Startメソッドでタイルパレットをロードする
    void Start()
    {
        //Tile Paletteをロード(ブロッキング
        GameObject tilepalette=Addressables.LoadAssetAsync<GameObject>("Assets/Rectangular Palette.prefab").WaitForCompletion();
        Debug.Log("tilepalette:"+tilepalette);
    }

正しくロードされると,Consoleに以下のようにタイルマップのオブジェクト名が表示されます
tilepalette:Rectangular Palette (UnityEngine.GameObject)
UnityEngine.Debug:Log (object)

何も表示されない時は,たぶんファイルパスが間違っています(拡張子忘れているなど
よくやるミスですので,Logの所は
        if(tilepalette == null){
            Debug.LogError("error!! tilepalette:");
        }
などと書いておいた方が,後々使い勝手がいいでしょう

○Tilemapを取り出す
タイルパレットの中に入っているTilemapを取り出します
プレハブになっており,以下の構造になっています
Rectangular Palette
|-Layer1
このLayer1オブジェクトのコンポーネントに,目標のTilemapが付いています

先ほどのプログラムの続きに記述する
        //Tilemapを取り出す
        GameObject layer1=tilepalette.transform.Find("Layer1").gameObject;
        Debug.Log("layer1:"+layer1);
        Tilemap tilemap=layer1.GetComponent<Tilemap>();
        Debug.Log("tilemap:"+tilemap);

実行するとConsoleに以下のように表示されます
layer1:Layer1 (UnityEngine.GameObject)
UnityEngine.Debug:Log (object)

tilemap:Layer1 (UnityEngine.Tilemap)
UnityEngine.Debug:Log (object)

○チップ(TileBase)を取り出す
俗にいう32x32画像などのチップ画像は,TileBaseクラスとして扱います
グローバル変数で256コ分を定義しておきます
    //チップ画像用グローバル変数
    TileBase[] mapchip=new TileBase[256];

ここからがややこしい話になるのですが,
Tilemap内に保存されているTileBaseの範囲を,tilemap.cellBounds.allPositionsWithinで取得できます
その範囲内を全て調べて,有効なTileBaseを取り出します
        //チップ画像を全て取り出す
        int counter=0;
        //tilemap.cellBounds.allPositionsWithinに全てのTileBaseの位置が入っている
        foreach(Vector3Int pos in tilemap.cellBounds.allPositionsWithin){
            //その位置のTileBaseをGetTileで取り出す
            TileBase tilebase=tilemap.GetTile(pos);
            if(tilebase != null){  //チップ画像が見つかったかを判定
                //チップ画像をグローバル変数に順番に入れる
                Debug.Log("chip:"+tilebase);
                mapchip[counter++]=tilebase;
            }
        }

これで,チップ画像を取り出せました

このエントリーをはてなブックマークに追加

●Addressablesの設定
Addressablesはリソース管理の仕組みです
SpriteAtlasファイルとTilePaletteファイルのみをここに入れます
※この記事を書いた検証時には,ビルド時にスプライトアトラス画像の元のテクスチャー画像が自動格納されているログがあったので要確認

○設定をする
UnityメニューのWindow→Asset Management→Addressables→GroupsでAddressables Groups画面を開く
Default Local Group (Default)を開くと,先ほどAddressableにチェックを入れたSpriteAtlasファイルとTilePaletteファイルの2つが入っていることが確認できます
mapchip12
Default Local Group (Default)をクリックした時のInspector設定
Advanced OptionsのAsset Bundle CompressionにLZ4を設定する
LZ4に設定することで,圧縮したファイルを解凍せずにそのまま読み込むことができます

○ビルドする
mapchip13
Addressables Groups画面の上のBuild→New Build→Default Build Script

生成されたファイルは,ゲームをBuildした際に自動的に組み込まれます
※別ファイルにしてネットダウンロード化など様々な機能がありますが,すごく長くなるのでここでは書きません

●シーン上のGrid→Tilemapを作成する
Scene画面のHierarchy画面を開いて(TilePaletteファイルをダブルクリックしていた場合はプレハブが開いているので閉じる
mapchip14
UnityメニューのGameObject→2D Object→Tilemap→Rectangular
シーン上にGrid→Tilemapが生成される
そのTilemapをクリックする

Tile Palette画面からチップ画像をドラッグ&ドロップで配置する事ができる
尚,この説明は自動生成なので何も置かないこと(置いてもクリアするから無意味

○レイヤー構造
Tilemapは重ねておくことができます
Gridオブジェクト上で右クリックして,2D Object→Tilemap→Rectangular
そうすると,Gridの下にTilemap_1が増えます
いくつでも追加することができます

Gridオブジェクト配下のTilemapが上から順に重ねて描画されます


これでプロジェクトの全設定が完了です

このエントリーをはてなブックマークに追加

●TilePaletteにマップチップを並べる
1枚絵のTileと,複数の絵を順番に表示するAnimatedTileを作成して,TilePaletteに並べます
ちょっと手順がややこしいのですが,Tile生成の都合上先にTilePaletteファイルを作成します

○TilePaletteファイル作成
Assetsフォルダ以下で右クリック→Create→2D→Tile Palette→Rectangular
出来たファイルをクリックして,Inspector設定
mapchip06

Addressable:チェックを入れる
他はデフォルトのまま触らないでください。説明と変わってくる可能性があります

UnityメニューのWindow→2D→Tile Palette画面を表示
とりあえず,Sceneと一緒の所に入れておくと良いです。そこにProjectからファイルをドロップして設定する事になります

○Tileファイル作成
mapchip07
Spritesフォルダの画像に▲マークがあるので,それをクリックすると分割されたスプライト画像群が表示されます
その中でアニメしない画像。例えば,Scavengers_SpriteSheet_18のビンとカンの画像を,先ほど開いたTile Paletteにドラッグ&ドロップして並べる
すると,.assetファイル保存ダイアログが開くので,任意の場所に保存する
それがTileファイルになります
mapchip08
InspectorのCollider Typeで,Noneなら衝突判定無し,Gridなら衝突判定有りです。グリッド上ではSprite状態はありませんのでどちらかに設定してください

ここでは,chipフォルダを作成して,そこにどんどん入れていきました

○AnimatedTileファイル作成
chipフォルダで右クリック→Create→2D→Tiles→Animated Tile
mapchip09
InspectorのNumber of Animated:にコマ数を入力する
Spritesフォルダの画像から,アニメする順番にスプライト画像をドラッグ&ドロップで設定していく

Minumum Speed:ランダムでこの間で開始する事で統一的な動きを防げる
Maximum Speed:
Start Time:アニメの開始時刻をずらす事ができる
Start Frame:アニメの開始コマをずらす事ができる
Collider Type:Noneなら衝突判定無し,Gridなら衝突判定有りです。グリッド上ではSprite状態はありませんのでどちらかに設定してください

作成したAnimatedTileファイルを,Tile Paletteにドラッグ&ドロップして並べる
既に保存されているものですので,保存ダイアログは表示されません

☆間違えて置いてしまったチップを削除したい場合
mapchip10
Tile Palette画面の上にあるEditを押す
→上のツールアイコンの一番左を押す
→削除したいチップをクリック
→InspectorのDelete Selectionボタンをクリックする
→Editを元に戻すと保存される

☆チップの場所を移動したい場合
mapchip11
Tile Palette画面の上にあるEditを押す
→上のツールアイコンの一番左を押す
→動かしたいチップをクリックして,一度放す
→上のツールアイコンの左から2番目を押す
→再度クリックしながらドラッグすると動かせる
→Editを元に戻すと保存される

このエントリーをはてなブックマークに追加

↑このページのトップヘ