Why won't AddExplosionForce work in my code? - c#

What is wrong with this code? When i fire the Rocket, it does not effect the character.
I have tried Looking other places etc but nothing really helps. I already got help so now at least the code actually runs.
using UnityEngine;
using System.Collections;
public class Rocket : MonoBehaviour
{
//Public changable things
public float speed = 20.0f;
public float life = 5.0f;
public float explosionForce = 1.0f;
public float explosionRadius = 1.0f;
public bool isGrounded;
public Rigidbody rb;
// Use this for initialization
void Start()
{
Invoke("Kill", life);
}
// Update is called once per frame
void Update()
{
transform.position += transform.forward * speed * Time.deltaTime;
if (isGrounded)
{
Kill();
}
}
void OnCollisionEnter(Collision other)
{
if (other.gameObject.tag == "Ground")
{
isGrounded = true;
}
}
//
void OnCollisionExit(Collision other)
{
if (other.gameObject.tag == "Ground")
{
isGrounded = false;
}
}
//Explosion code
void Kill()
{
Vector3 explosionCenterPosition = transform.position;
rb.AddExplosionForce(explosionForce, explosionCenterPosition, explosionRadius);
Destroy(gameObject);
}
}
I am making a game where you rocket jump like TF2. It should also move other rigidbodys like described here:
https://docs.unity3d.com/ScriptReference/Rigidbody.AddExplosionForce.html
I'm new to unity and have no clue why this won't work.

#bobshellby
you are destroying the rocket object in the same frame that you are applying the explosion force. so before you see the explosion effects the rocket will be destroyed.
Try using coroutine for the kill function, that way you can add wait time.
void Start()
{
//Invoke("Kill", life);
}
// Update is called once per frame
void Update()
{
transform.position += transform.forward * speed * Time.deltaTime;
if (isGrounded)
{
StartCoroutine( Kill());
}
}
void OnCollisionEnter(Collision other)
{
if (other.gameObject.tag == "Ground")
{
isGrounded = true;
}
}
//
void OnCollisionExit(Collision other)
{
if (other.gameObject.tag == "Ground")
{
isGrounded = false;
}
}
//Explosion code
IEnumerator Kill()
{
Vector3 explosionCenterPosition = transform.position;
rb.AddExplosionForce(explosionForce, explosionCenterPosition, explosionRadius);
yield return new WaitForSeconds(2f);
Destroy(gameObject);
}
The other thing is you are invoking the kill function after 5second in start itself which again destroy the rocket. Remove that, as you are already checking it in update if the rocket has hit the ground or not.

Related

Problems with OnCollisionEnter2D & OnCollisionExit2D

I'm trying to make the Player not jump continuously so I use isOnGrounded variable to check if the player is on the ground or not. Here is my code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
public class PlayerController : MonoBehaviour
{
//REFERENCES
private Rigidbody2D rb2D;
//VARIABLES
[SerializeField] float moveSpeed = 0;
private float moveX;
[SerializeField] bool isOnGrounded = true;
[SerializeField] float jumpY;
// Start is called before the first frame update
void Start()
{
rb2D = GetComponent<Rigidbody2D>();
}
// Update is called once per frame
void Update()
{
moveX = Input.GetAxis("Horizontal");
PlayerJump();
}
private void FixedUpdate()
{
PlayerMove();
}
void PlayerMove()
{
rb2D.velocity = new Vector2(moveX * moveSpeed * Time.fixedDeltaTime, rb2D.velocity.y);
}
void PlayerJump()
{
if (Input.GetKeyDown(KeyCode.Space) && isOnGrounded == true)
{
rb2D.AddForce(new Vector2(rb2D.velocity.x, jumpY));
}
}
private void OnCollisionEnter2D(Collision2D other)
{
if (other.gameObject.CompareTag("Ground"))
{
isOnGrounded = true;
}
}
private void OnCollisionExit2D(Collision2D other)
{
if (other.gameObject.CompareTag("Ground"))
{
isOnGrounded = false;
}
}
}
The problem is when the Player is standing on Platform01 so obviously isOnGrounded = true and when the Player moves out of Platform01 isOnGrounded = false, I suppose when move in Platform02 it will automatically check the Ground and isOnGrounded = true but it still false and everything just messing up.
This is because OnCollisionEnter2D(Platform02) is triggered before OnCollisionExit2D(Platform01).
You can remember the last hit collider and compare with it when leave a platform.
public class PlayerController : MonoBehaviour
{
private Collision2D ground;
public bool IsGround => (bool)ground;
private void OnCollisionEnter2D(Collision2D other)
{
if (other.gameObject.CompareTag("Ground"))
{
ground = other;
}
}
private void OnCollisionExit2D(Collision2D other)
{
if (other.gameObject.CompareTag("Ground") && other == ground)
{
ground = null;
}
}
}

