Play animator on collider enter - c#

I have wrote a code that semi-works for me. Everything works aside from working animation.
What I'm trying to do is that when Player enters trigger, and if he/she presses E it will perform an animation. (Animation is working fine btw, so it's just code error?).
Here's what I got so far:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class barTrigger : MonoBehaviour {
// press shit to drink text
public GameObject drinkText;
// bottle
public GameObject alcBottle;
// drink animator
public GameObject animatorOjbect;
Animator drinkAmin;
public bool triggerIsOn;
// Use this for initialization
void Start () {
drinkAmin = animatorOjbect.GetComponent<Animator> ();
drinkText.SetActive(false);
alcBottle.SetActive(false);
}
// Update is called once per frame
void Update () {
}
void OnTriggerEnter(Collider other){
triggerIsOn = true;
if (other.gameObject.name == "vThirdPersonController") {
drinkText.SetActive (true);
}
if (triggerIsOn && Input.GetKeyDown (KeyCode.E)) {
drinkAmin.Play ("Dab");
alcBottle.SetActive (true);
}
}
void OnTriggerExit(Collider other){
if (other.gameObject.name == "vThirdPersonController") {
drinkText.SetActive (false);
alcBottle.SetActive (false);
}
}
}

OnTriggerEnter is called once and it will be hard to get press the E button and get Input.GetKeyDown(KeyCode.E) to detect that at the-same time. Checking the E input in the OnTriggerStay function is more appropriate for this but OnTriggerStay does not work sometimes so count it out. Although it's worth knowing that it exist.
Move Input.GetKeyDown(KeyCode.E) to the Update function which is called every frame then set it to true in the OnTriggerEnter function and false in the OnTriggerExit function. Below are the code that should be changed.
void Update()
{
if (triggerIsOn && Input.GetKeyDown(KeyCode.E))
{
Debug.Log("E button pressed");
drinkAmin.Play("Dab");
alcBottle.SetActive(true);
}
}
void OnTriggerEnter(Collider other)
{
if (other.gameObject.name == "vThirdPersonController")
{
Debug.Log("Detected vThirdPersonController");
triggerIsOn = true;
drinkText.SetActive(true);
}
}
void OnTriggerExit(Collider other)
{
if (other.gameObject.name == "vThirdPersonController")
{
Debug.Log("Lost vThirdPersonController");
triggerIsOn = false;
drinkText.SetActive(false);
alcBottle.SetActive(false);
}
}
Once you get that working, starting using the CompareTag function instead of gameObject.name as that is more proficient.

Related

Unity 2D RPG Healing from Potions

I'm currently developing developing a 2d top-down RPG game in Unity.
I am trying to implement a healing system where you heal some points when you buy a coffee. This is my healthManager:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class HealthManager : MonoBehaviour
{
public int maxHealth = 10;
public int currentHealth;
public HealthBarScript healthBar;
void Start()
{
currentHealth = maxHealth;
healthBar.SetMaxHealth(maxHealth);
}
void Update()
{
if(Input.GetKeyDown(KeyCode.Space))
{
TakeDamage(1);
}
}
public void TakeDamage(int damage)
{
currentHealth -= damage;
healthBar.SetHealth(currentHealth);
if(currentHealth <= 0)
{
currentHealth = 0;
}
}
public void heal(int heal)
{
currentHealth += heal;
healthBar.SetHealth(currentHealth);
if(currentHealth >= maxHealth)
{
currentHealth = maxHealth;
}
}
}
And this is the script to buy coffee from a game object (sth. like a healing fountain):
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class KaffeeautomatDialog : MonoBehaviour
{
public GameObject dialogBox;
public Text dialogText;
public string dialog;
public bool playerInRange;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
if(Input.GetKeyDown(KeyCode.E) && playerInRange)
{
if(dialogBox.activeInHierarchy)
{
dialogBox.SetActive(false);
}
else
{
dialogBox.SetActive(true);
dialogText.text = dialog;
}
}
}
public void OnTriggerEnter2D(Collider2D other)
{
if (other.CompareTag("Player"))
{
Debug.Log("Player entered");
playerInRange = true;
var healthManager = other.GetComponent<HealthManager>();
if(Input.GetKeyDown(KeyCode.J) && playerInRange)
{
if(healthManager != null)
{
healthManager.heal(5);
Debug.Log("You healed 5 Points!");
}
}
}
}
public void OnTriggerExit2D(Collider2D other)
{
if (other.CompareTag("Player"))
{
Debug.Log("Player left");
playerInRange = false;
dialogBox.SetActive(false);
}
}
}
The Dialog Box shows up just fine and the Text is displayed. When i am staning in front of the healing fountain, i can activate and deactivate the dialog box by pressing "e".
But when i press "j", i don't heal and the console.log won't appear in Unity.
Did i mess up the Component import?
Checking for an Input it should always happen inside the Update() method and not inside the OnTriggerEnter2D() because the OnTriggerEnter2D() method it will only executed everytime something gets inside the trigger which might happen only onces. On the other hand Update() it will be executed every single frame and check for an Input.
What you can do is the following, inside your OnTriggerEnter2D() method you need to have a global boolean variable that indicates that the player has entered the trigger and inside your Update() method when you check for the Input key "J" you need to check if the above boolean flag is true, if it is true then continue with the heal process. Also you need to make the flag false when the player exit the trigger.
From what I see you already have such flag playerInRange, you can write the following code:
public HealthManager healthManager;
void Update()
{
if(playerInRange)
{
if(Input.GetKeyDown(KeyCode.E))
{
if(dialogBox.activeInHierarchy)
{
dialogBox.SetActive(false);
}
else
{
dialogBox.SetActive(true);
dialogText.text = dialog;
}
}
if(Input.GetKeyDown(KeyCode.E))
{
if(healthManager != null)
{
healthManager.heal(5);
Debug.Log("You healed 5 Points!");
}
}
}
}
public void OnTriggerEnter2D(Collider2D other)
{
if (other.CompareTag("Player"))
{
Debug.Log("Player entered");
playerInRange = true;
healthManager = other.GetComponent<HealthManager>();
}
}
Remove the Input check from your OnTriggerEnter2D() method.

