简体   繁体   English

传送不工作 c# 统一代码(完整的菜鸟)

[英]teleport not working c# unity code (complete noob)

I am trying to get my gameobject character to move from one location to another in a video game after picking up 4 objects.在拿起 4 个对象后,我试图让我的游戏对象角色在视频游戏中从一个位置移动到另一个位置。 It does teleport but once it does it'll keep teleporting to the specified location.它会传送,但一旦传送,它就会继续传送到指定位置。 I don't know how to stop it so it lets me move freely to the new location.我不知道如何阻止它,所以它让我可以自由地移动到新位置。 The thing that makes it go to the new location is the if (scoreValue >= 4) {winTextObject.SetActive(true);}.使它转到新位置的原因是if (scoreValue >= 4) {winTextObject.SetActive(true);}。

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

public class PlayerScript: MonoBehaviour {
  private Rigidbody2D rd2d;
  public float speed;
  public Text scoreText;
  private int scoreValue;
  public GameObject winTextObject;
  public GameObject loseTextObject;
  private int lives;
  public Text livesText;

  // Start is called before the first frame update
  void Start() {
    rd2d = GetComponent < Rigidbody2D > ();
    scoreValue = 0;
    scoreText.text = "Score: " + scoreValue.ToString();
    winTextObject.SetActive(false);
    loseTextObject.SetActive(false);
    lives = 3;
  }

  // Update is called once per frame
  void FixedUpdate() {
    float hozMovement = Input.GetAxis("Horizontal");
    float verMovement = Input.GetAxis("Vertical");
    rd2d.AddForce(new Vector2(hozMovement * speed, verMovement * speed));
  }

  private void OnCollisionEnter2D(Collision2D collision) {
    if (collision.collider.tag == "Coin") {
      scoreValue += 1;
      scoreText.text = "Score: " + scoreValue.ToString();
      Destroy(collision.collider.gameObject);
    } else if (collision.collider.tag == "Enemy") {
      lives -= 1;
      livesText.text = lives.ToString();
      Destroy(collision.collider.gameObject);
    }

  }

  void Update() {

    if (scoreValue >= 4) {
      winTextObject.SetActive(true);
    } {
      livesText.text = "Lives: " + lives.ToString();
    }
    if (lives <= 0) {
      loseTextObject.SetActive(true);
    }

  }

  private void OnCollisionStay2D(Collision2D collision) {
    if (collision.collider.tag == "Ground") {
      if (Input.GetKey(KeyCode.W)) {
        rd2d.AddForce(new Vector2(0, 3), ForceMode2D.Impulse);
      }
    }
    if (Input.GetKey("escape")) {
      Application.Quit();
    }
    if (scoreValue == 4) {
      transform.position = new Vector2(64.0 f, -1.0 f);
    }
  }
}

You can add an additional boolean variable so that it will enter that if only once.您可以添加额外的布尔变量,这样它会输入if只有一次。

  1. At the beginning you declare private bool isGameOver;一开始你声明private bool isGameOver;
  2. Inside Start() you make sure isGameOver = falseStart()您确保isGameOver = false
  3. Change your final condition with:更改您的最终条件:
  if (scoreValue == 4 && !isGameOver)
  { 
    isGameOver = true;
    transform.position = new Vector2(64.0f, -1.0f);
  }

With this addition you will fire your "teleport" just once.有了这个添加,您将只触发一次“传送”。

I think you should put a flag where you want the transportation event occurs.我认为您应该在您希望发生运输事件的地方放置一个标志。

bool isTransported = false;

then compare in Update()然后在 Update() 中进行比较

if (scoreValue >= 4) isTransported == true;

if (isTransported) transform.position = new Vector2(64.0 f, -1.0 f);

then reset the boolean if you want to do another transportation by doing:如果您想通过以下方式进行另一次运输,则重置布尔值:

isTranported == false;

And I also suggest that you if you want to do some more transportation events in your game.如果你想在你的游戏中做更多的交通事件,我也建议你。 You should explicitly compare your score with a value or a range of values.您应该明确地将您的分数与一个值或一系列值进行比较。 If not, your event will not work correctly.否则,您的活动将无法正常工作。 For example, when score >=4 you want your character teleports to location A, when score >=10 your character moves to location B then the conditions overlap here.例如,当得分 >=4 时,您希望您的角色传送到位置 A,当得分 >=10 时,您的角色移动到位置 B,则这里的条件重叠。 The game will execute both events because >=10 is also >=4 as well.游戏将执行这两个事件,因为 >=10 也是 >=4。

