2

我正在尝试从任何泡泡射击游戏中复制射击游戏。气泡将跟随的虚线。

我想要做的是,创建一条虚线,当接近相机限制时反弹(反射)(相机的限制是图像的限制)。此外,当被泡泡(蓝点)击中时停止创建更多点。

这条线到目前为止反弹,但不正确(见角落)。此外,当被泡泡(蓝点)击中时它不会停止。

private void DrawPoints() {
        bool hasReversed = false;
        bool reversedLeft = false;

        var leftEdge = mainCamera.ScreenToWorldPoint(new Vector3(0, 0, 0));
        var rightEdge = mainCamera.ScreenToWorldPoint(new Vector3(Screen.width, 0, 0));
        var normalDir = shootDir.normalized;

        int count = 0;

        for (var i = 0; i < dots.Count; i++) {
            var dot = dots[i];
            dot.GetComponent<SpriteRenderer>().color = color;

            var newPos = new Vector2(normalDir.x, normalDir.y) * i * DotGap;
            if (hasReversed) {
                newPos.x += reversedLeft ? (-rightEdge.x + Constants.BubbleRadius/2) * 2 * count : (rightEdge.x - Constants.BubbleRadius/2) * 2 * count;
                //newPos.x += reversedLeft ? (-rightEdge.x + Constants.BubbleRadius) * 2 : (rightEdge.x - Constants.BubbleRadius) * 2;
            }

            //newPos += normalDir * delta;

            dot.transform.localPosition = newPos;

            RaycastHit2D hit = Physics2D.Raycast(newPos, shootDir);
            if (hit.collider != null) {
                float distance = Vector2.Distance(hit.transform.position, newPos);
                if (distance < Constants.WhiteCircleRadius + Constants.BubbleRadius) {
                    dot.SetActive(false);
                    Debug.Log("Found!: " + distance + " " + hit.collider.name);
                    break;
                } else {
                    dot.SetActive(true);
                }
            }

            if (dot.transform.localPosition.x <= leftEdge.x + Constants.BubbleRadius) {
                hasReversed = true;
                reversedLeft = true;
                normalDir = Vector2.Reflect(normalDir, Vector2.left);
                count++;
            }
            else if (dot.transform.localPosition.x >= rightEdge.x - Constants.BubbleRadius) {
                hasReversed = true;
                reversedLeft = false;
                normalDir = Vector2.Reflect(normalDir, Vector2.right);
                count++;
            }
        }
    }

图像如下: 红点是支点(虚线的起点)。蓝点,是一个气泡。

4

2 回答 2

2

经过一番摆弄,我设法让它工作得相当体面。我从头开始,因为我从来没有做过这样的事情,我需要通过它来了解你遇到的问题。大量的代码只是来自https://medium.com/@kunaltandon.kt/creating-a-dotted-line-in-unity-ca044d02c3e2的 Kunal Tandon 的修改版本,所以向他推荐这么好的教程.

点从墙壁反弹到底部

点在精灵处停止

注意:为了让虚线停在气泡上,我在气泡上添加了一个对撞机和一个标签。然后我只检查代码中的标签。为了确保线路反弹,我为它们添加了一个不同的标签,并且只要我撞到墙就会反弹。

using System.Collections.Generic;
using UnityEngine;

public class DottedLine : MonoBehaviour
{
    Vector3 mp;
    Vector2 mousePosition;
    Vector2 start;
    public Sprite Dot;
    [Range(0.01f, 1f)]
    public float Size;
    [Range(0.1f, 2f)]
    public float Delta;

    List<Vector2> positions;
    List<GameObject> dots;

    private void Start()
    {
        start = new Vector2(transform.position.x, transform.position.y);
        positions = new List<Vector2>();
        dots = new List<GameObject>();
    }

    void Update()
    {
        mp = Camera.main.ScreenToWorldPoint(Input.mousePosition);
        mousePosition = new Vector2(mp.x, mp.y);
        if (Input.GetMouseButtonDown(0))
        {
            DrawPoints(mousePosition);
        }
    }