The scene change script for my unity project is not working, I cant understand why

Here is the code for the same.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class changescene : MonoBehaviour
{
private void OnTriggerEnter(Collider other)
{
if (other.CompareTag("Player"))
{
if(Input.GetKeyDown(KeyCode.Space))
{
SceneManager.LoadScene(1);
}
}
}
}
Running this with a 3D cube tagged player is not changing scenes and neither showing any errors.
Input.GetKeyDown is only true once per key press and only during a single frame where the key went down.
It is extremely unlikely that you press the key down exactly in the FixedUpdate physics all when the trigger enters your collider!
You want to split your physics / collision detection from user input and rather do e.g.
public class changescene : MonoBehaviour
{
private bool isEntered;
private void OnTriggerExit(Collider other)
{
if (!other.CompareTag("Player")) return;
isEntered = false;
}
private void OnTriggerEnter(Collider other)
{
if (!other.CompareTag("Player")) return;
isEntered = true;
}
private void Update()
{
if(isEntered && Input.GetKeyDown(KeyCode.Space))
{
SceneManager.LoadScene(1);
}
}
}
Or if you want to make it a bit more efficient without an Update method that runs most of time unnecessary you can use a Coroutine like e.g.
public class changescene : MonoBehaviour
{
private void OnTriggerExit(Collider other)
{
if (!other.CompareTag("Player")) return;
StartCoroutine(CheckSpaceRoutine());
}
private void OnTriggerEnter(Collider other)
{
if (!other.CompareTag("Player")) return;
StopAllCoroutines();
}
private IEnumerator CheckSpaceRoutine()
{
while(true)
{
if(Input.GetKeyDown(KeyCode.Space))
{
SceneManager.LoadScene(1);
yield break;
}
yield return null;
}
}
}

Invoke Can't Be Called

I am very new to Unity and C#, and am just starting to learn the basics. I made a simple game that has a cube moving forward, and if it hits an obstacle, the game restarts. However, when I try to use Invoke to delay the time after the game restarts when the cube collides, the restart is instant.
I haven't been able to try much since I am still new to C# and Unity.
This is my GameManager script:
using UnityEngine;
using UnityEngine.SceneManagement;
public class GameManager : MonoBehaviour
{
bool gameHasEnded = false;
public float restartDelay = 3f;
public void EndGame()
{
if (gameHasEnded == false)
{
gameHasEnded = true;
Debug.Log("Game Over!");
Invoke("Restart", restartDelay);
Restart();
}
}
void Restart()
{
SceneManager.LoadScene(SceneManager.GetActiveScene().name);
}
}
When the player collides with an object (Obstacle script):
using UnityEngine;
public class PlayerCollision : MonoBehaviour
{
public PlayerMovement movement;
void OnCollisionEnter(Collision collisionInfo)
{
if (collisionInfo.collider.tag == "Obstacle")
{
movement.enabled = false;
FindObjectOfType<GameManager>().EndGame();
}
}
}
I want the restart to be delayed so the game doesn't restart instantly. Any help would be greatly appreciated :)
You called Restart() after invoking the Restart function with a delay.
// ...
if (gameHasEnded == false) {
gameHasEnded = true;
Debug.Log("Game Over!");
Invoke("Restart", restartDelay);
// This below is called instantly.
// It does not wait for the restartDelay.
Restart();
}
// ...
Just simply remove the Restart() call like so:
if (gameHasEnded == false) {
gameHasEnded = true;
Debug.Log("Game Over!");
Invoke("Restart", restartDelay);
}
Note that the code does not 'pause' at Invoke(). Think of Invoke as a async/coroutine operation.