In general instead of poll-checking these values every frame make you code event driven !通常,不是每帧轮询检查这些值,而是让您编写事件驱动的代码!

There is no need for an additional flag at all.根本不需要额外的标志。

As OnCollisionEnter2D seems actually to be the only place where the two values are changed rather do eg由于OnCollisionEnter2D似乎实际上是改变两个值的唯一地方而不是例如

// NOT NEEDED AT ALL
// private void Update() { }

private void OnCollisionEnter2D(Collision2D collision) 
{
    // In general rather use "CompareTag" instead of string "=="
    // While "==" silently fails in case of typos or non-existent tags
    // "CompareTag" will throw an error making your debugging easier and is also slightly faster since it uses Hashes
    if (collision.gameObject.CompareTag("Coin")) 
    {
        Destroy(collision.gameObject);

        scoreValue++;
        scoreText.text = $"Score: {scoreValue}";
        
        if(scoreValue == 4)
        {
            winTextObject.SetActive(true);
            // in general never set the position via Transform when dealing with Rigidbodis!
            rd2d.position = new Vector2(64.0 f, -1.0 f);
        }
    } 
    else if (collision.gameObject.CompareTag("Enemy")) 
    {
        Destroy(collision.gameObject);

        lives--;
        livesText.text = $"Lives: {lives}";

        if (lives <= 0) 
        {
            loseTextObject.SetActive(true);
        }
    }
}

private void OnCollisionStay2D(Collision2D collision) 
{
    if (collision.gameObject.CompareTag("Ground"))
    {
        if (Input.GetKey(KeyCode.W)) 
        {
            rd2d.AddForce(new Vector2(0, 3), ForceMode2D.Impulse);
        }
    }

    if (Input.GetKey("escape")) 
    {
        Application.Quit();
    }

    // no need to poll check the "lives" here either
}

You could even take it one more level further and use properties this way you can couple a behavior to any change of your fields and could even set them from the outside without having to double implement stuff:您甚至可以更进一步地使用属性,这样您就可以将行为与字段的任何更改结合起来,甚至可以从外部设置它们而无需双重实现:

// This only stores the value (backing field) but you will never touch it directly ;)
private int _scoreValue;

// This now is a property that allows everyone to read the value
// but only this class to set it (for now)
// additionally every time you set the value it will update the display and react to the => 4 condition
public int scoreValue
{
    get => _scoreValue;
    private set
    {
        _scoreValue = value;
        scoreText.text = $"Score: {_scoreValue}";
            
        if(_scoreValue == 4)
        {
            winTextObject.SetActive(true);
            // in general never set the position via Transform when dealing with Rigidbodis!
            rd2d.position = new Vector2(64.0 f, -1.0 f);
        }
    }
}

// The same thing you can also make for the lives
private int _lives;

public int lives
{
    get => _lives;
    private set
    {
        _lives = value;
        livesText.text = $"Lives: {_lives}";

        if (_lives <= 0) 
        {
            loseTextObject.SetActive(true);
        }
    }
}

So now yo would simply do所以现在你会简单地做

private void OnCollisionEnter2D(Collision2D collision) 
{
    // In general rather use "CompareTag" instead of string "=="
    // While "==" silently fails in case of typos or non-existent tags
    // "CompareTag" will throw an error making your debugging easier and is also slightly faster since it uses Hashes
    if (collision.gameObject.CompareTag("Coin")) 
    {
        Destroy(collision.gameObject);

        scoreValue++;
    } 
    else if (collision.gameObject.CompareTag("Enemy")) 
    {
        Destroy(collision.gameObject);

        lives--;
    }
}

but can later add more and more way of how you can lose or gain score and lives without having to remember to also implement the text updates and condition checks.但是以后可以添加越来越多的方式来说明如何失去或获得分数和生命,而不必记住还要实现文本更新和条件检查。 You only do these once within the properties ;)你只能做这些曾经的属性中;)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM