How can I redirectveriable veriable from object to my haracter - c#

I have 2 scripts one on player :
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerPositionCorrection : MonoBehaviour
{
Transform _playerTransform;
public float _xAxys;
public float _newXAxys;
public GameObject _changerPlayerPosition;
private void Start()
{
_playerTransform = GetComponent<Transform>();
}
private void OnTriggerEnter(Collider other)
{
if (other.tag == "ChangePlayerPosition")
{
float _newXAxys = this.GetComponent<ChangePositionOn>()._newPostion;
}
}
private void LateUpdate()
{
if (transform.position.z != 0)
{
transform.position = new Vector3(_xAxys, _playerTransform.position.y, _playerTransform.position.z);
}
}
and second on object :
public class ChangePositionOn : MonoBehaviour
{
public float _newPostion = 5;
void Start()
{
}
// Update is called once per frame
void Update()
{
}
}
I using Unity 2022.1.19f1 and C#.
Thank you for your healp,
Michal
I would like to have several object in my game and when player will collide with them change location on x axis.
Unfortunately every time i have this error message:
NullReferenceException: Object reference not set to an instance of an object
PlayerPositionCorrection.OnTriggerEnter (UnityEngine.Collider other) (at Assets/Scripts/PlayerPositionCorrection.cs:23)

Check if the ChangePositionOn script is attached to the player
gameObject.
remove the float decalaration in the function because it makes it a
local variable
replace your function with this instead
private void OnTriggerEnter(Collider other)
{
if (other.CompareTag("ChangePlayerPosition"))
{
Debug.Log("Check if Collided With : "+ other.gameObject.name);
_newXAxys = this.GetComponent<ChangePositionOn>()._newPostion;
Debug.Log("New XAxys value : "+ _newXAxys );
}
}

Make a new script PositionCorrector and Attach it to the Collider GameObject :
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PositionCorrector : MonoBehaviour
{
//this should be attached to Collider GameObject
//this is the X value you want to change to, each collider can have a different number.
public float _newXAxys=4;
private void OnTriggerEnter(Collider other)
{
if (other.CompareTag("PlayerTag"))
{
//changing the x axys of the player position
other.transform.position = new Vector3(_newXAxys, other.transform.position.y, other.transform.position.z);
}
}
}

Related

How to set Object pooling correctly in 2D game?

I have a couple of problems with object pooling in Unity with my 2D game, cannon balls don't want to stop when there is a collision with the wall, and 1 of them bursts shoot and the other 9 shoot together connected with each other, my cannon is static object on scene. Can someone help or give me some hint about it.
Here is my code, 3 scripts:
ObjectPooling.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ObjectPooling : MonoBehaviour
{
public static ObjectPooling instance;
[SerializeField] public GameObject objectToPool;
private List<GameObject> cannonBalls = new List<GameObject>();
private int numberOfObjects = 20;
private void Awake()
{
instance = this;
}
// Start is called before the first frame update
void Start()
{
for (int i = 0; i < numberOfObjects; i++)
{
GameObject gameObject = Instantiate(objectToPool);
gameObject.SetActive(false);
cannonBalls.Add(gameObject);
}
}
// Update is called once per frame
void Update()
{
}
public GameObject GetCannonBallObject()
{
for (int i = 0; i < cannonBalls.Count; i++)
{
if (!cannonBalls[i].activeInHierarchy)
{
return cannonBalls[i];
}
}
return null;
}
}
Cannon.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Cannon : MonoBehaviour
{
[SerializeField] private Rigidbody2D rb;
[SerializeField] private GameObject cannonBall;
[SerializeField] private Transform cannonBallPosition;
void Start()
{
}
private void Update()
{
Fire();
}
private void Fire()
{
cannonBall = ObjectPooling.instance.GetCannonBallObject();
if(cannonBall != null)
{
cannonBall.transform.position = cannonBallPosition.position;
cannonBall.SetActive(true);
}
}
}
CannonBall.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CannonBall : MonoBehaviour
{
private float speed = 10f;
[SerializeField] private Rigidbody2D rb;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
rb.velocity = Vector2.left * speed;
}
private void OnCollisionEnter2D(Collision2D collision)
{
if (collision.gameObject.CompareTag("FloorAndWall"))
{
// Destroy(this.gameObject);
gameObject.SetActive(false);
}
}
}
Why is you cannonball static? Have your tried not having it marked as static? Also, this problem has nothing to do with object pooling. Make sure that when your objects are enabled, all the components are active. Finally, when working with rigidbodies, you should handle them inside FixedUpdate(), and not inside Update().

