【问题标题】:Unity 2D C# gameObject does not activate other gameObjects if statements when colliding with each other. Why?Unity 2D C# 游戏对象在相互碰撞时不会激活其他游戏对象的 if 语句。为什么?
【发布时间】:2017-02-07 07:52:08
【问题描述】:

这个游戏的运作方式是游戏从一个最大的球开始。当火箭击中大球时,它分裂成两个中球,然后分裂成两个小球。当火箭击中最小的球时,它就会被摧毁。

我遇到的问题是当火箭与球相撞时。火箭被摧毁,但球“没有”分成两个大球,依此类推。

我刚刚注意到这一点,我想知道如果我将此代码语句转换为 == "smallest ball" 而不是 !=,我的问题是否会得到解决。

    if (target.tag == "Rocket")
    {
        if (gameObject.tag != "Smallest Ball")
        {
            InstantializeBallsonoff();
        }
        else {
            AudioSource.PlayClipAtPoint(popsounds[Random.Range(0, popsounds.Length)], transform.position);
            //play random audio in the popsounds array at current position of ball
            gameObject.SetActive(false); //deactivate the gameobject
        }
    }
}//ontriggerenter

这是我的球脚本的完整代码

using UnityEngine;
using System.Collections;

public class Ball : MonoBehaviour {

private float forceX, forceY;
private Rigidbody2D ball;

[SerializeField]
private bool moveLeft, moveRight;

[SerializeField]
private GameObject originalBall;

private GameObject ball1, ball2;
private Ball ball1script, ball2script;

[SerializeField]
private AudioClip[] popsounds; //array

// Use this for initialization
void Awake () {
    ball = GetComponent<Rigidbody2D>();
    ballspeed();
}

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

void InstantiatingBalls()
{
    if (this.gameObject.tag != "Smallest Ball")
    {
        ball1 = Instantiate(originalBall); //create copy of originalball into ball1
        ball2 = Instantiate(originalBall);

        ball1.name = originalBall.name;
        ball2.name = originalBall.name;

        ball1script = ball1.GetComponent<Ball>(); //get the ball script 
        ball2script = ball2.GetComponent<Ball>();

    }
}//InstantiatingBalls

void InstantializeBallsonoff() {
    InstantiatingBalls();

    Vector3 temp = transform.position; //start from current ball location
    ball1.transform.position = temp;
    ball1script.setmoveLeft(true);
    ball2.transform.position = temp;
    ball2script.setmoveRight(true);

    ball1.GetComponent<Rigidbody2D>().velocity = new Vector2(0, 2.5f); //x,y
    ball2.GetComponent<Rigidbody2D>().velocity = new Vector2(0, 2.5f); //x,y

    AudioSource.PlayClipAtPoint(popsounds[Random.Range(0, popsounds.Length)], transform.position);
    //play random audio in the popsounds array at current position of ball
    gameObject.SetActive(false); //deactivate the gameobject

}//InstantializeBallsonoff

public void setmoveLeft(bool moveLeft) { //canMoveLeft
    this.moveLeft = moveLeft;
    this.moveRight = !moveLeft; //moveRight is now false b/c we set moveLeft to true
}

public void setmoveRight(bool moveRight) {//canMoveRight
    this.moveRight = moveRight;
    this.moveLeft = !moveRight;
}

void ballmovement() {
    if (moveLeft) {
        Vector3 temp = transform.position; //current position of ball
        temp.x -= Time.deltaTime; // represent time per frame
        transform.position = temp;
    }

    if (moveRight) {
        Vector3 temp = transform.position; //current position of ball
        temp.x += Time.deltaTime; // represent time per frame
        transform.position = temp;
    }
}

void ballspeed() {
    forceX = 2.5f;

    switch (this.gameObject.tag) {
        //this refers to gameobject that holds this script

        case "Largest Ball":
            forceY = 11.5f;
            break;
        case "Large Ball":
            forceY = 10.5f;
            break;
        case "Medium Ball":
            forceY = 9f;
            break;
        case "Small Ball":
            forceY = 8f;
            break;
        case "Smallest Ball":
            forceY = 7f;
            break;
    }//switch

}//ballspeed

void OnTriggerEnter2D (Collider2D target) {
    if (target.tag == "Ground") {
        ball.velocity = new Vector2(0, forceY);
    }

    if (target.tag == "Right Wall") {
        setmoveLeft(true);
        /*moveRight = false;
        moveLeft = true;*/
    }

    if (target.tag == "Left Wall")
    {
        setmoveRight(true);
        /*moveRight = true;
        moveLeft = false;*/
    }

    if (target.tag == "Rocket")
    {
        if (gameObject.tag != "Smallest Ball")
        {
            InstantializeBallsonoff();
        }
        else {
            AudioSource.PlayClipAtPoint(popsounds[Random.Range(0, popsounds.Length)], transform.position);
            //play random audio in the popsounds array at current position of ball
            gameObject.SetActive(false); //deactivate the gameobject
        }
    }
}//ontriggerenter


 }//ball

这是我的代码的一部分,其中火箭在与大球和顶部碰撞时被摧毁。这是我遇到问题的另一部分。

