经典消除游戏——Unity 祖玛游戏

布局

祖玛游戏就不介绍了,此类游戏是关卡游戏。所以必须的先布关卡:

如图所示,必须先填充路径的点,游戏中的珠子就根据这个路径不断的向洞口靠近。


Unity 是个很好的工具,我们就使用它的编辑器功能,把球的位置给记录下来。原来是考虑用json或者xml文件记录的,后来发现LitJson对float是不支持的,但是支持double。如果使用Litjson,需要转换Vector3的时候相对麻烦。在Unity中我们考虑直接序列化,使用的是ScriptableObject。ScriptableObject是可以直接序列化成asset供unity使用,可以拖放到Inspector,可视化修改也比较方便。由此,用MenuItem调用的方式,选择场景中的Map开启记录。

[MenuItem ("Tools/Zuma/LevelConfig2Json", false, 1001)]
	public static void GameLevelLayout () {
		string assetPath = @"Assets/Resources/map.asset";

		if (Selection.activeGameObject == null) 
			throw new UnityException ("must select Map");

		Transform map = Selection.activeGameObject.transform;

		MapConfig info = AssetDatabase.LoadAssetAtPath (assetPath, typeof (MapConfig)) as MapConfig;
		bool isExist = (info != null); 

		if (info == null) {
			Debug.Log ("AssetDatabase not exist MapConfig");
			info = ScriptableObject.CreateInstance <MapConfig>() as MapConfig;			
		}

		info.MapInfo = new Vector3 [map.childCount];
		for (int i =0, L = map.childCount; i < L; ++i) {
			Transform t = map.GetChild (i);
			info.MapInfo [i] = t.localPosition;
		}
		
		if ( !isExist ) {
			AssetDatabase.CreateAsset (info, assetPath);
			return;
		}

		// 这里很重要,如果没有告诉unity已经被改变。它只写入内存,没有写入磁盘
		EditorUtility.SetDirty (info);
		AssetDatabase.SaveAssets();
	}

经过操作后,map.asset文件已经保存或更新了路径位置的信息。同样我们可以把其他的一些配置信息放到这里来。这个就是游戏的配置文件了。



游戏流程

 分析一下游戏的逻辑:首先左上角的洞口不断涌出珠子,点击(触摸过程调整方向,释放)发射珠子,打在队列中就与队列判断碰撞,插入队列并标记为搜索消除。如果符合规则,相连的类型数量大于等于3,消除珠子,分裂队列,播放音效与效果,此时,如果消除发生后在消除位置的后面一个与前面一个珠子的类型相同,后面的珠子需要带领它的队列段回缩,直到与前面珠子相连。游戏结束这里不作设置,如果珠子队列碰到青蛙的口,用一段时间让它整体回缩。

// Update is called once per frame
	void Update() {
		if (mgameState == GameState.runningTime) {
			// 消除球	
			CheckEliminate();
			// 检测球的碰撞插入
			CheckFireBallCross();
			// 有回缩趋势的球的检测
			CheckFallBackBall ();
			// 第一个球的推进
			if (mAttackState == 1) {
				CheckFirstSegmentAttack();
				// 检测失败点
				CheckGameFailurePoint();
			}
			// 当达到终点时队列回缩
			if (mAttackState == -1) {
				CheckLastSegmentAttack();
			}			
			// 判断队列的连接	
			CheckSnakeConnect();			
		}

		// 更新球的Tick
		UpdateAllBallTick ();
		// 更新球的渲染
		UpdateBallRender();
	}

游戏分析

推力

这个游戏中,在路径中的珠子我们首先以段为单位,每段由n颗珠子串连组成。如图: 


 当mAttackState==1时,队列向右移动。洞口第一颗珠子有推力。看图,当它推向右边就会与右边的珠子相交,右边的珠子必须向右推动,直到第一段全部推动。此时需要注意,这种情况下需要处理推到终点的情况。

	// 第一段推进
	void CheckFirstSegmentAttack() {

		//游戏中一段珠子都没有,先初始一段
		if (mSnakeSegment.Count == 0) {
			Ball b = CreateActiveBall();
			mSnakeSegment.Add(b);
			return;
		}

		//如果第一段中第一个珠子已经出了出口,补充新的珠子在洞口
		Ball ptr = mSnakeSegment[0];
		if (ptr.IsNotHoleExit()) {
			Ball b = CreateActiveBall();
			b.processIndex = ptr.processIndex - 1f;
			b.SetNext(ptr);
			ptr.SetPre(b);

			mSnakeSegment[0] = b;
			ptr = b;
		}

		//在出洞口第一颗珠子推动
		ptr.processIndex += Time.deltaTime * mAttackSpeed;

		//所有的右边的珠子都要调整
		while (ptr.Next != null) {
			if (ptr.Next.processIndex < ptr.processIndex + 1) {
				ptr.Next.processIndex = ptr.processIndex + 1;
			}

			ptr = ptr.Next;
		}
	}

当mAttackState == -1这是最后一段的最后一个珠子往左边推,这种情况下需要处理最左边的珠子会缩回出洞口的情况。

队列的连接

 
 前面一段珠子往右推,就会出现两段相交,此时就应该合并。
void CheckSnakeConnect() {
		//应该先排序下
		//mSnakeSegment.Sort (SortCompare);
		int i = mSnakeSegment.Count;
		while (i-- > 1) {
			Ball q = mSnakeSegment[i];
			Ball p = mSnakeSegment[i - 1];
			Ball t = p.Tail;

			//前一段的尾巴碰到了后一段的头
			if (t.processIndex + 1 >= q.processIndex) {
				q.processIndex = t.processIndex + 1;
				UpdateBallAndBallDistance(q);
				t.SetNext(q);
				q.SetPre(t);
				mSnakeSegment.RemoveAt(i);
			}
		}
	}

珠子的插入


 当发射的珠子碰撞队列时,是先插入队列。约定都是往右边插入

珠子的消除

 

以珠子为起点,在队列中左右搜索相同类型的珠子,如果相同类型的珠子数量大于等于3,便消除掉这一块珠子。消除后会产生三种情况:这段珠子为null,依旧剩下一段珠子,分裂成两段珠子。
消除后,如果两边的珠子的类型一样的还需要后面的段回缩拼接



工程分享: http://download.csdn.net/detail/wuzhi3078/9553990

  • 3
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值