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

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

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


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上就可以了,代码只描述了功能,比较简陋,具体的优化自己去实现吧,少年!!




  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
实现Unity2D中鱼的集群运动,可以使用以下方法: 1. 定义鱼群的行为规则 - 定义鱼的移动速度、转向速度和视野范围等参数。 - 定义鱼之间的距离阈值,当鱼之间的距离小于阈值时,它们会采取一定的集群行为,如跟随、聚集等。 - 定义鱼的目标点,可以是固定的目标点或者是其他鱼的位置。 2. 更新鱼的位置和朝向 - 在每更新中,遍历所有鱼,计算其移动方向。 - 根据鱼群行为规则,确定鱼的下一个目标点或者移动方向。 - 根据移动方向更新鱼的位置和朝向。 下面是一个简单的示例代码,展示了如何实现鱼的集群运动: ```csharp using UnityEngine; public class Fish : MonoBehaviour { public float moveSpeed = 5f; // 移动速度 public float turnSpeed = 10f; // 转向速度 public float visionRange = 3f; // 视野范围 public float distanceThreshold = 2f; // 距离阈值 private Vector3 targetPoint; // 目标点 private void Start() { // 初始化目标点为当前位置 targetPoint = transform.position; } private void Update() { // 计算移动方向和距离 Vector3 moveDirection = targetPoint - transform.position; float distance = moveDirection.magnitude; // 判断是否到达目标点 if (distance < distanceThreshold) { // 生成新的目标点 targetPoint = GenerateTargetPoint(); } // 转向目标方向 Quaternion toRotation = Quaternion.LookRotation(Vector3.forward, moveDirection); transform.rotation = Quaternion.Lerp(transform.rotation, toRotation, turnSpeed * Time.deltaTime); // 移动到目标点 transform.position += transform.up * moveSpeed * Time.deltaTime; } private Vector3 GenerateTargetPoint() { // 生成一个随机的目标点 Vector3 randomPoint = Random.insideUnitCircle * visionRange; randomPoint.z = transform.position.z; // 返回目标点 return randomPoint; } } ``` 在这个示例代码中,我们首先定义了鱼的移动速度、转向速度、视野范围和距离阈值等参数。在Start()方法中,我们初始化目标点为鱼的当前位置。在Update()方法中,我们计算鱼与目标点的移动方向和距离,并根据距离判断是否到达目标点。如果到达目标点,则生成一个新的随机目标点。然后,我们通过插值方法(Lerp)将鱼的朝向逐渐调整到目标方向,然后沿着朝向向目标点移动。 将这个脚本附加到鱼的游戏对象上,并调整参数值来实现你想要的集群运动效果。在运行游戏时,鱼会根据设定的规则进行集群运动。你可以根据需要进行调整和优化,以实现更复杂的鱼群行为。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值