Unity实现弹弓功能

写在前面

实现类似于愤怒的小鸟中的弹弓功能。

功能

  • 拖拽小鸟松开时发射
  • 拖拽范围的限制

实现

  1. 首先要用到Unity中的一个物理组件,Spring Joint 2D。它就是一个弹簧连接,就相当于两个物体间用弹簧连接一样。不管两个物体大于或者小于某固定的距离,都会产生相互作用的力。而且伴有弹性系数等。具体属性如下图(001):


    001.png
  2. 让物体跟随鼠标移动,因为鼠标是屏幕坐标系,需要转化为世界坐标系才能赋值使用。由于是2D场景,在转化后要修改下z轴,不然会看不到物体,代码如下:

transform.position = Camera.main.ScreenToWorldPoint(Input.mousePosition);
transform.position += new Vector3(0, 0, 10);
  1. 之后给拖拽限定一个范围,让物体在有效的范围内移动。对此,在弹弓上(Sprite图)上创建一个节点(CenterObject),计算出物体到节点的方向,在定义一个距离最大值。
if (Vector3.Distance(transform.position, CenterObject.position) > MaxDistance) {

                Vector3 pos1 = (transform.position - CenterObject.position).normalized;
                pos1 *= MaxDistance;
                transform.position = CenterObject.position + pos1;
            }

重点讨论

愤怒的小鸟的弹弓功能有一个小细节,就是拖拽物体碰到弓柄的时候不会透过弓柄,而是往上拉到发射口,这样显得更加真实,大致实现方法如下:
1 . 在会发生碰撞的地方设置碰撞体,设置IsTrigger为true。
2 . 添加监听事件

void OnTriggerEnter2D(Collider2D collider)
    {
        IsTrigger = true;
    }

 void OnTriggerExit2D(Collider2D collider)
    {
       IsTrigger = false;
    }

3 . 当触发碰撞体时,将拖拽最大距离缩小,将其拉到发射口。当离开碰撞体时,再将距离拉大。注意,以下代码中第一个if代码块,当物体运动到发射口时,且此时不再触发碰撞体,就不会缩短距离了,反之增加距离,这是受跟随鼠标的影响往下移动又触发碰撞体,产生了抖动的情况。要避开这种情况,就是当物体处于发射口时不要增加距离。

 void OnSetpOver()
    {

         if (Vector3.Distance(transform.position, ButtomObject.position) < 0.2)
            {
                IsAddDistance = false;
            }

            else
                IsAddDistance = true;

            if (IsTrigger) 
            {
                if (IsMove)
                    MaxDistance -= 0.1f;
            }
            else
            {
                if (IsMove && MaxDistance< 0.9f && IsAddDistance)
                {
                    MaxDistance += 0.1f;
                }
            }
    }

功能源码

文末有项目下载地址,结合项目更容易理解。

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

public class Brid : MonoBehaviour {

    //鼠标是否按下
    private bool IsClick;

    //是否触发了碰撞体
    private bool IsTrigger;

    //鼠标是否在移动
    private bool IsMove;

    //是否允许拉长距离
    private bool IsAddDistance;

    //能够拖拽小鸟的最长距离
    public float MaxDistance;

    //记录鼠标0.02s前的位置
    private Vector3 firstpos;

    //计时
    private float timer = 0f;

    
    private SpringJoint2D Sp;
    private Rigidbody2D rig2d;
    public CapsuleCollider2D TargetCollider;

    public LineRenderer right;
    public Transform Rightobject;
    public Transform ButtomObject;
    public Transform Target;
    public Transform CenterObject;

    public LineRenderer left;
    public Transform Leftobject;
     
    void Awake()
    { 
        Sp = GetComponent<SpringJoint2D> ();
        rig2d = GetComponent<Rigidbody2D> ();
    }

    void OnMouseDown()
    {
        IsClick = true;
        rig2d.isKinematic = true;
    }



    void OnMouseUp()
    {
        IsClick = false;
        rig2d.isKinematic = false;
        TargetCollider.enabled = false;
        Invoke("Fly", 0.1f);
         
    }

    void OnTriggerEnter2D(Collider2D collider)
    {
        IsTrigger = true;
    }

    void OnTriggerExit2D(Collider2D collider)
    {
        IsTrigger = false;
    }

    void FixedUpdate () 
    {
        if (IsClick)
        {
            transform.position = Camera.main.ScreenToWorldPoint(Input.mousePosition);
            transform.position += new Vector3(0, 0, 10);

            if (Vector3.Distance(transform.position, CenterObject.position) > MaxDistance) {

                Vector3 pos1 = (transform.position - CenterObject.position).normalized;
                pos1 *= MaxDistance;
                transform.position = CenterObject.position + pos1;
            }
            Line();
            OnSetpOver();
        }

        OnMouseMove();
    }

    void Fly()
    {
        Sp.enabled = false;
    }

    void Line()
    {
        right.SetPosition (0, Rightobject.position);
        right.SetPosition (1, transform.position);
        left.SetPosition (0, Leftobject.position);
        left.SetPosition (1, transform.position);
    }

    void Cancel()
    {
        
    }

    void OnMouseMove()
    {
        if (timer < 0.02f)
        {
            firstpos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
            timer += Time.fixedDeltaTime;

        }
        else
        {
            if (firstpos != Camera.main.ScreenToWorldPoint(Input.mousePosition))
            {
                IsMove = true;
            }
            else
                IsMove = false;
            timer = 0;
        }
    }

    void OnSetpOver()
    {
         if (Vector3.Distance(transform.position, ButtomObject.position) < 0.2)
            {
                IsAddDistance = false;
            }

            else
                IsAddDistance = true;

            if (IsTrigger) 
            {
                if (IsMove)
                    MaxDistance -= 0.1f;
            }
            else
            {
                if (IsMove && MaxDistance< 0.9f && IsAddDistance)
                {
                    MaxDistance += 0.1f;
                }
            }
    }
}

结语

以上代码实现的拖动看起来不是很顺畅,更真正的愤怒的小鸟比起来显得有些僵硬,如果读者有更好的解决方案请告诉我。

项目下载地址:

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • Unity3D塔防开发流程 配置环境及场景搭建 编程语言:C#,略懂些许设计模式,如果不了解设计模式,BUG Mo...
    Grape_葡萄阅读 3,011评论 1 3
  • 在我们的游戏开发过程中,有一个很重要的工作就是进行碰撞检测。例如在射击游戏中子弹是否击中敌人,在RPG游戏中是否捡...
    壹米玖坤阅读 24,628评论 0 17
  • 事件(event)的触发是PlayMaker交互设计的基础。 鼠标(mouse)、键盘(keyboard)、按钮(...
    shimmery阅读 13,930评论 0 23
  • 111. [动画系统]如何将其他类型的动画转换成关键帧动画? 动画->点缓存->关键帧 112. [动画]Unit...
    胤醚貔貅阅读 13,214评论 3 89
  • 曼殊菲儿2018.1.15坚持记录252天 冥想 意志力实验:5分钟训练大脑冥想 专心呼吸...
    曼殊斐儿_bcbb阅读 323评论 0 2