マウスの動きに追従する2Dアイテムの遅延を一体化で実現

まず、効果図をレイアウトします

期待通りの効果が得られたかは分かりませんが、とにかく大満足です、画像では止まり方が分かりませんが、マウスの座標と一致していれば動きません。

実際、他の人の方法も試してみましたが、ほとんどの記事が同じで、3D用で、このように書かれています。

this.transform.LookAt(mousePosition);
this.transform.Translate(Vector3.forward * 1f * Time.deltaTime,Space.Self); 

Baidu にある方法を使うと 2D アイテムが反転してしまいますが、その原因はアイテムをマウスの方向に見せる LookAt 機能なのですが、Unity には 2D アイテムに対する LookAt 機能がないようです。関数をすべて書き直すのはまだ時間の無駄なので、できれば既製のものを使用してください。しかし、情報を探していたところ、別のより良い解決策を見つけました。これについては後で説明します。

次に、コードの実装について説明します。

最初は自分で作りましたが、ゲームオブジェクトの位置をマウスの位置に近づける実装ロジックを考えていましたが、Unityには既製の関数がなかったので、自分で書く必要がありました。

ゲームオブジェクトの位置をマウスの位置と一致させるだけなら比較的簡単ですが、書き始めるとかなりの困難に遭遇しました。

つまり、画面のマウス座標とゲーム内のオブジェクトの座標は座標軸が異なり、単位も異なるため、最初に実行すると画面の外に飛び出してしまいます。幸いなことに、常に一方向に飛行するわけではなく、ある一定の領域に飛んでからある点の周りを旋回し始めるという動作からこの問題を発見し、Baidu がこの問題を解決しました。

コードひとつで解決できる

mousePosition = Camera.main.ScreenToWorldPoint(Input.mousePosition);

このコードの意味は、マウス ベクトル 3 の画面座標をゲーム内の座標に変換することです。

次の難関は距離の計算で、これは中学生の知識ですが、それでも拾い直すのに10分以上かかります。

具体的な数学的原理は次のとおりです

 まず変数を宣言します。mouse はマウスの座標、item はゲームオブジェクトの座標、item は 2 次元座標軸の原点、L はマウスとアイテムの間の直線距離、X はマウスと X 座標軸の間の直線距離、Y はマウスと X 座標軸の間の距離、Y 座標軸の直線距離、l はアイテムが 1 フレームで移動できる距離です、x は からのアイテムの直線距離、アイテムの座標と l のサイズ、x と y のサイズを求めます。

さて、数学の問題として書くとこうなります、非常に長い問題ですが、難しくはありません。私の解決策は次のとおりです。

 X と Y は 2 つの座標によって求められ、相似な三角形の公式によって x と y を計算できます。

数学的な問題は解決されましたが、ゲームの作成はこれよりもはるかに複雑であることは誰もが知っています。実際、アイテム上のマウスの位置 (左上) を考慮する必要があります。右下?では、どうすれば解決できるでしょうか?

私のコードは次のとおりです:

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

public class player : MonoBehaviour
{
    [Header("变量")]
    public Collider2D playerCollider;
    public Vector3 mousePosition;
    public Vector3 emtpyVector2;
    public Vector3 emtpyPosition;
    public float totalLength;
    public float playerSpeed;

    // Start is called before the first frame update
    void Start()
    {
        playerCollider = GetComponent<Collider2D>();
    }

    // Update is called once per frame
    void Update()
    {
        Move();
    }

    void Move()
    {
        mousePosition = Camera.main.ScreenToWorldPoint(Input.mousePosition);
        emtpyPosition = playerCollider.gameObject.transform.position;
        totalLength = Mathf.Pow(Mathf.Pow(mousePosition.x - emtpyPosition.x,2) + Mathf.Pow(mousePosition.y - emtpyPosition.y,2), 0.5f);

        if (playerSpeed > totalLength)
            emtpyVector2 = Cal(totalLength, mousePosition.x - emtpyPosition.x, mousePosition.y - emtpyPosition.y, totalLength, emtpyVector2, mousePosition, emtpyPosition);
        else
            emtpyVector2 = Cal(playerSpeed, mousePosition.x - emtpyPosition.x, mousePosition.y - emtpyPosition.y, totalLength, emtpyVector2, mousePosition, emtpyPosition);

        if(mousePosition.x != emtpyPosition.x || mousePosition.y != emtpyPosition.y)
        {
            playerCollider.gameObject.transform.position = new Vector3(emtpyPosition.x + emtpyVector2.x, emtpyPosition.y + emtpyVector2.y, emtpyPosition.z);
        }
    }