Jumping only once

I'm having some issues with a coding on C# (Unity); I'm trying to make my character move and jump with space. But for some reason, the character jumps once, and when reaching the ground once again, it stops jumping! Could anyone help me? I tried to check and uncheck "Is jumping" and "Double Jump" on Unity, but nothing seems to work D:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Player : MonoBehaviour {
public float Speed;
public float JumpForce;
public bool isJumping;
public bool doubleJump;
private Rigidbody2D rig;
// Use this for initialization
void Start () {
rig = GetComponent<Rigidbody2D>();
}
// Update is called once per frame
void Update () {
Move();
Jump();
}
void Move () {
Vector3 movement = new Vector3(Input.GetAxis("Horizontal"), 0f, 0f);
transform.position += movement * Time.deltaTime * Speed;
}
void Jump () {
if(Input.GetButtonDown("Jump"))
{
if(!isJumping){
rig.AddForce(new Vector2(0f, JumpForce), ForceMode2D.Impulse);
doubleJump = true;
}else{
if(doubleJump){
rig.AddForce(new Vector2(0f, JumpForce), ForceMode2D.Impulse);
doubleJump = false;
}
}
}
}
void OnCollisionEnter2D(Collision2D collision){
if(collision.gameObject.layer == 8)
{
isJumping = false;
}
}
void OnCollisionExit2D(Collision2D collision){
if(collision.gameObject.layer == 8){
isJumping = true;
}
}
}
Your logic in Jump() seems sound, so what i'm guessing is that isJumping is not being set correctly. It could be that you're on the ground, then jump onto a platform that is not on layer 8. In that case OnCollisionEnter2D will never get called to set your IsJumping value.
void OnCollisionEnter2D(Collision2D collision){
if(collision.gameObject.layer == 8)
{
isJumping = false;
}
}
void OnCollisionExit2D(Collision2D collision){
if(collision.gameObject.layer == 8){
isJumping = true;
}
}
I've edited your code a bit to make it a little more readable (although some of it is taste) and added some general tips.
using System.Collections.Generic;
using UnityEngine;
// Add https://docs.unity3d.com/ScriptReference/RequireComponent.html
[RequireComponent(typeof(Rigidbody))]
public class Player : MonoBehaviour {
public float Speed;
public float JumpForce;
// Naming of booleans should follow guidelines: https://learn.microsoft.com/en-us/dotnet/standard/design-guidelines/names-of-type-members#names-of-properties
public bool IsGrounded;
public bool HasDoubleJumped;
private Rigidbody2D rig;
// Use this for initialization
void Start () {
// Another tip, just write out variable names and don't shorten them (again see the guidelines).
rig = GetComponent<Rigidbody2D>();
}
// Update is called once per frame
void Update () {
Move();
JumpCheck();
}
void Move () {
// Some tips
// A) try to move any physiscs related movement to fixedUpdate
// B) try to use .AddForce() to move objects with a rigidbody NOT using transform.position. See: https://docs.unity3d.com/ScriptReference/Rigidbody.html
Vector3 movement = new Vector3(Input.GetAxis("Horizontal"), 0f, 0f);
transform.position += movement * Time.deltaTime * Speed;
}
void JumpCheck () {
if(Input.GetButtonDown("Jump"))
{
// Jump if we're grounded
if(IsGrounded)
{
Jump();
HasDoubleJumped = false;
}
// Jump if we're in the air (!IsGrounded) and we haven't double jumped yet.
else if(!HasDoubleJumped)
{
Jump();
HasDoubleJumped = true;
}
else
{
// We're in the air and we've double jumped, do nothing!
}
}
}
private void Jump() =>
rig.AddForce(new Vector2(0f, JumpForce), ForceMode2D.Impulse);
void OnCollisionEnter2D(Collision2D collision){
if(collision.gameObject.layer == 8)
{
IsGrounded = true;
}
}
void OnCollisionExit2D(Collision2D collision){
if(collision.gameObject.layer == 8){
IsGrounded = false;
}
}
}