OnTriggerExit2D getting called unnecessarily

I hope you all are doing well. I have been following a Unity tutorial for a rhythm game and I have found this bug that I could not get past. Essentially, my OnTriggerExit2D is getting called too early. I'll include a picture in the conclusion of this post. I have tried logging the game object and it seems that all of my button objects suffer the same fate. I have included a link of the tutorial that I have been following in the conclusion. Any help towards figuring this out would be helpful.
Tutorial Link: https://www.youtube.com/watch?v=PMfhS-kEvc0&ab_channel=gamesplusjames
What my game looks like, the missed shows up when I've hit it.
Debug Output
GameManager
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class GameManager : MonoBehaviour
{
public AudioSource theMusic;
public bool startPlaying;
public BeatScroller theBS;
public static GameManager instance;
public int currentScore;
public int scorePerNote = 100;
public int scorePerGoodNote = 125;
public int scorePerPerfectNote = 150;
public int currentMultiplier;
public int multiplierTracker;
public int [] multiplierTresholds;
public Text scoreText;
public Text multiText;
// Start is called before the first frame update
void Start()
{
instance = this;
scoreText.text = "Score: 0";
multiText.text = "Multiplier: x1";
currentMultiplier = 1;
}
// Update is called once per frame
void Update()
{
if(!startPlaying){
if(Input.anyKeyDown){
startPlaying = true;
theBS.hasStarted = true;
theMusic.Play();
}
}
}
public void NoteHit(){
Debug.Log("Note Hit On Time");
if(currentMultiplier-1 < multiplierTresholds.Length){
multiplierTracker++;
if(multiplierTresholds[currentMultiplier-1] <= multiplierTracker){
multiplierTracker = 0;
currentMultiplier++;
}
}
multiText.text = "Multiplier: x"+currentMultiplier;
//currentScore += scorePerNote * currentMultiplier;
scoreText.text = "Score: "+currentScore;
}
public void NormalHit(){
currentScore += scorePerNote * currentMultiplier;
NoteHit();
}
public void GoodHit(){
currentScore += scorePerGoodNote * currentMultiplier;
NoteHit();
}
public void PerfectHit(){
currentScore += scorePerPerfectNote * currentMultiplier;
NoteHit();
}
public void NoteMissed(){
Debug.Log("MISSED!");
multiText.text = "Multiplier: x1";
}
}
BeatScroller
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class BeatScroller : MonoBehaviour
{
public float beatTempo;
public bool hasStarted;
// Start is called before the first frame update
void Start()
{
beatTempo = beatTempo / 60f;
}
// Update is called once per frame
void Update()
{
if(!hasStarted){
}else{
transform.position -= new Vector3(0f, beatTempo*Time.deltaTime, 0f);
}
}
}
ButtonController
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ButtonController : MonoBehaviour
{
// Start is called before the first frame update
private SpriteRenderer theSR;
public Sprite defaultImage;
public Sprite pressedImage;
public KeyCode keyToPress;
void Start()
{
theSR = GetComponent<SpriteRenderer>();
}
// Update is called once per frame
void Update()
{
if(Input.GetKeyDown(keyToPress))
{
theSR.sprite = pressedImage;
}
if(Input.GetKeyUp(keyToPress))
{
theSR.sprite = defaultImage;
}
}
}
noteObject
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class noteObject : MonoBehaviour
{
public bool canBePressed;
public KeyCode KeyToPress;
public GameObject hitEffect, goodEffect, perfectEffect, missedEffect;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
if(Input.GetKeyDown(KeyToPress))
{
if(canBePressed)
{
gameObject.SetActive(false);
if(Mathf.Abs(transform.position.y) > 0.25){
GameManager.instance.NormalHit();
Debug.Log("Normal Hit!");
Instantiate(hitEffect,transform.position, hitEffect.transform.rotation);
}else if(Mathf.Abs(transform.position.y) > 0.05f){
GameManager.instance.GoodHit();
Debug.Log("Good Hit!!");
Instantiate(goodEffect,transform.position, goodEffect.transform.rotation);
}else{
GameManager.instance.PerfectHit();
Debug.Log("PERFECT HIT!!!");
Instantiate(perfectEffect,transform.position, perfectEffect.transform.rotation);
}
}
}
}
private void OnTriggerEnter2D(Collider2D other)
{
if(other.tag == "Activator")
{
canBePressed = true;
}
}
private void OnTriggerExit2D(Collider2D other)
{
if(other.tag == "Activator")
{
Debug.Log("Exited collider on game object: "+ other.gameObject.name);
canBePressed = false;
GameManager.instance.NoteMissed();
Instantiate(missedEffect,transform.position, missedEffect.transform.rotation);
}
}
}
EffectObject
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EffectObject : MonoBehaviour
{
public float lifeTime = 1f;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
Destroy(gameObject, lifeTime);
}
}
Hmm ... You say that OnTriggerExit2D is called to early? I assume it's called when the elements are still inside one another? If that's the case I guess your bounding boxes don't have the right size, or the right shape. I see arrows, do they have a rectangular bounding box or a polygon one that follows their shape? Are all your bounding boxes the right size?
I figured out what was wrong thanks to AdrAs's comment.
Turns out I had to check the y position of my arrow and collider were well enough below the height of my button box collider. In addition to that, I reshaped my colliders. I found that this code did the trick for me. Thank You All For the Nudges in the right direction.
noteObject -> new OnTriggerExit2D
private void OnTriggerExit2D(Collider2D other)
{
if(other.tag == "Activator" && transform.position.y < -0.32)
{
Debug.Log("Exited collider on game object: "+ other.gameObject.name);
canBePressed = false;
GameManager.instance.NoteMissed();
Instantiate(missedEffect,transform.position, missedEffect.transform.rotation);
}
}

