Unity 钓鱼玩法的初步实现

效果

https://www.bilibili.com/video/BV13r4y1q7vE

实现思路

钓鱼的核心玩法是:

甩钩,等待鱼咬钩后,再给予鱼线适当的力度把鱼给拉上来。

鱼的拉力用随机值模拟。

人的拉力则用按键来控制。如果不增加拉力,人对鱼竿的拉力会随着时间减小至0。按下L键时,就会在原拉力的基础上再给鱼竿增加一定的拉力。

如果人与鱼的拉力受力平衡时,可以看作是合适的拉力。

在合适的拉力范围内,积累一定的时间,即可将鱼钓上来。

鱼竿脚本

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using DG.Tweening;

public class Fishing : MonoBehaviour
{
    /*--------------核心玩法----------------*/

    public float lineTension = 0.5f;
    public float deviation = 0.1f;              //偏差范围

    public float resultantForce = 0;            //合力

    public float fishForce = 0;
    public float fishingRodForce = 0;
    
    public float fishingRodForceDeclinePerSec = 0.15f;      //人的拉力每秒减少量

    public float targetAccumulationTime = 5f;               
    public float currentAccumulationTime = 0;
    public float accumulationRate = 0;                  //积累进度

    /*--------------UI----------------*/

    public GameObject canvas;
    public GameObject TensionPanel;
    public Image curTensionBar;         //力度条
    public Image acRateBar;             //时间条

    public Text status;         //状态提示文本

    public FishingStatus fishingStatus = FishingStatus.notAtFishing;
    public enum FishingStatus
    {
        wait,
        hit,
        caught,
        notAtFishing,
    }

    void Update()
    {
        AdjustLength();

        if (fishingStatus == FishingStatus.caught)
            MoveWithHook();

        if (fishingStatus == FishingStatus.hit)
        {
            AdjustTension();
        }
    }

    void AdjustTension()
    {
        fishForce = Mathf.Lerp(fishForce, Random.Range(0, 1f), 0.2f);

        float fishingRodForceIncrease = (Input.GetKeyDown(KeyCode.L) ? 1 : 0) * 0.05f;
        float fishingRodForceDecrease = fishingRodForce - fishingRodForceDeclinePerSec * Time.deltaTime >= 0 ? fishingRodForceDeclinePerSec * Time.deltaTime : 0;

        fishingRodForce = fishingRodForce + fishingRodForceIncrease - fishingRodForceDecrease;
        fishingRodForce = Mathf.Clamp(fishingRodForce, 0, 1f);

        resultantForce = fishingRodForce - fishForce;
        
        lineTension = resultantForce + 0.5f;
        lineTension = Mathf.Clamp(lineTension, 0, 1f);

        if (lineTension <= (0.5f + deviation) && lineTension >= (0.5f - deviation))
        {
            currentAccumulationTime += Time.deltaTime;
        }
        else
        {
            currentAccumulationTime -= Time.deltaTime;
        }
        currentAccumulationTime = Mathf.Clamp(currentAccumulationTime, 0, targetAccumulationTime);
        accumulationRate = currentAccumulationTime / targetAccumulationTime;

        curTensionBar.fillAmount = lineTension;
        acRateBar.fillAmount = accumulationRate;

        if(accumulationRate == 1)
        {
            OnCaught();
        }
    }

    void MoveWithHook()
    {
        if (fish)
            fish.transform.position = transform.position;
    }

    IEnumerator CloseFishingUI()        //延迟关闭UI
    {
        float timer = 0;

        while (true)
        {
            timer += Time.deltaTime;

            yield return null;

            if (timer > 5)
            {
                canvas.gameObject.SetActive(false);
                StopCoroutine("CloseFishingUI");
            }
        }
    }

    private GameObject fish;
    private void OnTriggerEnter(Collider other)             //将钩子作为触发器,则必须将该脚本挂在钩子上
    {
        if (other.gameObject.name == "fish")
        {
            fish = other.gameObject;
            if(fish.GetComponent<Fish>().hookStatus == Fish.HookStatus.focusOnHook)
                OnEatHook();
        }
    }

    public GameObject fishingLine;
    public float fishingLineLength = 1;
    void AdjustLength()
    {
        if(Input.GetMouseButton(0))
            fishingLineLength += Input.GetAxis("Mouse ScrollWheel");

        fishingLine.transform.localScale = new Vector3(fishingLine.transform.localScale.x,
                            fishingLine.transform.localScale.y, Mathf.Clamp(fishingLineLength, 1f,7f)); 
    }