void OnTriggerEnter2D(Collider2D target) {
    if (target.tag == "Top") {
        Destroy(gameObject);
    }

    string[] ballhit = target.name.Split();
    /*array ballhit
    split = deletes the space between two words and make it so it takes 2 spaces in the array*/

    for (int s = 0; s < ballhit.Length; s++) {
        Debug.Log("The array contains: " +ballhit [s]);

        if (ballhit.Length > 1)
        { //ball names will always be more than 1 length "Largest Ball"
            if (ballhit[1] == "Ball")
            {
                Destroy(gameObject);
            }//destroy object
        }//ballhit name length
    }// name increments

}//triggerCollider

这是我的完整火箭脚本

using UnityEngine;
using System.Collections;

public class Rocket : MonoBehaviour {

private Rigidbody2D rocket;
private float speed = 5f;


// Use this for initialization
void Awake () {
    rocket = GetComponent<Rigidbody2D>();
}

// Update is called once per frame
void Update () {
    rocket.velocity = new Vector2(0, speed); //x, y rocket movement
}

void OnTriggerEnter2D(Collider2D target) {
    if (target.tag == "Top") {
        Destroy(gameObject);
    }

    string[] ballhit = target.name.Split();
    /*array ballhit
    split = deletes the space between two words and make it so it takes 2 spaces in the array*/

    for (int s = 0; s < ballhit.Length; s++) {
        Debug.Log("The array contains: " +ballhit [s]);

        if (ballhit.Length > 1)
        { //ball names will always be more than 1 length "Largest Ball"
            if (ballhit[1] == "Ball")
            {
                Destroy(gameObject);
            }//destroy object
        }//ballhit name length
    }// name increments

}//triggerCollider

}//rocket

【问题讨论】:

    标签: c# unity5 unity3d-2dtools


    【解决方案1】:

    您的代码比它需要的要复杂得多,因此很难找到实际的错误。

    首先,您的 moveLeftmoveRight 布尔值是互斥的。你只需要其中之一。我更愿意将两者都替换为public int currentDirection,您将其设置为右侧的 1 和左侧的 -1。
    您的新 ballMovement 方法可以简单地为:

    void MoveBall()    // C# methods are upper-case by convention 
    {
        transform.position += Vector3.right * currentDirection * Time.deltaTime;
    }
    

    检查你正在碰撞哪种类型的球的方式不是很安全。我建议您使用枚举来区分球的大小。

    public enum BallSizes { Largest, Large, Medium, Small, Smallest };    // The different possible values
    public BallSize size = BallSizes.Largest;                             // The balls current size, the biggest size by default
    

    这还允许您将 y 轴力值存储在匹配的数组中,并且无需使用开关或 else-if 即可轻松访问它们:

    private float[] forcesY = new float[]{ 11.5f, 10.5f, 9f, 8f, 7f };
    
    void SetBallSpeed() 
    {
        forceX = 2.5f;
        forceY = forcesY[(int)size];
    }
    

    我认为您遇到的球不分裂的问题与此有关。
    碰撞时,您可以通过检查其标签来检测您所碰撞的球的类型。但是您总是使用相同的预制件实例化新球,而且我从未见过您更改标签。那么你要制作什么类型的球呢?
    如果您使用我上面描述的方法,您可以简单地分配一个通用标签“Ball”并使用 BallSizes-enum 处理其余部分。创建新球时,您可以执行以下操作:

    [SerializedField]            // The SerializedField property makes it show up in the inspector, even though it is private
    private Ball ballPrefab;     // Attention: Type "Ball"
    
    public void IsHit()          // Method to execute upon rocket collision
    {
        if(ball.size != BallSizes.Smallest)
        {
            Ball leftBall = Instantiate(ballPrefab).  // Notice that, when you assign you prefab as Type "Ball", you directly get the Ball-Component as the return value.
            leftball.direction = -1;
            leftball.size = (BallSizes)(size + 1);    // Add one to size, to get get the next enum value, which is the next smaller size.
    
            Ball rightBall = ....                     // Do same stuff for the right ball
        }
    
        Destroy(this.gameObject);
    }
    

    我不知道您打算如何可视化球的类型,但您可能想添加一个 float[] ballScales,用于缩小球的实际大小,例如:leftBall.transform.localScale = Vector3.one * ballScales[(int)size]

    最后,您的碰撞不起作用的另一个原因很可能是您在两个不同的地方处理它。如果你在火箭检测到与球发生碰撞后摧毁它,那么球还没有发生任何事情。如果球随后检查碰撞,它很可能找不到火箭,因为你已经摧毁了它。
    解决这个问题的一个干净方法是让火箭通知碰撞球:

    void OnTriggerEnter2D(Collider2D target) 
    {
        if(target.tag == "Top")
            Destroy(gameObject);
        else if(target.tag == "Ball")
        {
            target.GetComponent<Ball>().IsHit();    // We know this component should exist when the object is tagged "Ball"
            Destroy(gameobject);
        }
    }
    

    然后你可以从你的球碰撞中删除它并将其缩短为:

    void OnTriggerEnter2D (Collider2D target) 
    {
        if(target.tag == "Ground")    
            ball.velocity = new Vector2(0, forceY);
    
        if(target.tag == "Right Wall" || target.tag == "Left Wall")
            direction *= -1;    // Inverts the direction, + <-> -
    }
    

    唷,这可太多了。
    我希望这仍然是相关的,并且回答的问题多于它提出的问题。
    编码愉快!

    【讨论】:

      猜你喜欢
      • 2023-03-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-01-28
      相关资源
      最近更新 更多