Unity C# float value not decreasing on "OnCollisionEnter2d" - c#

First have a look at my code
using UnityEngine;
using System.Collections;
public class Layer : MonoBehaviour {
public float health=150f;
void OnCollisionEnter2D(Collision2D beam){
if (beam.gameObject.tag == "Box") {
Destroy (gameObject);
}
Projectile enemyship = beam.gameObject.GetComponent<Projectile> (); // Retrieving enemyship
if (enemyship) {
Destroy (gameObject);
health = health - 100f; // its value is decreasing only once
Debug.Log (health);
if (health < 0f || health == 0f) {
Destroy (enemyship.gameObject); // this line not executing
}
}
}
}
In my above code the value of health is decreasing only once but OnCollisionEnter2D is working properly. That means on first collision the health value decreases by 100f and it becomes 50f but when it collides second time it's value is still 50f. And I have been looking since 3 hour for this solution. Please help me
I am adding little more thing. I am firing a projectile(laser) when I pressed space. So when laser hits twice object was supposed to be destroyed

Okay so first thing you're doing wrong is that your collision logic makes no sense at all. Your colliding object is "let's say a mortal object" which has to "die" whenever it's health is lower or equal to 0 but you're destroying it every time it collides with anything that has tag Box or has component of type Projectile.
To fix this first reduce the health based on these condition and then check if you want to destroy that object or not.
example code:
public float health = 150f;
void OnCollisionEnter2D(Collision2D beam)
{
float damage = 0f; // current damage...
if (beam.gameObject.tag == "Box")
{
// Destroy (gameObject); // do not destroy, just remove health
damage = health; // reduce health to 0
}
else
{
Projectile enemyship = beam.gameObject.GetComponent<Projectile> ();
if (enemyship)
{
// Destroy (gameObject); // again do not destroy.. just reduce health
damage = 100f;
}
}
health -= damage;
Debug.Log (health); // print your health
// check if dead
if (health < 0f || health == 0f) {
Destroy (gameObject); // this line not executing
}
}

Related

Why is a console log going off when it's not supposed to?

Basically, I have a system set up where one file has a damage value, and another file has the health.
void Attack()
{
// Detect enemies in range of attack
Collider2D[] hitEnemies = Physics2D.OverlapCircleAll(attackPoint.position, attackRange, enemyLayers);
// Damage them
foreach(Collider2D enemy in hitEnemies)
{
Debug.Log("We hit " + enemy.name);
enemy.GetComponent<Enemy>().TakeDamage(attackDamage);
}
}
it is worth noting that attackDamage is set to 40.
for my enemy script, this is the important code
public class Enemy : MonoBehaviour
{
public int maxHealth = 100;
int currentHealth;
// Start is called before the first frame update
void Start()
{
currentHealth = maxHealth;
}
public void TakeDamage(int damage)
{
currentHealth -= damage;
// Play hurt animation
if (currentHealth <= 0);
{
Die();
}
}
void Die()
{
Debug.Log("Enemy died!");
// Die animation
// Disable the enemy
}
The problem here is that when I run the console and the enemy it says the enemy has 60 health, it still runs the 'Enemy died!', even though that should only happen if it's equal to or under 0. By the way i'm using unity on c#
I believe the most likely issue is hitEnemies contains duplicates or already dead enemies. You can check if the enemy is already dead or not to solve this. You could also use .Distinct to remove duplicates but it will take more time to run the attack method.
Remember, a debugger can be your best friend. Use it to see what is really going on in your game. It will let you trace and follow through your code to see what is happening and why it does things.

I am struggling to get a game object to be destroyed when colliding with the player

I have written code to heal the player after colliding with the health potion and then destroy the potion game object making it one time use, however, the gameobject does not get destroyed and the player is not healed. Code is as shown below:
private void OnCollisionEnter2D(Collision2D collision)
{
if (collision.gameObject.tag == "Player" )
{
playerHealthScript.heal();
Destroy(gameObject);
}
}
}
(code below is in a seperate script, used for player health)
public void heal()
{
currentHealth += healingAmount;
currentHealth = Mathf.Clamp(currentHealth, 0, 100);
healthBar.fillAmount = currentHealth / 100f;
}
Before seek for anything, you should Debug.Log("Collision") in your first function, maybe your code is right but the collision isn't detect.
If so, yo could consideer check if the syntax of "Player" is the same as the tag, or maybe your "Player" doesn't have any rigidbody2D ( 2D is important ! ).

How to Make Enemy Attack When In Range of The Player? [duplicate]