Unity3D using OnTriggerStay

I'm using the event OnTriggerStay2D to destroy an object, the reason i'm using this instead of OnTriggerEnter2D is because i'm dragging the object using the touchscreen, and i want to destroy it after it is released, the problem i have is that OntriggerStay2D is not always called, so sometimes the object is not destroyed after it is released and it has to be moved again to work, i've read the docummentation from Unity
OnTriggerStay is called almost all the frames for every Collider other that is touching the trigger.
public void OnTriggerStay2D(Collider2D other)
{
if (gameObject.tag == other.tag) {
Destroy (other.gameObject);
}
}
I would like to know if there's any way to call OntriggerStay2D everytime i release the object.
Thanks.
Edit
Dragging code
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Drag : MonoBehaviour {
private bool draggingItem = false;
private GameObject draggedObject;
private Vector2 touchOffset;
void Update ()
{
if (HasInput)
{
DragOrPickUp();
}
else
{
if (draggingItem)
DropItem();
}
}
Vector2 CurrentTouchPosition
{
get
{
Vector2 inputPos;
inputPos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
return inputPos;
}
}
private void DragOrPickUp()
{
var inputPosition = CurrentTouchPosition;
if (draggingItem)
{
draggedObject.transform.position = inputPosition + touchOffset;
}
else
{
RaycastHit2D[] touches = Physics2D.RaycastAll(inputPosition, inputPosition, 0.5f);
if (touches.Length > 0)
{
var hit = touches[0];
if (hit.transform != null && hit.rigidbody != null)
{
draggingItem = true;
draggedObject = hit.transform.gameObject;
touchOffset = (Vector2)hit.transform.position - inputPosition;
}
}
}
}
private bool HasInput
{
get
{
return Input.GetMouseButton(0);
}
}
public void DropItem()
{
draggingItem = false;
}
}
Avoid using OnTriggerStay2D for this. You can use a boolean variable that you set to true and false in the OnTriggerEnter2D and OnTriggerExit2D function.
bool isTouching = false;
void OnTriggerEnter2D(Collider2D collision)
{
Debug.Log("Entered");
if (collision.gameObject.CompareTag("YourOtherObject"))
{
isTouching = true;
}
}
void OnTriggerExit2D(Collider2D collision)
{
Debug.Log("Exited");
if (collision.gameObject.CompareTag("YourOtherObject"))
{
isTouching = false;
}
}
You can now check the isTouching variable when the object is released.
if(isTouching){
....
}
Note that I suggest you abandon your current code that uses Raycast and Input.GetMouseButton(0); since you are using this on mobile devices too. You should be using Unity's new EventSystem for this since it is made to be mobile friendly too.
Since you are using 2D collider, see #7 from this answer.
Here is a complete example of how to drag a Sprite with the new EventSystem. Combine that with the answer above and you get a much more better solution.

Destroy Parent Object Unity3D

I'm facing the problem that i wish to destroy a parent object but i couldn't do so.
i wish to destroy User01 while bullet hit any of these child.
My code was as below.
JS:
function OnControllerColliderHit(col:ControllerColliderHit){
if(col.gameObject.tag == "Bullet"){
Destroy(col.transform.parent.gameObject);
}
}
C#:
public class PlayerDoe : MonoBehaviour {
private GameObject par;
// Use this for initialization
void Start () {
par = transform.parent.gameObject;
}
// Update is called once per frame
void Update () {
}
void OnCollisionHit(Collision col){
if (col.gameObject.tag == "Bullet") {
Destroy(par);
}
}
}
I believe you need to use OnCollisionEnter, instead of OnCollisionHit.
There is no OnCollisionHit(). You want to use OnCollisionEnter
void OnCollisionEnter(Collision collision)
{
if(col.gameObject.tag == "Bullet")
Destroy(transform.parent.gameObject);
}

Categories