hi creators I'm trying to make my first 3d game so it is going fine tell today when I decide to change the movement script
I'm checking if the player is grounded with OnTriggerEnter(Collider coll) on an empty gameObject attached to the player and it works fine and the player move like I dreamed 'but' after some random moves when testing the variable isGrounded turns false even if the player is grounded something that I'm sure about it
so her is the code I'm using on the gameObject child
using System.Collections.Generic;
using UnityEngine;
public class isGrounded : MonoBehaviour
{
public bool isgrounded=false;
private void OnTriggerEnter(Collider col){
isgrounded=true;
}
private void OnTriggerExit(Collider col){
isgrounded=false;
}
}
and the player movement script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class moves : MonoBehaviour
{
GameObject cam,world;
Rigidbody rd;
bool moveR,moveL,jump,teleport;
// Start is called before the first frame update
void Start()
{
rd=GetComponent<Rigidbody>();
cam=GameObject.Find("Main Camera");
world=GameObject.Find("World");
}
// Update is called once per frame
void Update()
{
if(Input.GetKeyDown(KeyCode.D)){
moveR=true;
} if(Input.GetKeyUp(KeyCode.D)){
moveR=false;
}
if(Input.GetKeyDown(KeyCode.A)){
moveL=true;
}if(Input.GetKeyUp(KeyCode.A)){
moveL=false;
}
if(Input.GetKeyDown(KeyCode.Space)){
jump=true;
}
if(Input.GetKeyUp(KeyCode.Space)){
jump=false;
}
if(Input.GetKeyDown(KeyCode.W)){
teleport=true;
world.GetComponent<Rigidbody>().velocity=new Vector3(0,0,-90);
}
}
void FixedUpdate(){ Debug.Log(isGrounded());
if(moveR==true&&isGrounded()==true){
rd.velocity=new Vector3(5,0,0);
if(jump==true){rd.velocity+=new Vector3(0,5f,0);}
}
if(moveL==true&&isGrounded()==true){
rd.velocity=new Vector3(-5,0,0);
if(jump==true){rd.velocity+=new Vector3(0,5f,0);}
}
if(jump==true&&isGrounded()==true){
rd.velocity+=new Vector3(0,5f,0);
}
}
bool isGrounded(){
return transform.Find("GroundCheck").GetComponent<isGrounded>().isgrounded;
}
}
I really want to know why and be sure I understand the mechanism of this wonderful variable isGrounded turning false while the player is grounded
and also I would like to know if there is a deference between OnTriggerEnter and OnTriggerStay
The issue is that you're checking if an object is grounded via OnTriggerEnter and OnTriggerExit.
You have no possible way to determine that correctly using this method. Instead you should use https://docs.unity3d.com/ScriptReference/Physics.Raycast.html. You can throw the Raycast downwards, check if it hits anything that have a tag corresponding to your ground objects and if yes then you know you're on the ground.
For the second question. The difference between OnTriggerEnter and OnTriggerStay is that OnTriggerEnter is only invoked when one collider enters the other. OnTriggerStay on the other hand is invoked constantly if the colliders are overlapping each other.
Related
I have recently started creating a c# game due to it being a mandatory assignment in my computer science course however i am new to c# and have hit a bump. I have written a Healthbar script so that when my player collides with a gameobject tagged "Enemy" the players health should reduce by 20. However when i press play the health bar visual did not decrease as it should. Like i said i am new to c# so im not too sure how to fix it. I have searched many tutorials however they all gave me the same suggestion of checking to make sure the inspector window of my player and enemy is correct.
After making sure everyting is linked up properly including making the player box collider to " is trigger" and then adding a capsule collider so that it still interacts like a solid object, the code i wrote still didnt work, and whenever i hit my enemy which i tagged as "Enemy" the health bar visual did not change/decrease. I thought that maybe it was just the visual and my health was actually reducing, so to check this i added debugging code to produce a message in the console whether the OnTriggerEnter code was working properly and to my surprise it did not work. I added multiple other debugging code lines as well and none of them showed that anything was working.
This is my player script, giving my player health and allowing the TakeDamage code to run if i enter the enemies collider.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Player : MonoBehaviour
{
public int maxHealth = 100;
public int currentHealth;
public HealthBar healthBar;
// Start is called before the first frame update
void Start()
{
currentHealth = maxHealth;
if (healthBar != null)
{
healthBar.SetMaxHealth(maxHealth);
}
}
// Update is called once per frame
void Update()
{
}
void TakeDamage(int damage)
{
currentHealth -= damage;
if (currentHealth < 0)
{
// Trigger game over event
Debug.Log("Game over!");
}
healthBar.SetHealth(currentHealth);
}
// This function is called when the player collides with an enemy
void OnTriggerEnter(Collider other)
{
Debug.Log("Collision detected!");
if (other.gameObject.tag == "Enemy")
{
// Decrease the player's health by a certain amount
TakeDamage(20);
}
}
}
And this is my healthbar script which should update and decrease based on the value after the TakeDamage line is executed upon collding with the enemy, however no matter what i try, it doesnt seem to update, nor do any debug areas appear in my console, showing that the script isnt detecting the collision between me and my enemy.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class HealthBar : MonoBehaviour
{
public Slider slider;
public Gradient gradient;
public Image fill;
public void SetMaxHealth(int health)
{
slider.maxValue = health;
slider.value = health;
fill.color = gradient.Evaluate(1f);
}
public void SetHealth(int health)
{
slider.value = health;
fill.color = gradient.Evaluate(slider.normalizedValue);
}
}
I am a beginner in Unity and I am currently making a simple game. I have a problem where upon initial collision, the event that I wanted to happen does not trigger or in other words the OnCollisionEnter is not working upon initial collision.
The process of my script is when colliding which is the OnCollisionEnter the button will appear or it will be set active to true. But in the first collision it does not trigger or it is not working, I need to walk away a bit and go back in that way it only works. Sometimes I need to do it 2 or more times for the collider to trigger. I don't know if the script has problem or the collider itself but I made sure it is colliding properly when I look at the editor.
I set the object to static so it will not be pushed when walking and colliding towards it. I wonder if that has to do with this problem because even disabled it is the same. But can anyone give suggestions on how not to make the objects move or be pushed away upon collision?
Here is the script for my collision:
using UnityEngine;
using UnityEngine.UI;
public class InteractNPC : MonoBehaviour
{
//public Button UI;
[SerializeField] GameObject uiUse, nameBtn;
private Transform head;
private Vector3 offset = new Vector3(0, 1.0f, 0);
// Start is called before the first frame update
void Start()
{
//uiUse = Instantiate(UI, FindObjectOfType<Canvas>().transform).GetComponent<Button>();
uiUse.gameObject.SetActive(true);
head = transform.GetChild(0);
uiUse.transform.position = Camera.main.WorldToScreenPoint(head.position + offset);
}
// Update is called once per frame
void Update()
{
uiUse.transform.position = Camera.main.WorldToScreenPoint(head.position + offset);
nameBtn.transform.position = Camera.main.WorldToScreenPoint(head.position + offset);
}
private void OnCollisionEnter(Collision collisionInfo)
{
//Debug.Log("wews2");
if(collisionInfo.collider.name == "Player")
{
nameBtn.gameObject.SetActive(true);
}
}
private void OnCollisionExit(Collision collisionInfo)
{
if(collisionInfo.collider.name == "Player")
{
nameBtn.gameObject.SetActive(false);
}
}
}
Here is another script with collision and has the same problem:
using UnityEngine;
using UnityEngine.UI;
public class InteractButtonPosition : MonoBehaviour
{
//public Button UI;
[SerializeField] GameObject uiUse;
private Vector3 offset = new Vector3(0, 0.5f, 0);
// Start is called before the first frame update
void Start()
{
//uiUse = Instantiate(UI, FindObjectOfType<Canvas>().transform).GetComponent<Button>();
//uiUse = GameObject.FindGameObjectWithTag("ViewButton");
}
// Update is called once per frame
void Update()
{
uiUse.transform.position = Camera.main.WorldToScreenPoint(this.transform.position + offset);
}
private void OnCollisionEnter(Collision collisionInfo)
{
if(collisionInfo.collider.name == "Player")
{
Debug.Log("wews");
uiUse.gameObject.SetActive(true);
}
}
private void OnCollisionExit(Collision collisionInfo)
{
if(collisionInfo.collider.name == "Player")
{
//Destroy(uiUse.gameObject);
uiUse.gameObject.SetActive(false);
}
}
}
Try changing Colision detection from Descrete to Continuous
collission detection
I solved this issue by using OntriggerEnter instead of OnCollisionEnter. In the editor, for the NPC I put a Collider on each part of the body and check the IsTrigger in the parent Object so it will still collide with my character even if the IsTrigger is enabled that will make the character go through the object. I just enlarged the scale of the collider with IsTrigger enabled so the collision will be detected immediately.
I have been doing a tutorial for network games using Unity but I am having trouble with the bullet, whenever I include the private void OnCollision thing, the bullet will not initialise if I press space but if I remove it the bullets will be there but I am trying to avoid the arrays of the bullet (clone) when shooting so I want to destroy the bullet. I used the code
//private void OnCollisionEnter(Collision collision)
//{
// Destroy(gameObject);
//}
In my bullet script that I have created, I have had to comment out the lines as whenever I use this and play the game the space button which shoots the bullets don't work at all.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Bullet : MonoBehaviour
{
Rigidbody rigidbody;
// Start is called before the first frame update
void Awake()
{
rigidbody = GetComponent<Rigidbody>();
}
public void InitializeBullet(Vector3 originalDirection)
{
transform.forward = originalDirection;
rigidbody.velocity = transform.forward * 18f;
}
//private void OnCollisionEnter(Collision collision)
//{
// Destroy(gameObject);
//}
}
This is probably happening due to OnCollisionEnter function gets triggered when the gameobject collides with something. When you instantiate the bullet it probably collides with the player character itself as that also has a collider, thus instantly destroying itself.
A simple solution would be to check the tag of the collided gameobject to make sure that the bullet collided with something that we want it to. So after setting the enemy prefab to have it's own tag your collision code would look like this:
private void OnCollisionEnter(Collision collision)
{
if (collision.gameObject.tag == "Enemy") //I choosed enemy as the custom tag
{
Destroy(gameObject);
}
}
I figured out what went wrong as #66Gramms talked about the bullet colliding with the player character I had another game object called bullet position where I was suppose to put it in front of the player character but instead I didn't do that, the player and bullet were together colliding smh. So the code I used
private void OnCollisionEnter(Collision collision)
{
Destroy(gameObject);
}
Actually works
now, I know the title sounds confusing but let me explain my problem. I have some code that makes a gameobject trigger its animation when it collides with a gameobject with a certain name. is there a way to make it so when my PLAYER collides with a game object, it will trigger a specific gameobjects animation without that specific gameopject having to collide? I want a wall to flip up when my player steps on a cube that acts as my pressure plate. Here is my current code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class WallFlip : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
}
void OnCollisionEnter(Collision collision)
{
if (collision.gameObject.name == "FlipPlate")
{
GetComponent<Animation>().Play("WallFlip");
}
}
}
I think something like this would work if you attach it to the player.
//SerializeField makes it visible in inspector. This is better than making it public bc of encapsulation
[SerializeField]
private GameObject wallThatWillFlip = null;
void OnCollisionEnter(Collider collider)
{
//do note that checking for the name will work but is not generally best practice.
if(collider.gameObject.name == "FlipPlate")
{
wallThatWillFlip.GetComponent<Animation>.Play("WallFlip);
}
}
However, I would put a script like this on the "FlipPlate" that would check for the player instead. This would be a bit neater and would allow you to assign different walls to different FlipPlates if you wanted to do that.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MoveProjectile : MonoBehaviour
{
public Rigidbody2D projectile;
public float moveSpeed = 10.0f;
// Start is called before the first frame update
void Start()
{
projectile = this.gameObject.GetComponent<Rigidbody2D>();
}
// Update is called once per frame
void Update()
{
projectile.velocity = new Vector2(0,1) * moveSpeed;
}
void OnCollisionEnter2D(Collision2D col){
if(col.gameObject.name == "Enemy"){
gameObject.name == "EnemyHeart5".SetActive(false);
}
if(col.gameObject.name == "Top"){
DestroyObject (this.gameObject);
}
}
}
This is the code to my player projectile. On collision i tried to reference it to a game object i have called playerheart and it doesnt seem to work out the way i wanted it to.
Im trying to make a health system where if my bullet collides with the enemy game object the health would decrease by one. Im pretty new to Unity and im confused on how to target the hearts when the bullets collide.
I'm assuming "EnemyHeart5" is a GameObject inside Enemy as child gameobject. Correct?
Issue here is when the collision takes place, it recognize "Enemy" gameobject and won't have access to "EnemyHeart5" for disabling it. I'd suggest you to add simple EnemyManager script into your enemy which manages your enemy health and health related gameobject (ie. EnemyHearts which you are displaying). When collision takes place, access that EnemyManager component and change health value.
void OnCollisionEnter2D(Collision2D col){
if(col.gameObject.tag == "Enemy"){
col.gameObject.GetComponent<EnemyManager>().health =-1;
}
Now, in the update method of EnemyManager you check the health value and disable EnemyHealth5 component.
Also, use "tag" in collision instead of "name". name will create issues when you have multiple enemies in the game. Make sure you add tag in enemy gameobject if you are using it.
Hope this helps, let me know how it goes.