    Vector2 Cal(float passLength, float x, float y, float totalLength, Vector2 vector2, Vector2 mousePosition, Vector2 playerPosition)
    {
        vector2.x = passLength / totalLength * x;
        vector2.y = passLength / totalLength * y;
        
        return vector2;
    }
}

私のコーディング基盤が貧弱であることは無視してください。変数間の関係を確認したいため、変数はすべて public として宣言されています。ここで、核心部分を抽出して見てみましょう。

void Move()
    {
        mousePosition = Camera.main.ScreenToWorldPoint(Input.mousePosition);
        emtpyPosition = playerCollider.gameObject.transform.position;
        totalLength = Mathf.Pow(Mathf.Pow(mousePosition.x - emtpyPosition.x,2) + Mathf.Pow(mousePosition.y - emtpyPosition.y,2), 0.5f);

        if (playerSpeed > totalLength)
            emtpyVector2 = Cal(totalLength, mousePosition.x - emtpyPosition.x, mousePosition.y - emtpyPosition.y, totalLength, emtpyVector2, mousePosition, emtpyPosition);
        else
            emtpyVector2 = Cal(playerSpeed, mousePosition.x - emtpyPosition.x, mousePosition.y - emtpyPosition.y, totalLength, emtpyVector2, mousePosition, emtpyPosition);

        if(mousePosition.x != emtpyPosition.x || mousePosition.y != emtpyPosition.y)
        {
            playerCollider.gameObject.transform.position = new Vector3(emtpyPosition.x + emtpyVector2.x, emtpyPosition.y + emtpyVector2.y, emtpyPosition.z);
        }
    }

    Vector2 Cal(float passLength, float x, float y, float totalLength, Vector2 vector2, Vector2 mousePosition, Vector2 playerPosition)
    {
        vector2.x = passLength / totalLength * x;
        vector2.y = passLength / totalLength * y;
        
        return vector2;
    }

マウスの座標の取得と変換方法は前述しましたが、直角三角形の両辺の二乗の和が斜辺の二乗に等しいという式で両者間の距離が計算されます。つまり、全長

Cal 関数では、x と y を計算する関数を実装し、vector2 を使用してこれら 2 つの値を返しました。

この計算関数を呼び出す場合は 2 つの状況があり、1 つは移動可能距離がアイテムとマウスの間の距離より小さい場合、つまり l<L の場合、移動可能距離は渡されます。の場合、最初のパラメータにアイテムの移動可能な距離である l を渡し、それ以外の場合は両者の間の距離である L を渡すと、アイテムの座標とマウスの座標が完全に一致して移動が停止します。数学的原理を改めて説明する必要はありませんね。

コードを書いているときに私が遭遇したもう 1 つの落とし穴は、x と y の正と負についてです。これには注意する必要があります。マウスが項目の左下隅にあり、x と y が両方とも正の数である場合、行きますね ネズミは反対方向に飛んでいきました、さようなら。

私の側では、totalLength は平方根以降の正の数であるため、passLength は正の数のみになり、入力される x と y の符号に依存するため、この問題は解決されます。

2 つ目は、アイテムの座標とマウスの座標が一致するかどうかを判断する方法です。transform.position を使用して直接比較することはできません。その時点ではゲームは実行されていましたが、バックグラウンドでエラーが報告され続けていました。座標が等しいという理由だけで、2 つは完全に等しいわけではありません。効果は変わりませんが、項目に null 値を割り当てようとするため、バックグラウンドでエラーが報告され続けます。その後変更してみたら解決しました。

これは愚かな方法ですが、決して他人に誤解を与えないという考えから、もう一度情報を確認し、より良い方法を見つけました。

Vector2.Lerp 関数は上記と同じ機能を実現できるので書き直しはしませんが、興味があればこのリンクにアクセスして公式ドキュメントの Vector2.Lerp 関数の説明を直接読んでください

学習に終わりはありません。説明する技術的な困難はすべて終わりました。Unity に関する関連テクノロジを共有するのはこれが初めてです。滅多に見に来ませんが、何か質問等ございましたらお気軽にメッセージをお願い致します。私と一緒にインディーゲームを作りたい方はぜひご連絡ください(売り込みを考えています)

おすすめ

転載: blog.csdn.net/weixin_49779414/article/details/122442439