Unity2D: Fixing colliding for inventory

My goal was to make my character pickup item on collider (2D) didn't work.
So here is what I've tried:
Player Controller Script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerController : MonoBehaviour
{
public float moveSpeed = 2f;
public Inventory inventory;
void Start()
{
}
public bool isGrounded;
public LayerMask groundLayers;
void Update()
{
// isgrounded?
isGrounded = Physics2D.OverlapArea(new Vector2(transform.position.x -
0.2f, transform.position.y - 0.2f),
new Vector2(transform.position.x + 0.2f, transform.position.y -
0.21f), groundLayers);
Jump();
Vector3 movement = new Vector3(Input.GetAxis("Horizontal"), 0f, 0f);
transform.position += movement * Time.deltaTime * moveSpeed;
}
void Jump()
{
if(Input.GetButtonDown("Jump") && isGrounded)
{
gameObject.GetComponent<Rigidbody2D>().AddForce(new Vector2(0f,
2.5f), ForceMode2D.Impulse);
}
}
private void OnCollisionEnter2D(ControllerColliderHit hit)
{
IInventoryItem item = hit.collider.GetComponent<IInventoryItem>();
if (item != null)
{
inventory.AddItem(item);
}
}
}
HUD SCRIPT:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class HUD : MonoBehaviour
{
public Inventory Inventory;
void Start ()
{
Inventory.ItemAdded += InventoryScript_ItemAdded;
}
private void InventoryScript_ItemAdded(object sender, InventoryEventArgs
e)
{
Transform inventoryPanel = transform.Find("InventoryPanel");
foreach(Transform slot in inventoryPanel)
{
// Border... Image
Image image = slot.GetChild(0).GetChild(0).GetComponent<Image>();
// We found empty slot!
if (!image.enabled)
{
image.enabled = true;
image.sprite = e.Item.Image;
// Todo store a reference;
break;
}
}
}
}
Inventory Script:
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Inventory : MonoBehaviour
{
private const int SLOTS = 7;
private List<IInventoryItem> mItems = new List<IInventoryItem>();
public event EventHandler<InventoryEventArgs> ItemAdded;
public void AddItem(IInventoryItem item)
{
if(mItems.Count < SLOTS)
{
Collider collider = (item as MonoBehaviour).GetComponent<Collider>
();
if (collider.enabled)
{
collider.enabled = false;
mItems.Add(item);
item.OnPickup();
if (ItemAdded != null)
{
ItemAdded(this, new InventoryEventArgs(item));
}
}
}
}
}
Inventory Item Script:
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public interface IInventoryItem
{
string Name { get; }
Sprite Image { get; }
void OnPickup();
}
public class InventoryEventArgs : EventArgs
{
public InventoryEventArgs(IInventoryItem item)
{
Item = item;
}
public IInventoryItem Item;
}
Rock Script (The object):
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Rock : MonoBehaviour, IInventoryItem
{
public string Name
{
get
{
return "Rock";
}
}
public Sprite _Image = null;
public Sprite Image
{
get
{
return _Image;
}
}
public void OnPickup()
{
// TODO: ADD LOGIC THAT WILL MAKE THE ROCK A 'WEAPON' TO CUT DOWN THE
TREE
gameObject.SetActive(false);
}
}
All of those scripts work, but whenever I join my game and Collide the player with the object (all 2d, 2D Box colliders, etc.) the character wont pick the item up and put it in it's inventory?
The scripts are referenced to each other.
What did I do wrong?
Physics 2D Screenshot:
Player inspector screenshot:
Rock (Object that needs to join his inventory)
One thing I noticed is that you are mixing the syntax of two events to create one that doesn't exist. void OnCollisionEnter2D(ControllerColliderHit hit) is not a built-in event in Unity. You probably mean to use void OnCollisionEnter2D(Collision2D hit):
private void OnCollisionEnter2D(Collision2D hit)
{
IInventoryItem item = hit.collider.GetComponent<IInventoryItem>();
if (item != null)
{
inventory.AddItem(item);
}
}
Another thing is that BoxCollider2D does not inherit from Collider. So, in AddItem, you should look for a Collider2D component instead:
public void AddItem(IInventoryItem item)
{
if(mItems.Count < SLOTS)
{
Collider2D collider = (item as MonoBehaviour).GetComponent<Collider2D>();
if (collider.enabled)
{
collider.enabled = false;
mItems.Add(item);
item.OnPickup();
if (ItemAdded != null)
{
ItemAdded(this, new InventoryEventArgs(item));
}
}
}
}
Consider this to be a partial solution because this may not capture all the changes needed... Let me know if this alone doesn't fix the problem in the comments below.