How do I make my player speed up when collide with a game object in Unity?

I am doing a school project in Unity. My team and I decided to make an endless runner 2D game. However, because it is the first time I use C#, I don't know how to make my player's speed accelerate when collide with a game object in Unity. I only know how to destroy the player's health when a collision happens. Please help me! Thank you!
it's quite hard to give answers without seeing any code you've written, but as it's 2D and you've already got the collision damage working, you've probably used an OnCollisionEnter(), well it's very similar: you test if you've collided (which you've already done), then you add force to your player using a rigidbody2d, probably something along the lines of:
public Rigidbody2D rb;
void OnCollisionEnter2D(Collision2D collision)
{
rb.AddForce(direction * force, ForceMode2D.Impulse); // the ForceMode2D is
// optional, it's just so that
// the velocity change is sudden.
}
This should work.
If you have a GameManager that stores the game speed you can also do that too:
private float gameSpeedMultiplier = 0.5f;
void OnCollisionEnter(Collision collision)
{
if(collision.gameObject.CompareTag("Tag of the collided object")
{
GameManager.Instance.gameSpeed += gameSpeedMultiplier;
}
}
public class PlayerContoler : MonoBehaviour
{
public static PlayerContoler instance;
public float moveSpeed;
public Rigidbody2D theRB;
public float jumpForce;
private bool isGrounded;
public Transform GroundCheckPoint;
public LayerMask whatIsGround;
private bool canDoubleJump;
private Animator anim;
private SpriteRenderer theSR;
public float KnockbackLength, KnockbackForce;
private float KnockbackCounter;
public float bonceForce;
public bool stopImput;
private void Awake()
{
instance = this;
}
// Start is called before the first frame update
void Start()
{
anim = GetComponent<Animator>();
theSR = GetComponent<SpriteRenderer>();
}
// Update is called once per frame
void Update()
{
if(!PauseMenu.instance.isPause && !stopImput)
{
if (KnockbackCounter <= 0)
{
theRB.velocity = new Vector2(moveSpeed * Input.GetAxis("Horizontal"), theRB.velocity.y);
isGrounded = Physics2D.OverlapCircle(GroundCheckPoint.position, .2f, whatIsGround);
if (isGrounded)
{
canDoubleJump = true;
}
if (Input.GetButtonDown("Jump"))
{
if (isGrounded)
{
theRB.velocity = new Vector2(theRB.velocity.x, jumpForce);
AudioManager.instance.PlaySFX(10);
}
else
{
if (canDoubleJump)
{
theRB.velocity = new Vector2(theRB.velocity.x, jumpForce);
canDoubleJump = false;
AudioManager.instance.PlaySFX(10);
}
}
}
if (theRB.velocity.x < 0)
{
theSR.flipX = true;
}
else if (theRB.velocity.x > 0)
{
theSR.flipX = false;
}
} else
{
KnockbackCounter -= Time.deltaTime;
if(!theSR.flipX)
{
theRB.velocity = new Vector2(-KnockbackForce, theRB.velocity.y);
} else
{
theRB.velocity = new Vector2(KnockbackForce, theRB.velocity.y);
}
}
}
anim.SetFloat("moveSpeed", Mathf.Abs(theRB.velocity.x));
anim.SetBool("isGrounded", isGrounded);
}
public void Knockback()
{
KnockbackCounter = KnockbackLength;
theRB.velocity = new Vector2(0f, KnockbackForce);
anim.SetTrigger("hurt");
}
}

Power-Ups increasing projectile stats

I am trying to increase the damage of the players fireball when a power up is picked up. I am getting an object reference error, I'm pretty sure this is due to the code being linked tot he player for the collision and the fireballs have their own script detailing their speed, damage etc.
Essentially I need a way to reference my fireball prefab (Called Bullet) so the code can access the 'damage' stat and increase it for a period of time.
The code for the power-up is:-
private void OnTriggerEnter2D(Collider2D other)
{
if (other.CompareTag("Player"))
{
Pickup(other);
}
}
void Pickup(Collider2D player)
{
Instantiate(pickupEffect, transform.position, transform.rotation);
Fire stats = GetComponent<Fire>();
stats.damage *= 2;
Destroy(gameObject);
}
}
**The code for the fireball prefabs (known as Fire) is:-**
public class Fire : MonoBehaviour
{
public Animator animator;
public float speed = 20f;
public int damage = 30;
public Rigidbody2D rb;
public GameObject FireEmbers;
public float liveTime = 1f;
// Start is called before the first frame update
void Start()
{
rb.velocity = transform.right * speed;
}
void OnTriggerEnter2D(Collider2D hitInfo)
{
Enemy enemy = hitInfo.GetComponent<Enemy>();
if (enemy != null)
{
enemy.TakeDamage(damage);
}
Destroy(gameObject);
Instantiate(FireEmbers, transform.position, Quaternion.identity);
}
void Update()
{
liveTime -= Time.deltaTime;
if (liveTime <= 0)
{
Destroy(this.gameObject);
Instantiate(FireEmbers, transform.position, Quaternion.identity);
}
}
}
I actually resolved this by using scriptable objects instead of hard coding things into prefabs.

