I am trying to make a Magnet power up like subway surfer. My game is a endless runner game. When the runner collide with the magnet, the coins attracting towards the player. But it is not working. After runner collide with the magnet and after that every time he collide with the coin below error keep coming.
NullReferenceException: Object reference not set to an instance of an object
Coin.OnTriggerEnter (UnityEngine.Collider other) (at Assets/Scripts/Coin.cs:37)
any one can help me?
Magnet Script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Magnet : MonoBehaviour
{
// Start is called before the first frame update
public GameObject coinDetectorObj;
public static bool iscoinDetectorObj;
// Start is called before the first frame update
void Start()
{
coinDetectorObj = GameObject.FindGameObjectWithTag("coin detector");
coinDetectorObj.SetActive(false);
}
private void OnTriggerEnter(Collider other)
{
if (other.gameObject.tag == "Player")
{
StartCoroutine(ActivateCoin());
Destroy(transform.GetChild(0).gameObject);
}
}
IEnumerator ActivateCoin()
{
coinDetectorObj.SetActive(true);
yield return new WaitForSeconds(0.5f);
coinDetectorObj.SetActive(false);
}
}
Coin Script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Coin : MonoBehaviour
{
public Transform playerTransform;
public float moveSpeed = 17f;
CoinMove coinMoveScript;
void Start()
{
playerTransform = GameObject.FindGameObjectWithTag("Player").transform;
coinMoveScript = gameObject.GetComponent<CoinMove>();
}
void Update()
{
transform.Rotate(130 * Time.deltaTime, 0, 0);
}
private void OnTriggerEnter(Collider other)
{
if (other.tag == "Player")
{
FindObjectOfType<AudioManager>().PlaySound("PickUpCoin");
PlayerManager.numberOfCoins += 1;
Destroy(gameObject);
}
if (other.gameObject.tag == "coin detector")
{
coinMoveScript.enabled = true;
}
}
}
CoinMove Script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CoinMove : MonoBehaviour
{
Coin coinScript;
// Start is called before the first frame update
void Start()
{
coinScript = gameObject.GetComponent<Coin>();
}
// Update is called once per frame
void Update()
{
transform.position = Vector3.MoveTowards(transform.position, coinScript.playerTransform.position,
coinScript.moveSpeed * Time.deltaTime);
}
private void OnTriggerEnter(Collider other)
{
if (other.gameObject.tag == "Player")
{
//Add count or give points etc etc.
Destroy(gameObject);
}
}
}
Related
I'm developing a TopDown 2D game in Unity.
The idea is, when the player steps on a certain tile, a UI with text pops up (already working) and the player stops moving until the player clicks a button (already programmed and working) and the UI disappears.
I was advised to turn the RigidBody2D to kinematic however it doesn't work and it just does what it used to do.
Am I doing something wrong?
Here is the code for the trigger script on the tiles:
public class TriggerScript : MonoBehaviour
{
public string popUp;
public void Start()
{
}
private void OnTriggerEnter2D(Collider2D collision)
{
Rigidbody2D Player = GameObject.Find("Player").GetComponent<Rigidbody2D>();
PopUpSystem pop = GameObject.FindGameObjectWithTag("GameManager").GetComponent<PopUpSystem>();
if (collision.gameObject.tag == "Player")
{
pop.PopUp(popUp);
Player.GetComponent<Rigidbody2D>().bodyType = RigidbodyType2D.Kinematic;
}
}
private void OnTriggerExit2D(Collider2D collision)
{
Rigidbody2D Player = GameObject.Find("Player").GetComponent<Rigidbody2D>();
PopUpSystem pop = GameObject.FindGameObjectWithTag("GameManager").GetComponent<PopUpSystem>();
pop.closeBox();
Player.GetComponent<Rigidbody2D>().bodyType = RigidbodyType2D.Dynamic;
}
}
PopUpSystem.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using TMPro;
public class PopUpSystem : MonoBehaviour
{
public GameObject popUpBox;
public Animator popupanimation;
public TMP_Text popUpText;
public PLayerController mb;
public void PopUp(string text)
{
popUpBox.SetActive(true);
popUpText.text = text;
popupanimation.SetTrigger("pop");
}
public void closeBox()
{
popupanimation.SetTrigger("close");
mb.camMove = true;
}
}
PLayerController.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PLayerController : MonoBehaviour
{
private Rigidbody2D MyRB;
private Animator myAnim;
[SerializeField]
private float speed;
public bool camMove = true;
// Start is called before the first frame update
void Start()
{
MyRB = GetComponent<Rigidbody2D>();
myAnim = GetComponent<Animator>();
}
// Update is called once per frame
void Update()
{
if (camMove)
{
MyRB.velocity = new Vector2(Input.GetAxisRaw("Horizontal"), Input.GetAxisRaw("Vertical")) * speed * Time.deltaTime;
myAnim.SetFloat("moveX", MyRB.velocity.x);
myAnim.SetFloat("moveY", MyRB.velocity.y);
if ((Input.GetAxisRaw("Horizontal") == 1) || (Input.GetAxisRaw("Horizontal") == -1) || (Input.GetAxisRaw("Vertical") == 1) || (Input.GetAxisRaw("Vertical") == -1))
{
myAnim.SetFloat("LastMoveX", Input.GetAxisRaw("Horizontal"));
myAnim.SetFloat("LastMoveY", Input.GetAxisRaw("Vertical"));
}
}
if (!camMove)
{
MyRB.velocity = new Vector2(0, 0);
}
}
}
TriggerScript.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class TriggerScript : MonoBehaviour
{
public string popUp;
Animator popAnim;
public PLayerController mb;
private void Start()
{
popAnim = GameObject.FindGameObjectWithTag("PopUpBox").GetComponent<Animator>();
}
private void OnTriggerEnter2D(Collider2D collision)
{
PopUpSystem pop = GameObject.FindGameObjectWithTag("GameManager").GetComponent<PopUpSystem>();
var myp = GameObject.FindGameObjectWithTag("Player").GetComponent<PLayerController>();
if (collision.gameObject.tag == "Player")
{
pop.PopUp(popUp);
mb.camMove = false;
}
if (popAnim.GetCurrentAnimatorStateInfo(1).IsName("close"))
{
mb.camMove = true;
Debug.Log("close");
}
}
private void OnTriggerExit2D(Collider2D collision)
{
PopUpSystem pop = GameObject.FindGameObjectWithTag("GameManager").GetComponent<PopUpSystem>();
pop.closeBox();
}
}
Things to keep in mind:
1- Make a new tag and call it PopUpBox. then assign this tag to the Trigger GameObject.
2- To the button of the PopUpBox GameObject (the one which is disabled) assign GameManager GameObject and in its function select PopUpSystem.closeBox
3- In both Trigger GameObject and GameManager assign Player in Mb field.
Hope this help you. You can play with that more to get better results.
I am creating this flappy bird style game in unity with C#.
I have a scored function in the Game Controller script. Here it is...
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
public class GameController : MonoBehaviour
{
private int score = 0;
public float starScrollSpeed;
public float groundScrollSpeed;
public float skyScrollSpeed;
public GameObject gameOverText;
public GameObject playAgain;
public bool gameOver = false;
public static GameController instance;
public Text scoreText;
// Start is called before the first frame update
void Awake()
{
if(instance == null)
{
instance = this;
}
else if(instance != this)
{
Destroy(gameObject);
}
}
// Update is called once per frame
void Start()
{
}
void Update()
{
}
public void BirdScored()
{
if (gameOver)
{
return;
}
score++;
scoreText.text = "SCORE " + score.ToString();
}
public void PlaneDestroyed()
{
gameOverText.SetActive(true);
playAgain.SetActive(true);
gameOver = true;
}
}
Actually Bird and Plane is the same thing.
What I want to do is to make the bird score/run the BirdScored() function when the Plane overlaps with a star. The Plane has a Rigidbody2D and a collider and stars have a Rigidbody2D but no collider because In the bird script if the plane collide, it destroys.
Here is the Bird Script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Bird : MonoBehaviour
{
private bool isDead = false;
private Rigidbody2D rb2d;
public float upforce = 200f;
private Animator anim;
// Start is called before the first frame update
void Start()
{
rb2d = GetComponent<Rigidbody2D>();
anim = GetComponent<Animator>();
}
// Update is called once per frame
void Update()
{
if (isDead == false)
{
if (Input.GetMouseButtonDown(0))
{
rb2d.velocity = Vector2.zero;
rb2d.AddForce(new Vector2(0, upforce));
}
}
anim.SetTrigger("Flap");
}
void OnCollisionEnter2D()
{
isDead = true;
anim.SetTrigger("Die");
GameController.instance.PlaneDestroyed();
}
}
And here is the star script...
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Stars : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
}
public void OnTriggerEnter2D(Collider2D other)
{
if (other.gameObject.name == "Plane")
{
GameController.instance.BirdScored();
}
}
}
What is wrong and what should I do?
Put a Colider2D on the star, and check the Is Trigger option in the inspector.
The Is Trigger is disable the collision with any other collider2d so your plane wont be destroyed by the OnCollisionEnter2D, but the OnTriggerEnter2D will trigger properly.
I can see in your screenshot that the collider isn't set to "is trigger", which makes it unable to register trigger collisions.
I'm trying to create a platform that will move player with itself. Both horizontally, as well as vertically. I tried to do this by setting the player's parent to be the platform, but the player doesn't stick to it. This is the code I'm trying to use:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Platform : MonoBehaviour
{
public GameObject player;
public GameObject platformAnchor;
public float movementSpeed;
void Update()
{
transform.position = Vector3.Lerp(transform.position, platformAnchor.transform.position, (Time.deltaTime * movementSpeed));
}
private void OnTriggerEnter(Collider other)
{
if (other.gameObject == player)
{
other.transform.parent = transform;
}
}
private void OnTriggerExit(Collider other)
{
if (other.gameObject == player)
{
other.transform.parent = null;
}
}
}
When the player reSpawns I want the stones(which can be moved by the player), to go to their original spot. This is not working for me. Instead, the stone spawn on other nearby locations and sometimes off the map. All stones are tagged stone.
I have tried reversing the Vectors and reversing the signs on the subtraction and such.
This is the player script.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerControll : MonoBehaviour
{
public bool isTouchingGround = false;
public GameObject locater1;
public GameObject locater2;
public GameObject currentCheckPoint;
public GameObject playerPrefab;
public Rigidbody2D myRigidBody;
public GameObject GameMaster;
// Start is called before the first frame update
void Start()
{
isTouchingGround = false;
GameObject MyGameMaster= Instantiate(GameMaster, new Vector3(0, 0, 0), Quaternion.identity);
GameMaster = MyGameMaster;
}
// Update is called once per frame
void Update()
{
if (Input.GetKey("a"))
{
transform.Translate(-0.1f, 0, 0);
}
if (Input.GetKey("d"))
{
transform.Translate(0.1f, 0, 0);
}
if ((Input.GetKey("w") || Input.GetKey("space")) && isTouchingGround == true)
{
myRigidBody.AddForce(new Vector2(0f, 130f));
}
if (locater1.transform.position.y <= locater2.transform.position.y)
{
ReSpawn();
}
}
private void OnCollisionEnter2D(Collision2D collision)
{
if (collision.gameObject.tag == "Platform" || collision.gameObject.tag == "Stone")
{
isTouchingGround = true;
}
}
private void OnCollisionExit2D(Collision2D collision)
{
if ((collision.gameObject.tag == "Platform" || collision.gameObject.tag == "Stone") && locater2.transform.position.y > collision.transform.position.y)
{
isTouchingGround = false;
}
}
private void OnTriggerEnter2D(Collider2D collision)
{
if (collision.gameObject.tag == "CheckPoint")
{
currentCheckPoint = collision.gameObject;
}
if (collision.gameObject.tag == "Radiation")
{
ReSpawn();
}
}
public void ReSpawn()
{
GameMaster.gameObject.GetComponent<ReverToOriginalPositions>().RevertToOrignalPosition();
GameObject currentPlayer=Instantiate(playerPrefab, currentCheckPoint.transform.position, currentCheckPoint.transform.rotation);
currentPlayer.GetComponent<PlayerControll>().isTouchingGround = false;
Destroy(this.gameObject);
}
}
This is the RememberPositions script. This belongs to every stone to remember the position is has during the start.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class RememberPositions : MonoBehaviour
{
public float StartXPosition;
public float StartYPosition;
float StartRotation;
// Start is called before the first frame update
void Start()
{
StartXPosition = transform.position.x;
StartYPosition = transform.position.y;
StartRotation = transform.rotation.z;
}
// Update is called once per frame
void Update()
{
}
}
this is the RevertToOriginalPosition Script. This reverts the stones to their original positions. This is in the GameMaster/MasterControll.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ReverToOriginalPositions : MonoBehaviour
{
public GameObject[] allStones;
// Start is called before the first frame update
void Start()
{
allStones = GameObject.FindGameObjectsWithTag("Stone");
}
// Update is called once per frame
void Update()
{
}
public void RevertToOrignalPosition()
{
for (int i = 0; i < allStones.Length; i++)
{
allStones[i].gameObject.transform.Translate((new Vector3((allStones[i].gameObject.GetComponent<Transform>().position.x- allStones[i].gameObject.GetComponent<RememberPositions>().StartXPosition) , (allStones[i].gameObject.GetComponent<Transform>().position.y- allStones[i].gameObject.GetComponent<RememberPositions>().StartYPosition), 0)));
allStones[i].gameObject.transform.Rotate(0, 0, -allStones[i].gameObject.transform.rotation.z);
}
}
}
This is the Store reciever Script. This is for another game mechanic called an Activator. This is not that important but I am including it anyway.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class StoreReciever : MonoBehaviour
{
public GameObject reciever;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
}
void OnTriggerEnter2D(Collider2D collision)
{
reciever.gameObject.GetComponent<PolygonCollider2D>().enabled = true;
}
void OnTriggerExit2D(Collider2D collision)
{
reciever.gameObject.GetComponent<PolygonCollider2D>().enabled = false;
}
}
No error messages at all. Just Stones reSpawning in locations they are not supposed to. Thank You for helping.
Just make some fields/properties they dont even have to be private static readonly
public static readonly Vector3 StartPos = new Vector3(1.0f, 2.0f, 3.0f);
public static readonly Vector3 StartRot_In_EulerAngles = new Vector3(1.0f, 2.0f, 3.0f);
Then you can do something like this in a method:
public static void ResetMyStones()
{
var allStones = GameObject.FindGameObjectsWithTag("Stone");
foreach(var stone in allStones)
{
stone.transform.position = StartPos;
stone.transform.eulerAngles = StartRot_In_EulerAngles;
}
}
About Euler Angle:
Why Euler Angle? - because for rotations Unity uses so called Quaternions, so Gimbal lock will not happen, but the bad thing about this is that you cannot really set x y z component individually without deep understanding of Quaternions, however if you just wanna set and get a current rotation Euler Angle is perfect, because you can use the traditional x,y,z components for setting the value.
Additional Notes:
Your code is kinda long and not well structured, like ReverToOriginalPositions should be a method and not a component, also not evrything has to be a derived from monobehaviour.
Also remove the unused Update methods, they have a small overhead if its in a script but not used(Usually its immeasurable but in bigger project it can effect performance :)), and maybe if your game is structured that way you could store all your current stones in a GameManager class list so you dont need to call GameObject.FindGameObjectsWithTag("Stone");
im having a problem from my enemyDamage script in unity5 when i play it and stick to the enemy i died instantly even the enemy damage is 10 and my health was 100
well this is my first time to make this things on unity hope you helps me :(
heres my code
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class enemydmg : MonoBehaviour {
public float damage;
public float damagerate;
public float pushbackforce;
float nextdamage;
bool playerInRange = false;
GameObject theplayer;
playerHealth theplayerhealth;
// Use this for initialization
void Start () {
nextdamage = Time.time;
theplayer = GameObject.FindGameObjectWithTag ("Player");
theplayerhealth = theplayer.GetComponent<playerHealth> ();
}
// Update is called once per frame
void Update () {
if (playerInRange)
Attack ();
}
void OnTriggerEnter (Collider other)
{
if (other.tag == "Player")
{
playerInRange = true;
}
}
void OnTriggerExit (Collider other)
{
if (other.tag == "Player")
{
playerInRange = false;
}
}
void Attack()
{
if (nextdamage <= Time.time)
{
theplayerhealth.addDamage(damage);
nextdamage = Time.time + damagerate;
pushback (theplayer.transform);
}
}
void pushback(Transform pushObject)
{
Vector3 pushDirection = new Vector3 (0, (pushObject.position.y - transform.position.y), 0).normalized;
pushDirection *= pushbackforce;
Rigidbody pushedRB = pushObject.GetComponent<Rigidbody> ();
pushedRB.velocity = Vector3.zero;
pushedRB.AddForce (pushDirection, ForceMode.Impulse);
}
}
and this was my playerhealth
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class playerHealth : MonoBehaviour {
public float fullhealth;
float currentHealth;
// Use this for initialization
void Start () {
currentHealth = fullhealth;
}
// Update is called once per frame
void Update () {
}
public void addDamage(float damage)
{
currentHealth -= damage;
if (currentHealth <= 0) {
makeDead ();
}
}
public void makeDead()
{
Destroy (gameObject);
}
}
theplayerhealth = theplayer.GetComponent<playerHealth> ();
I think this line of code fails you because the player is a GameObject. theplayerhealth is or should already be initialized in your other script. I think you could approach polymorphism in a better way.
public class enemydmg : playerHealth{
}
This will allow you to directly inherit everything you need from the playerHealth script without having to grab extra components. You can also use this technique for may other scripts in the future.
Another approach that you could use is calling your class directly:
playerHealth.addDamage(damage);
From now on when you name your scripts use capitalization. PlayerHealth, EnemyDamage, etc... That's just a pro-tip to make your code look a bit cleaner when you're doing things like this. (Optional)