Want to make my Spheres able to damage each other
Have tried to get the component of the other object
Health script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
public class Hitpoints
{
private int health;
public int healthMax;
public Hitpoints(int health)
{
this.health = health;
}
public int GetHealth()
{
return health;
}
public float GetHealthPercent()
{
return (float)health / healthMax;
}
public void Damage(int damageAmount)
{
health -= damageAmount;
if (health < 0)
{
health = 0;
}
}
public void Heal(int healAmount)
{
health += healAmount;
if (health > healthMax)
{
health = healthMax;
}
}
}
Damage script
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;
public class Detect_Blue : MonoBehaviour
{
Hitpoints hitpoints = new Hitpoints(100);
bool onetime = false;
public float radius;
public Vector3 direction = new Vector3(2, 2, 2);
private void Start()
{
Debug.Log("Health: " + hitpoints.GetHealth());
InvokeRepeating("DetectEnemy", 4f, 2f);
}
private void DetectEnemy()
{
var hitColliders = Physics.OverlapSphere(direction, radius);
for (var i = 0; i < hitColliders.Length; i++)
{
if (hitColliders[i].CompareTag("Player"))
{
if (!onetime)
{
onetime = true;
print(hitColliders[i].tag);
InvokeRepeating("Hello", 1, 1);
}
}
// collect information on the hits here
}
}
private void Hello()
{
var hitColliders = Physics.OverlapSphere(direction, radius);
for (var i = 0; i < hitColliders.Length; i++)
{
if (hitColliders[i].CompareTag("Player"))
{
hitColliders[i].GetComponent<Hitpoints>().Damage(10);
}
Debug.Log("Damaged: " + hitColliders[i].GetComponent<Hitpoints>().GetHealth());
if (hitpoints.GetHealth() == 0)
{
Destroy(gameObject);
}
}
}
}
ArgumentException: GetComponent requires that the requested component 'Hitpoints' derives from MonoBehaviour or Component or is an interface.
UnityEngine.Component.GetComponent[Hitpoints] () (at C:/buildslave/unity/build/Runtime/Export/Component.bindings.cs:42)
Detect_Blue.Hello () (at Assets/Detect_Blue.cs:57)
When you do GetComponent<T> on a game object, the type of T should inherit from monobehaviour.(Since Monobehavior are components for game-object, and you are trying to get a component)
To fix this, just simply use the hitpoints you have already created in Detect_Blue.
Debug.Log("Damaged: " + hitColliders[i].GetComponent<Hitpoints>().GetHealth());
will become
Debug.Log("Damaged: " + hitColliders[i].GetComponent<Detect_Blue>().hitpoints.GetHealth());
likewise for hitColliders[i].GetComponent<Hitpoints>().Damage(10);, it should be:
hitColliders[i].GetComponent<Detect_Blue>().hitpoints.Damage(10);
Alternatively,
you can just simply make Hitpoints inherit from Monobehavior and attach the script to the respective gameObject.
Though in your case, the first solution will be more feasible.
Also, you can use OnCollisionEnter to detect when the balls enter collision with another object.
Related
What I'm trying to do is have my player stop moving so I can play animation through a trigger-event or just a custscene.
What I expect was for one of them to trigger the timer then play animation>player move.. like a cut-scene
Also there are no errors In any of them They just didn't stop player from moving or just stop the player when starting the game(or when I press play it just set forwardMovement to 0)
Here's the code I use:
public class Player_controls : MonoBehaviour
{
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UIElements;
public class Player_controls : MonoBehaviour
{
public int forwardMovement = 1000;
public void Update()
{
rb.AddForce(0, 0, forwardMovement * Speed * Time.deltaTime);
}
}
}
Things that I tried:
public void ForwardMovement()
{
forwardMovement = 0;
Invoke("Action", 2f);
}
public void Action ()
{
forwardMovement = 1000 ;
}
Which only works for ForwardMovement(); method nothing else
I tried these two things also:
Public static class MonoExtensions
{
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
public float Delayer = 10f;
public static class MonoExtensions
{
public static void Timed_delay(this MonoBehaviour mono,Action function, float Delayer)
{
mono.StartCoroutine(Timed_delayRoutine(function,Delayer));
}
static IEnumerator Timed_delayRoutine(Action function, float Delayer)
{
yield return new WaitForSeconds(Delayer);
function();
}
public class `Player_Controls`: MonoBehaviour
{
public void PM ()
{
forwardMovement = 0;
}
void OnTriggerEnter(Collider other)
{
if (CompareTag("Power_up"))
{
this.Timed_delay(PM, Delayer);
}
}
}
Which just stop the player from moving an nothing else.
What I also tried was:
public class Player_Controls : MonoBehaviour
{
void Start()
{
StartCoroutine(ForwardMovement());
}
IEnumerator ForwardMovement()
{
forwardMovement = 0;
yield return new waitforseconds(Delayer);
forwardMovement = 1050;
}
void OnTriggerEnter(collider other)
{
if (CompareTag("Power_up"))
{
ForwardMovement();
}
}
}
Which did not work as in(it works but the timer part does nothing, so the player can't move when started the game )
Different way I tried
public class Player_Controls : MonoBehaviour
{
OnTriggerEnter(collider other)
{
Startcroutine(ForwardMovement ));
}
}
it didn't work but no Errors.
I tried this one by jazzhar:
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UIElements;
public class Player_controls : MonoBehaviour
{
// Drag the player in the inspector here;
public Rigidbody rb;
// Youre speed variable for movement.
public float Speed = 5;
// Youre speed variable for movement.
public int forwardMovement = 1000;
// Set this "stopmoving" bool to true to prevent movement.
public bool stopMoving = false;
// Create and select the right layer in the inspector.
public LayerMask WichObjectStopsMovement;
public void Update()
{
// if stopMoving = true than Dont Add force.
if (stopMoving == false)
{
rb.AddForce(0, 0, forwardMovement * Speed * Time.deltaTime);
}
}
private void OnCollisionEnter(Collision collision)
{
// if you're player touches a object and that object's layer
// is the same as "WichObjectStopsMovement" than disable Movement.
if (collision.collider.gameObject.layer == WichObjectStopsMovement)
{
stopMoving = false;
}
}
}
It sorta works in a way if you set if
if (stopMoving == true)
{
rb.AddForce(0, 0, forwardMovement * Speed * Time.deltaTime);
}
and
if (collision.collider.gameObject.layer == WichObjectStopsMovement)
{
stopMoving = true;
}
then the player would be able to move but it will not trigger if hit the cube
it didn't work either but no Errors.
And some other timers I did but forgotten....
_________________________________________________________________March/6/21
public float Delayer = 10.0f;
I think found solution by doing this
private void OnTriggerEnter(Collider other)
{
if (CompareTag("Power_up"))
{
Delayer -= Time.deltaTime; <- this part giving me the error
if (Delayer => 0)
{
forwardMovement = 0;
}
}
}
but their one problem it giving me the this error Cannot convert lambda expression to type 'bool' because it is not a delegate type [Assembly-CSharp]csharp(CS1660) I don't know much about this even searching about doesn't help either
__________________________________________________________________March 28/21
this script is under player controls
this one works I made sure by doing Debug.Log("test");
void OnTriggerExit(Collider collision)
{
if (collision.gameObject.CompareTag("Power_up"))
{
forwardMovement = 0;
}
if (forwardMovement <= 0)
{
Debug.Log("test");
}
This might be a solution to you're problem, Fire-Source!:
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UIElements;
public class Player_controls : MonoBehaviour
{
// Drag the player in the inspector here;
public Rigidbody rb;
// Youre speed variable for movement.
public float Speed = 5;
// Youre speed variable for movement.
public int forwardMovement = 1000;
// Set this "stopmoving" bool to true to prevent movement.
public bool stopMoving = false;
// Create and select the right layer in the inspector.
public LayerMask WichObjectStopsMovement;
public void Update()
{
// if stopMoving = true than Dont Add force.
if (stopMoving == false)
{
rb.AddForce(0, 0, forwardMovement * Speed * Time.deltaTime);
}
}
private void OnCollisionEnter(Collision collision)
{
// if youre player touches a object and that object's layer
// is the same as "WichObjectStopsMovement" than disable Movement.
if (collision.collider.gameObject.layer == WichObjectStopsMovement)
{
stopMoving = false;
}
}
}
This code uses a LayerMask, to create 1 click on any object and in the inspector go:
Click on Layer:
Add Layer:
Write in User Layer 6, StopMovement (or anything else).
Than in the object that should stop player movement:
Click on layer:
Than select the Layer that says StopMovement.
And in you're player's script drag the object into the rb variable.
and in "WichObjectStopsMovement" assign the StopMovement layer.
This should take care of everything is that ok?
So, i created two scripts, one named "Stats.cs" registers the player stats and the other one named "PlayerHealth.cs" "makes" the player take damage on contact and updates the Hearts in the HUD. My problem is, whenever i collide with an object that has a tag named "Projectile" it simply doesn't work, my player doesn't take damage at all. The Stats.cs script isn't in any object, the PlayerHealth.cs is in my Player object.
Stats.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[System.Serializable]
public class Stats{
private int health;
public int maxHP = 3;
public int Health
{
get
{
//Some code
return health;
}
set
{
//Some code
health = Mathf.Clamp(value, 0, maxHP);
}
}
public void SetHealth()
{
Health = maxHP;
}
}
PlayerHealth.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class PlayerHealth : MonoBehaviour
{
Stats playerStats = new Stats();
public int curHealth;
public int numOfHearts = 3;
public Image[] hearts;
public Sprite fullHeart;
public Sprite emptyHeart;
void OnCollisionEnter2D(Collision2D other)
{
if (other.gameObject.CompareTag("Projectile"))
{
Debug.Log("Hello");
DamagePlayer(1);
Destroy(other.gameObject);
}
}
public void DamagePlayer(int damage)
{
playerStats.Health -= damage;
}
// Start is called before the first frame update
void Start()
{
playerStats.SetHealth();
curHealth = numOfHearts;
}
// Update is called once per frame
void Update()
{
curHealth = playerStats.Health;
numOfHearts = playerStats.maxHP;
if (curHealth>numOfHearts){
curHealth = numOfHearts;
}
if(curHealth <= 0){
Die();
}
for (int i = 0; i < hearts.Length; i++)
{
if(i < curHealth){
hearts[i].sprite = fullHeart;
} else
{
hearts[i].sprite = emptyHeart;
}
if(i < numOfHearts){
hearts[i].enabled = true;
} else {
hearts[i].enabled = false;
}
}
}
void Die(){
//Restart
Application.LoadLevel(Application.loadedLevel);
}
}
curHealth is updating so it will stay as the actual Health in Stats and will change the images in HUD.
The Player has a RigidBody2D on him two colliders, one is a box for the body, and the other is a circle collider, so when the player crouches, the circle collider disables.
The Projectiles also have and RigidBody2D with 0 gravity (so it won't fall in mid air) and a BoxCollider2D.
I would check and make sure that the projectile is tagged as Projectile and that the BoxCollider doesn't have "Is Trigger" checked.
I should also say, iterating with that for loop in the Update is very bad practice performance wise. That is happening literally as fast as the machine can loop it and it is doing that every time. I would look into updating it on an event.
Hope this helps!
This question already has answers here:
What is a NullReferenceException, and how do I fix it?
(27 answers)
Closed 4 years ago.
I need help, i'am trying to add float number from a script to another script but it does not work. I'am new to c# and coding in general if somebody code fix the script and explained whats wrong with this i would be very thankful. This is the error i am getting.
"NullReferenceException: Object reference not set to an instance of an object
Resources.Die () (at Assets/Resources.cs:42)
Resources.Update () (at Assets/Resources.cs:22)"
Here is my scripts:
1st
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Resources : MonoBehaviour {
public float maxHealth = 5;
public float currentHealth;
public float ResourceCounter;
public Texture stoneIcon;
public Texture woodIcon;
void Start ()
{
currentHealth = maxHealth;
ResourceCounter = 0;
}
void Update ()
{
Die();
}
public void OnMouseOver()
{
if(Input.GetButtonDown("Fire1"))
{
Debug.Log("Loosing one health");
currentHealth = currentHealth - 1f;
}
}
public void Die()
{
if(currentHealth <= 0)
{
Destroy(gameObject);
Inventory inventory = GetComponent<Inventory>();
inventory.ResourceStone = inventory.ResourceStone + 1;
}
}
}
2nd
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Inventory : MonoBehaviour {
public float ResourceStone;
// Use this for initialization
void Start ()
{
ResourceStone = 0;
}
// Update is called once per frame
void Update () {
}
}
By looking at your code i think you never defined the inventory instance for your "resources" script. If you are using a getcomponent both the resources and the inventory script must be on the same gameobject to be found.
If what you want requires both scripts to be on other gameobjects you need a reference to the inventory in your resources script.
You can do this several way (like making a static reference and refering to it or defining inventory as a public variable and then adding the inventory reference in the unity editor)
This is how the first case would look:
First Script -
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Inventory : MonoBehaviour
{
public static Inventory instance;
private void Awake()
{
instance = this;
}
public float ResourceStone;
// Use this for initialization
void Start()
{
ResourceStone = 0;
}
}
Second Script -
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Resources : MonoBehaviour
{
public float maxHealth = 5;
public float currentHealth;
public float ResourceCounter;
public Texture stoneIcon;
public Texture woodIcon;
void Start()
{
currentHealth = maxHealth;
ResourceCounter = 0;
}
void Update()
{
Die();
}
public void OnMouseOver()
{
if (Input.GetButtonDown("Fire1"))
{
Debug.Log("Loosing one health");
currentHealth = currentHealth - 1f;
}
}
public void Die()
{
if (currentHealth <= 0)
{
Destroy(gameObject);
Inventory.instance.ResourceStone++;
}
}
}
This is how the code would look if you did the second one:
first script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Inventory : MonoBehaviour
{
public float ResourceStone;
// Use this for initialization
void Start()
{
ResourceStone = 0;
}
// Update is called once per frame
void Update()
{
}
}
second script-
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Resources : MonoBehaviour
{
public float maxHealth = 5;
public float currentHealth;
public float ResourceCounter;
public Inventory inventory;
public Texture stoneIcon;
public Texture woodIcon;
void Start()
{
currentHealth = maxHealth;
ResourceCounter = 0;
}
void Update()
{
Die();
}
public void OnMouseOver()
{
if (Input.GetButtonDown("Fire1"))
{
Debug.Log("Loosing one health");
currentHealth = currentHealth - 1f;
}
}
public void Die()
{
if (currentHealth <= 0)
{
Destroy(gameObject);
inventory.ResourceStone++;
}
}
}
Just take in account two things to decide if you will use the first or the second one. The first one is a static reference, that means that you can't make more that one inventory. In the second one you need to manually drag the reference in the editor. Just in case you don't know, writing ++ after an integer does the same as integer = integer + 1;
EDIT: There, that's better looking :D
i'm having problem in the score and high score when i play the game and eat coin its increasing the score and high score but when i die and play again its start counting from the score before i dead like i dead my score was 3 when i play again without closing the game its start counting from 3 and the high score aren't saving
Score Manager script
using UnityEngine;
using UnityEngine.UI;
using System.Collections;
public class ScoreManager : MonoBehaviour
{
public Text scoreText;
public Text hiScoreText;
public static int scoreCount;
public int hiScoreCount;
public bool scoreIncreasing;
// Use this for initialization
void Start()
{
if (PlayerPrefs.HasKey("HighScore"))
{
hiScoreCount = PlayerPrefs.GetInt("HighScore");
}
}
// Update is called once per frame
void Update()
{
if (scoreIncreasing)
{
scoreCount = BallMain.getPoints();
}
if (scoreCount > hiScoreCount)
{
hiScoreCount = scoreCount;
PlayerPrefs.SetFloat("HighScore", hiScoreCount);
}
scoreText.text = "Score: " + (scoreCount);
hiScoreText.text = "High Score: " + (hiScoreCount);
}
}
BallMain Script
using UnityEngine;
using System.Collections;
public static class BallMain {
private static float ballSpeed = 1.2f;
private static int points;
private static int lives = 0;
public enum BallStateEnum { shielded,Vulnerable};
public static BallStateEnum ballState = BallStateEnum.Vulnerable;
public static float getBallSpeed()
{
return ballSpeed;
}
public static void IncreaseSpeed()
{
ballSpeed += 0.1f;
}
public static void IncreasePoints()
{
points++;
}
public static int getPoints()
{
return points;
}
public static int getLive()
{
return lives;
}
public static void addLife()
{
lives++;
}
}
CoinHandler Script
using UnityEngine;
using UnityEngine.UI;
using System.Collections;
public class coinHandler : MonoBehaviour {
public Transform particles;
void OnCollisionEnter2D(Collision2D collider)
{
if (collider.gameObject.tag == "Player")
{
Instantiate(particles, new Vector3(transform.position.x, transform.position.y, -0.2f), Quaternion.identity);
BallMain.IncreaseSpeed();
BallMain.IncreasePoints();
GameObject.FindWithTag("CoinUI").GetComponent<Text>().text = BallMain.getPoints().ToString();
Destroy(gameObject);
}
}
BadCoinHandler Script
using UnityEngine;
using UnityEngine.SceneManagement;
using System.Collections;
public class BadCoinHandler : MonoBehaviour {
public Transform particles;
// Use this for initialization
void Start ()
{
Destroy(gameObject, 8f);
}
void OnCollisionEnter2D(Collision2D collider)
{
if (collider.gameObject.tag == "Player")
{
Instantiate(particles, new Vector3(transform.position.x, transform.position.y, -0.2f), Quaternion.identity);
Destroy(gameObject);
if(BallMain.getLive() == 0 && BallMain.ballState == BallMain.BallStateEnum.Vulnerable)
{
SceneManager.LoadSceneAsync(0);
}
}
}
}
You have to zero the score manually. Because you are using the static keyword. So create another void in BallMain and make the point zero; Example:
public static void ResetPoints()
{
points = 0;
}
And call it on awake method on Score Manager script; Example:
void Awake()
{
scoreCount = 0; //Also the score here
BallMain.ResetPoints();
}
To save your high score use this:
PlayerPrefs.SetInt("HighScore",scoreCount);//HighScore is key and scoreCount is the number you want to save
PlayerPrefs.Save();
BTW I thing you need another void to reset ball speed as well.
I want my player to give a speed boost for a few seconds. When it collects 4 items (paintCount = 4), the player gets a movement speed boost for a short period of time.
I always have an error in the class Paintser: SimplePlayer0.SpeedUp();.
I've tried many things to counter it, but none of them are working.
I'm working in Unity.
Error: An object reference is required for the non-static field, method, or property 'SimplePlayer0.SpeedUp().
This is the players script:
using UnityEngine;
using System.Collections;
public class SimplePlayer0 : MonoBehaviour
{
// SPEEDVARIABLES
public static float speed = 3.5f;
// BONUSSPEED
private static float speedBoostTime;
public static float SpeedBoostTime
{
get
{
return speedBoostTime;
}
set
{
speedBoostTime = value;
}
}
// BONUSSPEED
public void SpeedUp()
{
speed *= 2;
SpeedBoostTime = 3; // seconds
}
void Update()
{
// BONUSSPEED
while (speedBoostTime > 0)
{
speedBoostTime -= Time.deltaTime;
if (speedBoostTime <= 0) speed /= 2;
}
}
This is the power up script, where the gameobject gets destroyed.
using UnityEngine;
using System.Collections;
public class PowerUp : MonoBehaviour
{
void OnTriggerEnter2D(Collider2D other)
{
if (other.tag == "Player")
{
Paintser.ExtraTime();
Destroy(this.gameObject);
Paintser.paintCount++;
}
}
}
And finally the script where all the magic (or errors) happens:
using UnityEngine;
using System.Collections;
public class Paintser : PowerUp
{
public static int paintCount = 0;
public int speedBoostTime = 3;
public static void ExtraTime()
{
if (paintCount == 4)
{
SimplePlayer0.SpeedUp();
Paintser.paintCount = Paintser.paintCount = 0;
}
}
}
SpeedUp method is an instance member of SimplePlayer0 class.
Thus, you need to call it as an instance method:
SimplePlayer0 player0 = new SimplePlayer0();
player0.SpeedUp();