How do I stop enemies from spawning in Unity 3D?

I want to stop enemies from spawning when one of them hit the "finish" tag.
Here's the script which spawn enemies:
public class spawn : MonoBehaviour {
public GameObject enemy;
private float spawnpoint;
public float xlimit = 12f;
float spawnNewEnemyTimer = 1f;
void Start()
{
}
public void Update()
{
spawnNewEnemyTimer -= Time.deltaTime;
if (spawnNewEnemyTimer <= 0 )
{
spawnNewEnemyTimer = 3;
GameObject nemico = Instantiate(enemy);
}
}
Here's the script which make the enemies appear at random point and move:
public class nemici : MonoBehaviour {
float speed = 4f;
public GameObject enemy;
public float xlimit = 12f;
private float currentPosition;
public GameObject spawn;
bool endGame = false;
void Start()
{
if (endGame == false)
{
Vector3 newPosition = transform.position;
newPosition.x = Random.Range(-xlimit, xlimit);
transform.position = newPosition;
}
else if (endGame == true)
{
return;
}
}
void Update()
{
if (endGame == false)
{
//per farlo muovere verso il basso
Vector3 movimento = new Vector3(0f, -speed, 0f); //(x, y, z)
transform.position += movimento * Time.deltaTime;
}
else if (endGame == true)
{
return;
}
}
void OnTriggerEnter(Collider other)
{
if (other.tag == "Player")
{
Destroy(enemy);
}
else if (other.tag == "Finish")
{
Debug.Log("hai perso!");
endGame = true;
}
}
}
What's wrong with this code? Thanks!
The logic that spawns new enemies is in the spawn class. The logic that decides whether you should stop spawning enemies, resides on the enemy class.
You are succesfully setting the endgame boolean to true whenever you want enemies to stop spawning when they hit an object with the finish tag.
void OnTriggerEnter(Collider other){
if (other.tag == "Finish"){
Debug.Log("hai perso!");
endGame = true;
}
}
Great! But you are not actually using it to stop spawns.
So far this variable is local to each enemy. So if you include checks in the start and update functions, they will only activate for the specific enemy that touched touched the finish object. This is not what you want.
You want the Spawn class to check the endgame variable, and if it is active, to stop spawning enemies.
To do this you will have to somehow be able to access the endgame variable from Spawn, What I recommend is that you make the endGame variable a member of te Spawn class. And that you include a reference to the Spawn in each enemy.
All together it might look something like this:
public class Spawn: MonoBehaviour{
public boolean endgame = false;
GameObject nemico = Instantiate(Enemy);
nemico.ParentSpawn = this
}
public class Enemy: MonoBehaviour{
public Spawn spawn;
void OnTriggerEnter(Collider other){
if (other.tag == "Finish"){
Spawn.endGame = true;
}
}
}
And then you can use the endgame boolean from within Spawn to check if you should keep spawning enemies.

Categories

Resources