您的位置:首页 > 移动开发 > Unity3D

unity 利用2d toolkit 实现按帧改变碰撞监测范围

2015-12-10 00:01 691 查看
自己在做动作类游戏的时候,碰到一个问题,在攻击的时候按帧播放,每一帧的攻击范围都是不同的,怎样才能实现每帧都能够检测图片对应的碰撞范围?

在网上找了很多资料,有好几种解决方案,其中包括射线检测等方法,虽然这些方法代码实现方便而且效率比较高,但是检测不够精确,而且局限性较大。

2d toolkit有很强大的功能,但是网上资料太少了,我也没找到这样的帖子来实现按帧改变碰撞监测范围。

创建一个Sprite With Animation,该物体包含Mesh Filter、Mesh Renderer、Mesh Collider、Tk 2d Sprite、Tk 2d Sprite Animator等组件。其中Mesh Collider是网格碰撞器,Tk 2d Sprite和Tk 2d Sprite Animator是2d toolkit的类,分别控制一个Clip(包含一定数量的图片)管理类和众多Clip组成的管理类。

控制一个动画的流程:

在Sprite Collection中为每帧图片绘制碰撞体积的后,然后添加到Sprite Animation中组成一个Clip,并在Tk 2d Sprite、Tk 2d Sprite Animator中选择它们。

用过2d toolkit的人应该都知道上面的流程,但是你会很奇怪在Inspector界面调节Tk 2d Sprite中的Sprite选项时Scene窗口的碰撞范围会改变,而在程序运行的时候并没有随着Sprite的切换而切换对应的碰撞范围,它只停留在初始Sprite的碰撞范围。

这个问题困扰了我很久,我也是刚接触unity,并不怎么搞。

今天我瞎搞,看了2d toolkit自带的类tk2dSprite、tk2BaseSprite、tk2dSpriteDefinition等这几类

tk2dSprite继承了tk2BaseSprite,并且包含了一组tk2dSpriteDefinition,tk2dSpriteDefinition相当于每一张的图片。

在tk2BaseSprite类中有个函数CreateCollider(),该函数实现了创建碰撞器,当其碰撞器类型为tk2dSpriteDefinition.ColliderType.Mesh,即网格的时候,则执行下面代码:

else if (sprite.colliderType == tk2dSpriteDefinition.ColliderType.Mesh && boxCollider == null)
{
// this should not be updated again (apart from scale changes in the editor, where we force regeneration of colliders)
if (meshCollider == null)
meshCollider = gameObject.AddComponent<MeshCollider>();
if (meshColliderMesh == null)
meshColliderMesh = new Mesh();

meshColliderMesh.Clear();

meshColliderPositions = new Vector3[sprite.colliderVertices.Length];
for (int i = 0; i < meshColliderPositions.Length; ++i)
meshColliderPositions[i] = new Vector3(sprite.colliderVertices[i].x * _scale.x, sprite.colliderVertices[i].y * _scale.y, sprite.colliderVertices[i].z * _scale.z);
meshColliderMesh.vertices = meshColliderPositions;

float s = _scale.x * _scale.y * _scale.z;

meshColliderMesh.triangles = (s >= 0.0f)?sprite.colliderIndicesFwd:sprite.colliderIndicesBack;
meshCollider.sharedMesh = meshColliderMesh;
meshCollider.convex = sprite.colliderConvex;
meshCollider.smoothSphereCollisions = sprite.colliderSmoothSphereCollisions;

// this is required so our mesh pivot is at the right point
if (rigidbody) rigidbody.centerOfMass = Vector3.zero;
}


对应的部分变量的定义

public MeshCollider meshCollider = null;
public Vector3[] meshColliderPositions = null;
public Mesh meshColliderMesh = null;
其中该代码利用tk2dSpriteDefinition(每一张图片一些定义)初始化构造了meshColliderMesh,即每一张图片的tk2dSpriteDefinition都能初始化相应的网格。

如果我们动态的对Sprite With Animation中的Mesh Collider中的shareMesh进行初始化进行覆盖,那不就可以实现播放哪张图片的时候使用它对应的碰撞范围了?

结果成功了。看下面代码:

using UnityEngine;
using System.Collections;

public class test : MonoBehaviour {
private tk2dSprite roleSprite;

// Use this for initialization
void Start ()
{
roleSprite = GetComponent<tk2dSprite>();
if (roleSprite == null)
Debug.Log("oh noo!");
}

// Update is called once per frame
void Update ()
{
{
Vector3[] meshColliderPositions = null;
Mesh meshColliderMesh = null;
if (meshColliderMesh == null)
meshColliderMesh = new Mesh();
meshColliderMesh.Clear();
meshColliderPositions = new Vector3[roleSprite.CurrentSprite.colliderVertices.Length];
for (int i = 0; i < meshColliderPositions.Length; ++i)
meshColliderPositions[i] = new Vector3(roleSprite.CurrentSprite.colliderVertices[i].x * roleSprite.scale.x, roleSprite.CurrentSprite.colliderVertices[i].y * roleSprite.scale.y, roleSprite.CurrentSprite.colliderVertices[i].z * roleSprite.scale.z);
meshColliderMesh.vertices = meshColliderPositions;
float s = roleSprite.scale.x * roleSprite.scale.y * roleSprite.scale.z;
meshColliderMesh.triangles = (s >= 0.0f) ? roleSprite.CurrentSprite.colliderIndicesFwd : roleSprite.CurrentSprite.colliderIndicesBack;
GetComponent<MeshCollider>().sharedMesh = meshColliderMesh;
}
}
}


以上简单的实现了这个功能,将它挂在对应的Sprite With Animation上就可以了,代码只描述了功能,比较简陋,具体的优化自己去实现吧,少年!!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: