Unity2D:简单自动瓷砖的实现

 unity2017虽然官方支持了瓷砖,但是总觉得不够好用,就自己写了个简单的自动瓷砖,效果如图。

思路是遍历特点范围的每个GameObjec,然后计算坐标,再通过坐标来处理瓷砖间的相对关系,顺便也会合并Collider2D来节省资源。

先看父类,主要处理变换坐标的工作:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class AutoTile : MonoBehaviour
{
	public float		sideLength;                             /* 图块边长 */
	public bool		isCoillder;                             /* 是否合并碰撞体 */
	public GameObject	startOne;                               /* 左下角的起始块,标定开始计算的位置 */
	List<ArrayList>		mapContainer = new List<ArrayList>();   /* 存储地图 */

	protected Transform[]	childrenTransforms;                     /* 存储子物体 */
	protected Vector2	basePoint;                              /* 从startone获取的起点 */

	/* 初始化起点 */
	protected void intinalBasePoint()
	{
		basePoint = startOne.transform.position;
		/* Debug.Log ("BasePoint=" + basePoint); */
	}


	/* 初始化存储块信息的变长数组 */
	protected void intinalMapContainer()
	{
		/* 获取子物体的数组 */
		childrenTransforms = GetComponentsInChildren<Transform> ( false );
		foreach ( Transform tra in childrenTransforms )
		{
			/* 利用tag判断是否纳入计算 */
			if ( tra.tag == "Tile" )
			{
				Vector2 pos = tra.position;
				int	x, y;
				x	= (int) ( (pos.x - basePoint.x) / sideLength + 0.05f); /* 加0.05防止误差 */
				y	= (int) ( (pos.y - basePoint.y) / sideLength + 0.05f);

				/* 判断是否延长主组 */
				while ( mapContainer.Count <= x )
				{
					mapContainer.Add( new ArrayList() );
				}

				/* 向列数组填充元素 */
				while ( mapContainer [x].Count <= y )
				{
					mapContainer [x].Add( 0 );
				}
				mapContainer [x][y] = 1;
			}
		}
		return;
	}


	/* 以下has***函数是用来判断的工具函数,在子类中用到 */
	protected bool hasUp( int x, int y )
	{
		if ( x < 0 || y < 0 )
			return(false);
		if ( !(mapContainer.Count > x) || mapContainer [x] == null )
			return(false);
		if ( mapContainer [x].Count == y + 1 )
			return(false);
		else
			return( ( (int) mapContainer [x] [y + 1]) == 1);
	}


	protected bool hasDown( int x, int y )
	{
		if ( x < 0 || y < 1 )
			return(false);
		if ( !(mapContainer.Count > x) || mapContainer [x] == null )
			return(false);
		return( (int) mapContainer [x] [y - 1] == 1);
	}


	protected bool hasLeft( int x, int y )
	{
		if ( x < 1 || y < 0 )
			return(false);
		if ( !(mapContainer.Count > x) )
			return(false);
		if ( mapContainer [x - 1] == null || mapContainer [x - 1].Count < y + 1 )
			return(false);
		return( (int) mapContainer [x - 1] [y] == 1);
	}


	protected bool hasRight( int x, int y )
	{
		if ( x < 0 || y < 0 )
			return(false);
		if ( !(mapContainer.Count > x + 1) )
			return(false);
		if ( mapContainer [x + 1] == null || mapContainer [x + 1].Count < y + 1 )
			return(false);
		return( (int) mapContainer [x + 1] [y] == 1);
	}


	protected bool hasLeftUp( int x, int y )
	{
		return(hasLeft( x, y + 1 ) );
	}


	protected bool hasRightUp( int x, int y )
	{
		return(hasRight( x, y + 1 ) );
	}


	protected bool hasLeftDown( int x, int y )
	{
		return(hasLeft( x, y - 1 ) );
	}


	protected bool hasRightDown( int x, int y )
	{
		return(hasRight( x, y - 1 ) );
	}


	/* 测试用 */
	protected void test()
	{
		foreach ( ArrayList arraylist in mapContainer )
		{
			string output = null;
			foreach ( var e in arraylist )
			{
				output += e;
			}
			Debug.Log( output );
		}
	}


	public virtual void updateAllTile()
	{
	}


	public virtual void updateAroundTile( int x, int y )
	{
	}
}