    public void OnUnhook()
    {
        status.text = "鱼脱钩了";
        fishingStatus = FishingStatus.notAtFishing;
        TensionPanel.gameObject.SetActive(false);
        StartCoroutine("CloseFishingUI");
    }

    public void OnCaught()
    {
        status.text = "钓上来了";
        fishingStatus = FishingStatus.caught;
        fish.GetComponent<Fish>().hookStatus = Fish.HookStatus.caught;
        TensionPanel.gameObject.SetActive(false);
        StartCoroutine("CloseFishingUI");
    }

    public void OnEatHook()
    {
        status.text = "鱼吃钩了..";
        fishingStatus = FishingStatus.hit;
        canvas.gameObject.SetActive(true);
        TensionPanel.gameObject.SetActive(true);
    }

    public void OnSwingHook()
    {
        status.text = "静静等待";
        fishingStatus = FishingStatus.wait;
        canvas.gameObject.SetActive(true);
        TensionPanel.gameObject.SetActive(false);
        StartCoroutine("SwingHookAnimation");
    }

    public GameObject fishingRod;
    IEnumerator SwingHookAnimation()        //延迟甩钩动画
    {
        float timer = 0;
        while(true)
        {
            timer += Time.deltaTime;
            yield return null;
            if(timer >= 0.5f && timer <=1f)
            {
                fishingRod.transform.DOLocalRotate(new Vector3(-60,0,90),0.5f);
            }
            if (timer >= 1f && timer <= 1.5f)
            {
                fishingRod.transform.DOLocalRotate(new Vector3(0,0,90),0.5f);
            }
            if (timer > 1.5f)
                StopCoroutine("SwingHookAnimation");
        }
    }
}

鱼的脚本

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using DG.Tweening;

public class Fish : MonoBehaviour
{
    public GameObject hook;                 //鱼钩
    public float eatHookDistance = 10f;     //吃钩距离

    public HookStatus hookStatus = HookStatus.normal;
    public enum HookStatus
    {
        normal,
        focusOnHook,
        caught,
    }

    void Update()
    {
        if (Input.GetKeyDown(KeyCode.K) && (hook.GetComponent<Fishing>().fishingStatus == Fishing.FishingStatus.notAtFishing
                                         || hook.GetComponent<Fishing>().fishingStatus == Fishing.FishingStatus.wait))
        {
            hook.GetComponent<Fishing>().OnSwingHook();
            StartCoroutine("FindFood");
        }

        if(hookStatus == HookStatus.focusOnHook)
            ChaseHook();
    }

    IEnumerator FindFood()      //延迟吃钩
    {
        float timer = 0;

        while (true)
        {
            timer += Time.deltaTime;

            yield return null;

            if (timer > 10)
            {
                //注意到钩子
                hookStatus = HookStatus.focusOnHook;
                GetComponent<DOTweenPath>().DOPause();
                fish_y = transform.position.y;
                lastHookPosition = new Vector3(hook.transform.position.x, fish_y, hook.transform.position.z);
                StopCoroutine("FindFood");
            }
        }
    }

    public Vector3 lastHookPosition;
    private float fish_y;               //鱼受到浮力作用,纵坐标是时刻变化的
    void ChaseHook()            
    {
        //随意移动鱼钩位置,鱼跑了
        if (lastHookPosition != new Vector3(hook.transform.position.x, fish_y, hook.transform.position.z) && lastHookPosition != Vector3.zero)
        {
            hookStatus = HookStatus.normal;
            lastHookPosition = Vector3.zero;
            GetComponent<DOTweenPath>().DORestart();        //改变了位置之后不可继续播放,只能重新播放
            hook.GetComponent<Fishing>().OnUnhook();
            return;
        }

        if (Vector3.Distance(hook.transform.position, transform.position) < eatHookDistance)        //向钩子移动
        {
            if (Vector3.Distance(hook.transform.position, transform.position) > 0.5f)
                transform.position = Vector3.Lerp(transform.position, lastHookPosition,0.05f);
            transform.LookAt(hook.transform);
        }
    }
}

猜你喜欢

转载自blog.csdn.net/weixin_43673589/article/details/123622765