Method inaccessible due to its protection level

I'm currently developing within Unity 2018 and have made a script for decreasing a character's health on collision with an enemy:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class HealthManager : MonoBehaviour
{
public static int currentHealth;
public Slider healthBar;
void Awake()
{
healthBar = GetComponent<Slider> ();
currentHealth = 100;
}
void ReduceHealth()
{
currentHealth = currentHealth - 1;
healthBar.value = currentHealth;
}
void Update()
{
healthBar.value = currentHealth;
}
}
When I try to use said method in the scripting file for the enemy I get an error stating "Assets/Custom Scripts/BeetleScript.cs(46,28): error CS0122: `HealthManager.ReduceHealth()' is inaccessible due to its protection level"
The following is the enemy script initiating the variables being used and calling the method:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class BeetleScript : MonoBehaviour
{
Animator animator;
public GameObject cucumberToDestroy;
public bool cherryHit = false;
public float smoothTime = 3.0f;
public Vector3 smoothVelocity = Vector3.zero;
public PointsManager _ptsManager;
public HealthManager _healthManager;
void Start()
{
animator = GetComponent<Animator>();
}
void Update()
{
if (cherryHit)
{
var cm = GameObject.Find("CucumberMan");
var tf = cm.transform;
this.gameObject.transform.LookAt(tf);
// move towards Cucumber Man
animator.Play("Standing Run");
transform.position = Vector3.SmoothDamp(transform.position, tf.position,
ref smoothVelocity, smoothTime);
}
}
// Collision Detection Test
void OnCollisionEnter(Collision col)
{
if (col.gameObject.CompareTag("Player"))
{
_healthManager = GameObject.Find
("Health_Slider").GetComponent<HealthManager>();
_healthManager.ReduceHealth();
if (!cherryHit)
{
BeetlePatrol.isAttacking = true;
var cm = GameObject.Find("CucumberMan");
var tf = cm.transform;
this.gameObject.transform.LookAt(tf);
animator.Play("Attacking on Ground");
StartCoroutine("DestroySelfOnGround");
}
else
{
animator.Play("Standing Attack");
StartCoroutine("DestroySelfStanding");
}
}
}
}
Any help to fix this would be appreciated.
Your methods are private.
You have to write public in front of the method you want to access from outside the class.
public void ReduceHealth()
{
...
}
You need to make void ReduceHealth() to be public -> public void ReduceHealth()