子类,用来更改Sprite与合并碰撞体,为什么要写子类呢?因为我觉得有拐角与没有的可以分开处理。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class AutoEdgeTiles : AutoTile
{
	/* 序列化不同的图片,也许有资源集之类更好的办法,还望大神能指点一二 */
	public Sprite SpriteMid, SpriteLeft, SpriteRight, SpriteUp, SpriteDown,
		      SpriteUpLeft, SpriteUpRight, SpriteDownLeft, SpriteDownRight, SpriteUpDown, SpriteLeftRight,
		      SpriteOnlyOne, SpriteOnlyLeft, SpriteOnlyRight, SpriteOnlyUp, SpriteOnlyDown;
	void Awake()
	{
		intinalBasePoint();
		updateAllTile();


		/*
		 * 测试用,testX,testY要声明
		 * test ();
		 * Debug.Log(hasLeftUp(testX, testY)+"\t"+hasUp (testX, testY)+"\t"+hasRightUp(testX, testY)+
		 * "\n"+hasLeft(testX, testY)+"\t\t"+hasRight(testX, testY)+
		 * "\n"+hasLeftDown(testX, testY)+"\t"+hasDown(testX, testY)+"\t"+hasRightDown(testX, testY));
		 */
	}


	override public void updateAllTile()
	{
		/* 父类中 */
		intinalMapContainer();
		/* 遍历每个tile */
		foreach ( Transform tra in childrenTransforms )
		{
			if ( tra.tag == "Tile" )
			{
				Vector2 pos = tra.position;
				int	x, y, code = 0;
				x	= (int) ( (pos.x - basePoint.x) / sideLength + 0.05f);
				y	= (int) ( (pos.y - basePoint.y) / sideLength + 0.05f);

				if ( isCoillder )
					changeCoillder2D( tra, x, y );
                                
                                /*一种类似二进制的判别法
                                 *顺序上左下右
                                */
				if ( hasUp( x, y ) )
					code += 1;
				if ( hasDown( x, y ) )
					code += 4;
				if ( hasLeft( x, y ) )
					code += 8;
				if ( hasRight( x, y ) )
					code += 2;
				tra.gameObject.GetComponent<SpriteRenderer> ().sprite = findSpriteWithCode( code, tra, x, y );
			}
		}
	}


	/* 在可破化地形情况下使用(没写) */
	override public void updateAroundTile( int x, int y )
	{
	}


	/* 改变角 */
	void changeConer( Transform tra, int x, int y )
	{
		if ( !hasLeftUp( x, y ) && hasLeft( x, y ) && hasUp( x, y ) )
			tra.Find( "conerLeftUp" ).gameObject.SetActive( true );
		if ( !hasRightUp( x, y ) && hasRight( x, y ) && hasUp( x, y ) )
			tra.Find( "conerRightUp" ).gameObject.SetActive( true );
		if ( !hasRightDown( x, y ) && hasRight( x, y ) && hasDown( x, y ) )
			tra.Find( "conerRightDown" ).gameObject.SetActive( true );
		if ( !hasLeftDown( x, y ) && hasLeft( x, y ) && hasDown( x, y ) )
			tra.Find( "conerLeftDown" ).gameObject.SetActive( true );
	}


	/* 假如是可碰撞体,就想办法合并Collider2D,节省性能并防止“抽搐”问题 */
	void changeCoillder2D( Transform tra, int x, int y )
	{
		if ( hasUp( x, y ) && hasDown( x, y ) && hasLeft( x, y ) && hasRight( x, y ) )
		{
			tra.GetComponent<BoxCollider2D> ().enabled = false;
			return;
		}else if ( hasLeft( x, y ) )
		{
			tra.GetComponent<BoxCollider2D> ().enabled = false;
			return;
		}else if ( !hasLeft( x, y ) )
		{
			BoxCollider2D	theBox	= tra.GetComponent<BoxCollider2D> ();
			int		count	= 1;
			while ( hasRight( x + count - 1, y ) )
			{
				count++;
			}
			theBox.size	= new Vector2( sideLength * count, sideLength );
			theBox.offset	= new Vector2( sideLength / 2.0f * (count - 1), 0 );
		}
		return;
	}


	Sprite findSpriteWithCode( int code, Transform tra, int x, int y )
	{
		switch ( code )
		{
		case 0:
			return(SpriteOnlyOne);
		case 1:
			return(SpriteOnlyUp);
		case 2:
			return(SpriteOnlyRight);
		case 3:
			changeConer( tra, x, y );
			return(SpriteDownLeft);
		case 4:
			return(SpriteOnlyDown);
		case 5:
			return(SpriteUpDown);
		case 6:
			changeConer( tra, x, y );
			return(SpriteUpLeft);
		case 7:
			changeConer( tra, x, y );
			return(SpriteLeft);
		case 8:
			return(SpriteOnlyLeft);
		case 9:
			changeConer( tra, x, y );
			return(SpriteDownRight);
		case 10:
			return(SpriteLeftRight);
		case 11:
			changeConer( tra, x, y );
			return(SpriteDown);
		case 12:
			changeConer( tra, x, y );
			return(SpriteUpRight);
		case 13:
			changeConer( tra, x, y );
			return(SpriteRight);
		case 14:
			changeConer( tra, x, y );
			return(SpriteUp);
		case 15:
			changeConer( tra, x, y );
			return(SpriteMid);
		default:
			changeConer( tra, x, y );
			return(SpriteMid);
		}
	}
}

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
下一篇