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;
                }
            }
    }
}

结语

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

项目下载地址:

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,383评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,522评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,852评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,621评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,741评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,929评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,076评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,803评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,265评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,582评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,716评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,395评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,039评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,798评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,027评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,488评论 2 361
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,612评论 2 350

推荐阅读更多精彩内容

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