    public void DrawPoints(Vector2 mousePosition)
    {
        DestroyAllDots();

        Vector2 point = start;
        Vector2 end;
        Vector2 direction = (mousePosition - start).normalized;
        RaycastHit2D ray = Physics2D.Raycast(start, direction);
        Vector3 rayPos = ray.point;

        float distance = Vector2.Distance(ray.transform.position, start);
        end = new Vector2(rayPos.x, rayPos.y);
        //Only needs one line drawn
        if (ray.collider.tag == "bottom" || ray.collider.tag == "bubble")
        {
            DrawOneLine(start, end, direction);
        }
        else if (ray.collider.tag == "wall")
        {
            //Will create a new line every time it hits a wall.
            DrawOneLine(start, end, direction);

            while (ray.collider.tag == "wall")
            {
                Vector3 newRayPos = ray.point;
                Vector2 newStart = new Vector2(newRayPos.x, newRayPos.y);
                direction = Vector2.Reflect(direction, Vector2.right);

                //I had to put in a tolerances so a new raycast could start,
                //there is likely a better way, feedback appreciated.
                Vector2 rightTol = new Vector2(-.001f, 0);
                Vector2 leftTol = new Vector2(.001f, 0);
                if (ray.collider.name == "Right Wall")
                    ray = Physics2D.Raycast(newStart + rightTol, direction);
                else
                    ray = Physics2D.Raycast(newStart + leftTol, direction);
                rayPos = ray.point;
                end = new Vector2(rayPos.x, rayPos.y);
                DrawOneLine(newStart, end, direction, false);
            }
        }

        Render();
    }

    public void DrawOneLine(Vector2 start, Vector2 end, Vector2 direction, bool drawFirst = true)
    {
        //Debug.Log($"Start: {start} End: {end} Direction: {direction}");
        Vector2 point = start;
        while ((end - start).magnitude > (point - start).magnitude)
        {
            if (drawFirst)
                positions.Add(point);
            point += (direction * Delta);
            drawFirst = true;
        }
    }

    GameObject GetOneDot()
    {
        var gameObject = new GameObject();
        gameObject.transform.localScale = Vector3.one * Size;
        gameObject.transform.parent = transform;

        var sr = gameObject.AddComponent<SpriteRenderer>();
        sr.sprite = Dot;
        return gameObject;
    }

    private void Render()
    {
        foreach (var position in positions)
        {
            var g = GetOneDot();
            g.transform.position = position;
            dots.Add(g);
        }
    }

    public void DestroyAllDots()
    {
        foreach (var dot in dots)
            Destroy(dot);
        dots.Clear();
        positions.Clear();
    }
}
于 2019-08-22T09:55:57.477 回答
0

您的圆点过冲——即越过您的游戏区域的左/右边缘。

在此处输入图像描述

您忘记在图像中包含所述限制的可视化,所以这是我最好的猜测。


您正在检查何时dot.transform.localPosition.x超出范围,但何时超出范围,您并没有纠正点的位置!

实际的反弹是用 正确实现的Vector2.Reflect

解决此问题的最简单方法是隐藏最后一个白点:

if (dot.transform.localPosition.x <= leftEdge.x + Constants.BubbleRadius) {
    dot.SetActive(false);
    /* ... */
}
else if (dot.transform.localPosition.x >= rightEdge.x - Constants.BubbleRadius) {
    dot.SetActive(false);
    /* ... */
}

杂项评论,不直接链接到您的问题:

  • 您不需要从每个点进行光线投射,每次反弹一次光线投射就足够了。然后,您将沿着该线放置点。
  • new Vector3(0, 0, 0)可以更简洁地表示为Vector3.zero
  • 通常,不是将向量的大小与值进行比较,而是将其 sqrMagnitude 与该值的平方进行比较。性能差异可能微不足道,这是一个品味问题。
于 2019-08-17T01:22:50.883 回答