How can I use behaviours in Unity?

I am very new to c# and coding in general.
What I got is a weapon script that has a public int of 50 (damage). Then I got another script which is the enemy health.
Now what I want to do is use the value in the weapon script to apply it to the enemy health script and I have no clue how to do it.
I know its something quite simple but ive been bashing my head against the wall trying to figure this thing out.
Please help!
Weapon.cs:
using UnityEngine;
using System.Collections;
public class Weapon : MonoBehaviour {
static Animator anim;
public GameObject hitbox;
public int damage = 50;
private AudioSource MyAudioSource;
private AudioClip WeaponSound;
void Start () {
anim = GetComponentInParent<Animator>();
MyAudioSource = GetComponent<AudioSource>();
GetComponent<EnemyHealth>().TakeDamage(damage);
}
void Update () {
attack();
block();
}
public void attack() {
if (Input.GetButtonDown("Fire1")) {
GetComponent<EnemyHealth>().TakeDamage(damage);
anim.SetBool("IsAttacking", true);
hitbox.SetActive(true);
Debug.Log("hit");
MyAudioSource.PlayOneShot(WeaponSound);
}
else {
anim.SetBool("IsAttacking", false);
hitbox.SetActive(false);
}
}
public void block() {
if (Input.GetButtonDown("Fire2")) {
anim.SetBool("IsBlocking", true);
}
else {
anim.SetBool("IsBlocking", false);
}
}
}
EnemyHealth.cs:
using UnityEngine;
using System.Collections;
public class EnemyHealth : MonoBehaviour {
public int maxHealth = 100;
private int currentHealth;
private Animator animator;
void Start () {
currentHealth = maxHealth;
animator = GetComponent<Animator>();
}
public void OnTriggerEnter(Collider other) {
other.GetComponent<Weapon>().attack();
}
public void TakeDamage(int _damage) {
currentHealth -= _damage;
animator.SetTrigger("IsHit");
if(currentHealth <= 0) {
Die();
}
}
void Die() {
animator.SetBool("Isdead", true);
Destroy(gameObject);
}
}
Assuming these are both instantiated in another main class (meaning ones not isntatiate from another) in c# you just use the '.' operator to access public elements, properties and functions in a class
main()
{
EnemyHealth myehlth = new EnemyHealth();
Weapon myweapn = new Weapon ();
myehlth.TakeDamage(myweapn.damage);
}
Here I used the '.' operator to access the public damage in your weapon class and then used the '.' oeprator to pass it to the public TakeDamage function in your health class
The answer was quite simple! Thanks noone392
main()
{
Weapon myweapn = new Weapon ();
TakeDamage(myweapn.damage);
}

Categories