This question already has answers here:
What is a NullReferenceException, and how do I fix it?
(27 answers)
Closed 1 year ago.
So my game is a 2D top down movement game and my script does make my enemy attack but it constantly loops the attack animation because I obviously don't know what EXACTLY to put code wise to make the enemy attack when in range of the player to do damage instead of letting him constantly loop. Also i seem to be getting an error when i get close to my enemy as of right now it says
NullReferenceException: Object reference not set to an instance of an object
EnemyCombat.Attack () (at Assets/EnemyCombat.cs:36)
EnemyCombat.Update () (at Assets/EnemyCombat.cs:25)
Also, Here is the EnemyCombat script
enemy attausing System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EnemyCombat : MonoBehaviour
{
public Animator animator;
public Transform AttackPoint;
public float attackRange = 0.5f;
public LayerMask enemyLayers;
public int attackDamage = 5;
public float attackRate = 2f;
float nextAttackTime = 0f;
// Update is called once per frame
void Update()
{
if (Time.time >= nextAttackTime)
{
Attack();
nextAttackTime = Time.time + 1f / attackRate;
}
}
void Attack()
{
animator.SetTrigger("Attack");
Collider2D[] hitEnemies = Physics2D.OverlapCircleAll(AttackPoint.position, attackRange, enemyLayers);
foreach (Collider2D enemy in hitEnemies)
{
enemy.GetComponent<Enemy>().TakeDamage(attackDamage);
}
}
void OnDrawGizmosSelected()
{
if (AttackPoint == null)
return;
Gizmos.DrawWireSphere(AttackPoint.position, attackRange);
}
}
To fix your endless attack loop:
// Update is called once per frame
void Update()
{
if (attackRate >= nextAttackTime) /* checks that nextAttackTime is less than or equal to the attackRate */
{
Attack();
nextAttackTime = Time.deltaTime * 5f; // adds 5 seconds to nextAttackTime
}
else
{
nextAttackTime -= Time.deltaTime; /* if nextAttackTime is greater than the attackRate, subtract one from nextAttackTime. this only happens once per second because you use Time.deltaTime */
}
}
From that NullReference Error it looks like the major problem you're having is that there is no actual point in the code or in the game hierarchy that you are telling your script which gameObject it is referring to.
Line 36 is trying to retrieve that information with .GetComponent<Enemy()>, so you need to provide that reference.
You could do this in the script fairly easily by creating a public variable that you can drag the enemy gameObject into in your hierarchy in Unity.
Try something like:
public GameObject enemyObject;
This will create a variable in the script visible in the hierarchy when you select the script which you can drag the appropriate gameObject into.
There might need to be some adjustments to it because I can't see the rest of your code, but this seems to be the issue.
Another option would be trying to manually adding it in:
void Start()
{
GameObject enemyObject = gameObject.GetComponent<Enemy>();
}
this is taken from Unity Scripting Documentation

Ball shaking upon increasing its speed in Unity

