I want to play a death animation to my enemy. Basically, he has an idle animation and I would like to play the death animation when he dies, and after one or two seconds, the GameObject gets deleted. I'm new to coding, so a basic solution would be better :) .
Here's my coding:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EnemyHealthManager : MonoBehaviour {
public int enemyHealth;
public GameObject deathEffect;
public int pointsOnDeath;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update ()
{
if (enemyHealth <= 0)
{
Instantiate (deathEffect, transform.position, transform.rotation);
ScoreManager.AddPoints (pointsOnDeath);
Destroy (gameObject);
}
}
public void giveDamage(int damageToGive)
{
enemyHealth -= damageToGive;
}
}
You can add a function called PlayAnimationAndDestroy() as a void and inside it put the Destroy (this.gameObject, 2f) and then animator.Play("deathAnim");
In the Destroy the number after the comma is the time Unity will wait to destroy the object so you need to check the duration of your animation in the timeline and put that duration in the Destroy ().
Another way to do this is to press the record button inside the animation at the end of it and change a public variable. In the script you will put a simple if() and If that variable has changed you destroy the object.
The third way is to use animation events (https://docs.unity3d.com/Manual/script-AnimationWindowEvent.html) but for your usage the first two options are easier :)
Welcome to Unity! Using an AnimatorController in your project and corresponding Animator components on your GameObject that you want to die is going to be your friend here as well.
You can check out a great tutorial by Unity about Animator Controllers here, but basically, it's a state machine. Based on what state your object is in, you can control which game object animations are active and you can set triggers in your game logic to trigger a transition to another state.
This is great for cases like triggering death animations.
In your case, you'd want one state for idle, and one state for death. You'd have a connection between your death and idle state.
You'd set a trigger named die. You'd make it so that the state idle only moves to state death when your die trigger is triggered in the game logic.
So, step 1:
You'd create a new AnimatorController Scriptable Object from the Editor, and then edit it in the Animator window. Make your desired state machine with the desired animations and that ScriptableObject will be saved in a project folder.
Step 2: Add an Animator component on your GameObject that you want to affect. It has an AnimatorController component - add your newly created controller here.
Step 3: In your game logic script, you'd have a reference to that Animator component:
...
public int enemyHealth;
public GameObject deathEffect;
public int pointsOnDeath;
public Animator animComponent;
...
Then when you hit your condition, you'd do something like this:
if (enemyHealth < 0){
animComponent.SetTrigger("die");
}
Then your AnimatorController will move from your previous state to death, and your animation that you set will play.
Best of luck.
Related
This is the current script that I have. I have a ball that is player, and I want a collision with my game object tagged as "pit" to end the game. When the game ends I want my game over canvas to pop up. The current script detects the hit when the player rolls over the pit, however, currently, nothing else happens. Both my player and pit have rigidbodies and colliders attached to them. I would really appreciate any help with how to get my code to work properly.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Trigger : MonoBehaviour
{
public GameObject GameManager;
private void OnTriggerEnter(Collider other)
{
Debug.Log("hit detected")
if(other.gameObject.tag == "pit")
{
GameManager.GetComponent<Game_Manager>().EndGame();
}
}
}
My EndGame code is in my GameManager script. The is the part of that script that deals with ending the game.
public void EndGame ()
{
player.GetComponent<Rigidbody>().constraints = RigidbodyConstraints.FreezePosition;
hasGameStarted = true;
inMenuUI.gameObject.SetActive(false);
inGameUI.gameObject.SetActive(false);
gameOverUI.gameObject.SetActive(true);
}
If I'm correct in interpreting your question, your script successfully detects player death already. If you want a game over screen you have a couple of options:
You can create a UI canvas with a panel on it that obscures the whole screen and put the words Game Over.
Or, probably the better option is to create an entirely new Unity scene and make the Game Over canvas there. When you want to trigger the game over screen you simply use:
Scene manager.LoadScene("Scene name");
You have to add "using UnityEngine.SceneManagement;" at the top of your script. Also note you have to add your Game Over scene to the list of scenes in you game. I believe this can be done by navigating to File>Build settings>scenes and then pressing add open scenes assuming the game over scene is open.
I'm trying to create a script in Unity wherein the gravity will go to zero when the game starts. The problem is, the gravity was still there after I launched the game.
This is for a Unity3D game. I've already tried to change the variable name, add using System; and moved my script to the top of the Rigidbody component, but none of these things worked.
public class PlayerGrav : MonoBehaviour
{
public Rigidbody rb;
void Start()
{
rb.useGravity = false;
}
void Update()
{
}
}
I expected the gravity to be removed when the game launches, but in the actual output the gravity still remained, and the cube still fell downwards.
create a new scene
create a new cube
add rb = this.GetComponent<Rigidbody>() to your start function in your PlayerGrav script
attach your PlayerGrav script to the new cube
Hit play, and take look at the "use gravity" property from your new cube's inspector window (make sure the inspector isn't locked to other game object)
If the above tryout succeeds, then you need to check the other code/objects in your original scene. If there are massive other objects in your original scene, then I will suggest disable other objects first, and re-enable them back group by group to see which object/monobhevaiour is causing the issue.
I know this is an old question but I looked forever trying to find an answer to this. I am new to unity so it took me a long time to figure this out but I am using a Rigidbody 2d so this is what worked for me
gameObject.GetComponent<Rigidbody2D>().gravityScale = 0;
Right now, I have a multiplayer game where the player fires projectiles at other players that have a certain amount of bubbles. Once a player has lost all of their bubbles, they lose.
The issue I had previously was that on one screen, a first player could shoot out a second player's bubbles, but not all of the bubbles on the second player's screen would be popped, so I am trying to sync it over the network somehow.
The issue I'm seeing is that NetworkServer.Destroy requires finding the GameObject you intend to destroy by its NetworkIdentity, but only the root Player GameObject is allowed to have the NetworkIdentity component on it. What's the best way I can sync the destruction of a child object of a player?
The https://unity3d.com/fr/learn/tutorials/topics/multiplayer-networking/ course is very similar to the game you describe. It has a Bullet script attached to the fired bullets. If the bullets touched something, it check if it's a player, and apply damage to it (the player prefab has a Health script attached to it).
using UnityEngine;
using System.Collections;
public class Bullet : MonoBehaviour {
void OnCollisionEnter(Collision collision)
{
var hit = collision.gameObject;
/* Code below is from the original example
var health = hit.GetComponent<Health>();
if (health != null)
{
health.TakeDamage(10);
}*/
var bubble = hit.GetComponent<BubbleBehavior>();
if (bubble != null)
{
bubble.Popped(); // Implement a Popped function doing the magic
}
Destroy(gameObject);
}
}
In your case you can do the same, but instead of checking if the touched object is a player, simply check if it is a bubble, and do whatever you want from the touched bubble.
In the original example, they sync the health (it is a "SyncVar"), in your case you can sync the number of bubbles remaining.
Let me explain the question first :)
I have a hero and an enemy. It is a fighting game. Both hero and enemy have idle, block, punch and getHit animations and states in the Animation Controller. The hero and enemy have scripts attached to them. The hero is controlled by player and then enemy is controller by AI.
Now I attach the script to hero first and then the enemy. Now when the enemy punches and if hero is not defending the hero takes a hit. But if the enemy is not blocking and the hero hits the enemy doesnt take the hit. This is because the script was attached to hero first.
Now if I remove the script from both and attach the enemy script first to enemy and then attach the hero script to hero. The wiseversa is true. In the enemy the hits will be registered and on the hero the hits wont be registered.
I am not sure why this is happening and I have tried different things and still the problem persists.
I also tried looking everywhere online for solution but none of them addressed my concern.
Thanks :)
below is the enemy script that checks is enemy can take hit
void Update () {
myTick++;
currentTick = myTick;
GameObject player = GameObject.Find("theDude");
Animator pAnim = player.GetComponent<Animator>();
//Getting Hit
if (pAnim.GetBool("tIsPunching"))
{
if (anim.GetBool("bEnemyIsDefending") == false)
{
Debug.Log("enemy got hit");
anim.SetTrigger("tEnemyGotHit");
anim.SetBool("bEnemyIsDefending", true);
}
}
}
And here is the hero script that checks if hero can take hit.
void Update () {
totalTime += Time.deltaTime;
GameObject enemy = GameObject.Find("Enemy");
Animator eAnim = enemy.GetComponent<Animator>();
//Getting Hit
if (eAnim.GetBool("tEnemyIsPunching"))
{
if (anim.GetBool("bIsDefending") == false)
{
Debug.Log("player got hit");
anim.SetTrigger("tGotHit");
}
}
}
Instead of get object I used to have a public GameObject and attached the hero and enemy in the respective classes. But It doesnt make any difference.
I think your problem lies in your use of the triggers tEnemyIsPunching and tIsPunching. Triggers get reset whenever they cause a transition to occur
(see: https://docs.unity3d.com/Manual/AnimationParameters.html).
In your case tIsEnemyPunching or (tIsPunching) is getting reset in the same frame as it gets set. Here is an example of what one update loop may look like in your game if the hero script is added first:
Hero Update()
Check if enemy is punching
He is not, so don't do anything
Enemy Update()
Punch! Set 'bIsEnemyPunching' = true
Animation Update()
bIsEnemyPunching is true so transition to the punching animation
reset bIsEnemyPunching = false
On the next update let's look at what happens in the hero update:
Hero Update()
Check bIsEnemyPunching
bIsEnemyPunching was reset in the previous frame, so it is false
Since the enemy isn't punching don't do anything
So Hero never sees the punch because bIsEnemyPunching got reset before Hero had a change to check it.
This is why the order of adding the scripts matters. Whichever script updates first is able to punch because the second script will see the trigger before it gets reset. However, the second script to update will never be able to punch because the trigger gets reset before the other scripts gets a chance to update.
One solution is to check the name of the animation state instead of the trigger value.
static int punchStateHash = Animator.StringToHash("Punch");
AnimatorStateInfo enemyState = eAnim.GetCurrentAnimatorStateInfo(0);
if (enemyState.nameHash == punchStateHash){
//The enemy is punching!
}
Alternatively, whenever a punch is triggered just call a function on whichever character is getting punched. So when the enemy punches the hero the Punch(...) function on the enemy should call TakePunch(...) on hero (or whatever you want to call those functions). The hero then checks his own state to determine if he is blocking.
Additional Note
You should avoid using the following code in an update function:
GameObject player = GameObject.Find("theDude");
Animator pAnim = player.GetComponent<Animator>();
These functions are very slow because Unity must search all objects for the one called theDude and then search all it's components to find the animator. Do this once and save off the result.
If I have a player and let's say a red ball hits my player and the player goes on fire... OK easy enough I did that. But now I want to add to the code below under the if statement that a blue ball hits my player and freezes or a black ball and causes death animation... But it's just not working out to add multiple animation events to 1 player.
Public GameObject GoneGo;
void OnTriggerEnter2D(Collider2D collisionObject)
{
if (collisionObject.gameObject.tag == "Orb")
{
PlayGone();
}
}
void PlayGone()
{
GameObject gone = (GameObject)Instantiate(GoneGo);
gone.transform.position = transform.position;
}
What you could do is perform a name check on the collider that impacts the player. You already have it checked the tag, have it check for redball,blueball, or blackball as the GameObject name afterwards.
You can handle multiple animations by looking into unitys mechanim system, which is the animator component (not animation component).
https://community.mixamo.com/hc/en-us/articles/203879268-Unity-Mecanim-Animation-Basics
What you would do after setting up the animator is have it SetTrigger for different trigger parameters. Or, you could use something like SetBool with a bool in the parameters like HitByBlueBall or HitByRedBall.
Hope this helps!