5
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Unity2Dのスプライトの描画順をLINQで正規化する

Last updated at Posted at 2014-12-24

#必要性

今カードゲームっぽいものを作っているのですが、Unity2DのSpriteは描画順をレイヤー(Sorting Layer)で管理しつつ、同じレイヤー内ではOrder in Layerの小さい順に描画するのは御存知の通り。
無題.png

で、カードゲームや、Windowsのウインドウのように、選択したものを一番上に持ってくる操作(レイズ操作)をするにはどうするか。

それは簡単で、Order in Layerの値に1万とか2万とか足しちゃえばとりあえず、一番上に来るはず(よっぽど多かったり、変な数値入れてない限り)

ちなみにInspectorだとOrder in Layerですが、スクリプト上ではRendererのメンバのsortingOrderです。

コードにするとこんな感じ(もちろん、SpriteRendererは最初に取っておいた方がいいけれど)

	public void Raise(int num) {
		var spr = GetComponent<SpriteRenderer>();
		spr.sortingOrder += num;
	}

#これでいいのか
でもこの方法にはもちろん問題があって、元もとsortingOrderが10のオブジェクトをRaise(1000); で1010にしたらとりあえず一番上に来たとして、別のsortingOrderが5とかのオブジェクトを同じくRaise(1000);しても、1005なので一番上には来ない!どうしよう!

#やっと本題
というわけで、sortingOrderの正規化が必要なのです。
と、正規化などと難しく言いましたが、順番はそのままに数字を振り直すだけです。
BASICでいうとRENUM命令って事です(どれくらいの人がピンとくるのか)

#LINQを無理に使うよ!

  1. 指定したsortingLayerIDを持つSpriteRendererを
  2. sortingOrderの値でソートしてから
  3. 番号を振り直す

は普通に書くとそこそこ長いです!
それがLINQなら

  1. 指定したsortingLayerIDを持つSpriteRendererを → Where
  2. sortingOrderの値でソートしてから → OrderBy
  3. 番号を振り直す

となるので、

	public void SortOrderNomalize(int targetLayer)
	{
		int cnt = 0;
		foreach (var card in FindObjectsOfType<SpriteRenderer>().Where(sr => sr.sortingLayerID == targetLayer).OrderBy(c => c.sortingOrder))
		{
			card.sortingOrder = cnt++;
		}
	}

で! 短い!すごいね!

一応コレだけで指定したレイヤーのsortingOrderを0から振り直してくれます。

ちなみに、ただ行数を減らすという方針ならforeachをArray.ForEach使うって手もありますが、Array.ForEachは配列限定なのでToArray()を走らせる必要があるのでメモリ的に不利っぽい気がします。

一応書くと

	public void SortOrderNomalize2(int targetLayer)
	{
		int cnt = 0;
		Array.ForEach(FindObjectsOfType<SpriteRenderer>().Where(sr => sr.sortingLayerID == targetLayer).OrderBy(c => c.sortingOrder).ToArray(),spr=>spr.sortingOrder = cnt++);
	}

です。 まぁ、短ければ良いってもんじゃないよね。

#閑話休題

これを、先ほどのRaiseメソッドと併せて

	public void Raise(int num) {
		var spr = GetComponent<SpriteRenderer>();
		spr.sortingOrder += num;
		SortOrderNormalize(spr.sortingLayerID);//sortingOrder振り直し
	}

とやってあげればいいんではないでしょうかー。

#もちろん
FindObjectsOfTypeとか決して軽い処理では無いので途中で増減しない限りはStartとかで確保しておくことをおすすめします。

#これだけやっておいて
実はsortingOrderの振り直しがすでにUnityによって用意されてたりします? さらっと探した感じは無かったんですが。

もしあるなら教えてください。 恥ずかしいので記事消しますから。

5
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?