I'm a beginner. I'm making a ball game in Unity, in which ball have to avoid the collision with the obstacle. In the game, I'm increasing the ball speed in every 3 seconds. Everything's working fine, but in the middle of game, I noticed the ball starts shaking, the speed decreases, and the camera can't catch the ball. I attached physics material to all gameobjects, and made all frictions zero, but the ball is still shaking.
Here is the link of the my game and the problem. Have a look: https://youtu.be/TR4M5whweTk
Here is the script attached to the ball:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
public class PlayerController : MonoBehaviour
{
public Text gameOverText;
public Text scoreText;
public bool isGameOver;
public float speeder;
public float Score;
Touch touch;
public float speedmodifier ;
public float speed = 5;
// Start is called before the first frame update
private void Awake()
{
isGameOver = false;
Score = 0;
if(PlayerPrefs.GetFloat("HighScore") == 0)
{
PlayerPrefs.SetFloat("HighScore", 0);
}
PlayerPrefs.SetFloat("Score", Score);
}
void Start()
{
speeder = 4f;
gameOverText.enabled = false;
speedmodifier = 0.01f;
// GetComponent<Rigidbody>().velocity = new Vector3(0,0,speed);
}
// Update is called once per frame
void Update()
{ if(speeder >= 0)
{
speeder -= Time.deltaTime;
}
if (speeder<= 0 && speed < 50)
{
speed++;
speeder = 4f;
}
Debug.Log(speed);
if (isGameOver == false)
{
Score++;
}
scoreText.text = "Score : " + Score ;
if (Input.touchCount >0 && transform.position.x >= -3.5f && transform.position.x <= 3.5f)
{
touch = Input.GetTouch(0);
transform.Translate(touch.deltaPosition.x * speedmodifier,0,0);
}
else if(transform.position.x > 3.5f)
{
transform.position = new Vector3(3.49f,transform.position.y,transform.position.z);
}
else if(transform.position.x < -3.5f)
{
transform.position = new Vector3(-3.49f,transform.position.y,transform.position.z) ;
}
if (Input.GetKey(KeyCode.RightArrow) && transform.position.x < 3.5f)
{
transform.Translate(Vector3.right*speed* Time.deltaTime);
}
if (Input.GetKey(KeyCode.LeftArrow) && transform.position.x >-3.5f)
{
transform.Translate(Vector3.left*speed* Time.deltaTime);
}
transform.Translate(Vector3.forward * speed * Time.deltaTime);
}
private void OnTriggerEnter(Collider other)
{
if(other.gameObject.tag == "enemy")
{
isGameOver = true;
StartCoroutine("Wait");
GetComponent<MeshRenderer>().enabled = false;
gameObject.GetComponentInChildren<TrailRenderer>().enabled = false;
gameOverText.enabled = true;
if(PlayerPrefs.GetFloat("HighScore") < Score)
{
PlayerPrefs.SetFloat("HighScore", Score);
PlayerPrefs.SetFloat("Score", Score);
}
else
{
PlayerPrefs.SetFloat("Score", Score);
}
}
}
IEnumerator Wait()
{
Debug.Log(" My HighScore is : " + PlayerPrefs.GetFloat("HighScore"));
Debug.Log(" Score is : " + PlayerPrefs.GetFloat("Score"));
yield return new WaitForSeconds(3f);
SceneManager.LoadScene(1);
}
}
As BugFinder pointed out you are actually not moving the ball with physics, but just teleporting the ball with Transform.Translate which might be affecting the shacking issue, the other possible problem is that your ball speed might be varying due to a collision with the road, have you tried making the road RigidBody to Kinematic? so it won't affect the speed of the ball
OK you SHOULD NOT be using unity phsyics for this.
It's a "raster" game (and that's fun).
remove all physics everything. completely remove rigidbody, collider, etc
simply move the ball and/or scenery using a calculation each time.
(It's basically just frame time * speed, obviously.)
(Note, you can use strictly triggers - if you want - simply to know if the "ball" is near a "stick". But you can do that with 1 line of code, really no need for colliders/etc.)
Your Question
I just want to make sure that I am understanding your question correctly first, I believe you are asking for a way to prevent the ball from shaking during the game. (Let me know if this is incorrect, if so I apologize). From what I have gathered, this does not seem like a code based issue
Collision Detection
In unity, the rigidbody component has a field named 'Collision Detection' and this is set to discrete by default. This means that unity will look in direction of travel for a possible collider every now and again. That is an okay method to use when trying to save computer resources, however when in constant contact or at high velocities it is best to use the 'continuous' mode. This will check for a collision every physics update which occurs every physics time-step.
Colliders
Colliders in unity are a little finicky. Most notorious are mesh colliders as they have to be more heavenly processed/calculated. Using a box collider for your ground might give more accurate physics results.
Other Solutions
Whilst looking at your game video you published on YouTube, it looks like using physics may not be able to work. Since you are only traveling left, right, and forward globally, I would suggest implementing a movement script that uses an object's transform component instead of physics. This will be less resource intensive and will save further debugging headaches in the long run.

unity 2D: simple enemy shooting

I'm working on a 2D game. If I wanted a simple enemy canon shooting side to side every 5 seconds, how would I go about it ?
I know that I would need to add a colider and rigidbody but not quite sure how to approach this, since am still grasping the whole idea
Red = Enemy/ Rough idea/Sketch
Thank you
What you want is to create a type of gameobject to be used as a 'bullet'. This gameobject when spawned has a script on it to make it travel in a certain direction.
You can move them using force (physics) or you can translate them from one place to another which is to move them 'absolutely' and ignore physics in the environment.
Then you can use a collider on this object to detect when it hits the player using either the OnCollisionEnter method or the OnTriggerEnter method.
There are some tutorials on it here so I hope they help.
Creating Shooting
First you need to think how your enemy should behavior, Just walk side by side or find the enemy as Navmesh.
I found this scritpt on unity website:
using UnityEngine;
using System.Collections;
public class EnemyAttack : MonoBehaviour
{
public float timeBetweenAttacks = 0.5f; // The time in seconds between each attack.
public int attackDamage = 10; // The amount of health taken away per attack.
Animator anim; // Reference to the animator component.
GameObject player; // Reference to the player GameObject.
PlayerHealth playerHealth; // Reference to the player's health.
EnemyHealth enemyHealth; // Reference to this enemy's health.
bool playerInRange; // Whether player is within the trigger collider and can be attacked.
float timer; // Timer for counting up to the next attack.
void Awake ()
{
player = GameObject.FindGameObjectWithTag ("Player");
playerHealth = player.GetComponent <PlayerHealth> ();
enemyHealth = GetComponent<EnemyHealth>();
anim = GetComponent <Animator> ();
}
//OntriggerEnter and On triggerExit the enemy will follow enemy everytime the player enter on collide and stop if player exit
void OnTriggerEnter (Collider other)
{
// If the entering collider is the player...
if(other.gameObject == player)
{
// ... the player is in range.
playerInRange = true;
}
}
void OnTriggerExit (Collider other)
{
// If the exiting collider is the player...
if(other.gameObject == player)
{
// ... the player is no longer in range.
playerInRange = false;
}
}
void Update ()
{
// Add the time since Update was last called to the timer.
timer += Time.deltaTime;
// If the timer exceeds the time between attacks, the player is in range and this enemy is alive...
if(timer >= timeBetweenAttacks && playerInRange && enemyHealth.currentHealth > 0)
{
// ... attack.
Attack ();
}
// If the player has zero or less health...
if(playerHealth.currentHealth <= 0)
{
// ... tell the animator the player is dead.
anim.SetTrigger ("PlayerDead");
}
}
void Attack ()
{
// Reset the timer.
timer = 0f;
// If the player has health to lose...
if(playerHealth.currentHealth > 0)
{
// ... damage the player.
playerHealth.TakeDamage (attackDamage);
}
}
}

Categories