Unity Selected Emote Animations - c#

Hello everyone I am trying to make a simple Emote functionality. I have a bubble(like a chat bubble) and inside of that there is an animation. Like in Legends of Runeterra and Clash Royale type games.
public class EmoteBubble : MonoBehaviour
{
private Animator animator;
private Animator childAnimator;
public List<GameObject> objectList;
// Start is called before the first frame update
void Start()
{
animator = gameObject.GetComponent<Animator>();
foreach (GameObject obj in objectList)
{
obj.SetActive(false);
}
}
// Update is called once per frame
void Update()
{
if (Input.GetKeyDown(KeyCode.Space)){
childAnimator = transform.Find(objectList[0].name).GetComponent<Animator>();
objectList[0].SetActive(true);
StartCoroutine(HeroAnimator(2f, objectList[0].name + "Bool"));
}
IEnumerator HeroAnimator(float animationLength, string parameter)
{
animator.SetBool("EmoteBool", true);
childAnimator.SetBool(parameter, true);
yield return new WaitForSeconds(animationLength);
animator.SetBool("EmoteBool", false);
childAnimator.SetBool(parameter, false);
yield return new WaitForSeconds(0.2f);
foreach (GameObject obj in objectList)
{
obj.SetActive(false);
}
}
}
This is the script of the bubble and it has childs in objectList. If I hit space I want a specific animation to kick in like the first one or the second one. I am trying to disable every object in Start function and enable the one that i choose. But when I use prefabs only the real one gets disabled. Should I use prefabs in this emote concept or should I make every object different ?

public class EmoteBubble : MonoBehaviour
{
private Animator animator;
private Animator childAnimator;
public List<GameObject> objectList;
// Start is called before the first frame update
void Start()
{
Debug.Log(objectList[2]);
animator = gameObject.GetComponent<Animator>();
foreach (GameObject obj in objectList)
{
obj.SetActive(false);
}
}
// Update is called once per frame
void Update()
{
if (Input.GetKeyDown(KeyCode.Space)){
objectList[0].SetActive(true);
childAnimator = transform.Find(objectList[0].name).GetComponent<Animator>();
StartCoroutine(HeroAnimator(2f, objectList[0].name + "Bool"));
}
if (Input.GetKeyDown(KeyCode.A)) {
objectList[1].SetActive(true);
childAnimator = transform.Find(objectList[1].name).GetComponent<Animator>();
StartCoroutine(HeroAnimator(2f, objectList[1].name + "Bool"));
}
if (Input.GetKeyDown(KeyCode.S)){
objectList[2].SetActive(true);
childAnimator = transform.Find(objectList[2].name).GetComponent<Animator>();
StartCoroutine(HeroAnimator(2f, objectList[2].name + "Bool"));
}
IEnumerator HeroAnimator(float animationLength, string parameter)
{
animator.SetBool("EmoteBool", true);
childAnimator.SetBool(parameter, true);
yield return new WaitForSeconds(animationLength);
animator.SetBool("EmoteBool", false);
childAnimator.SetBool(parameter, false);
yield return new WaitForSeconds(0.2f);
foreach (GameObject obj in objectList)
{
obj.SetActive(false);
}
}
}
}
I think this works, It looks simple and it works but I don't know if it's the best way.

Related

IEnumerator script is not working and Coroutine is not running? Unity,C#

I am writing a script for Enemy in my game, where they will attack hero using Coroutine at a certain interval. Though, while running the game, Enemy is not attacking. I have created two events for enemy animation specific for attack. The IE numerator part of code is not running. Can anyone tell what is going wrong?
I wrote Debug.Log("Hello"), to verify if it executes but it doesn't print.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EnemyAttack : MonoBehaviour
{
[SerializeField] private float range = 3f;
[SerializeField] private float timeBetweenAttacks = 1f;
private Animator anim;
private GameObject player;
private bool playerInRange;
private BoxCollider[] weaponColliders;
// Start is called before the first frame update
void Start()
{
weaponColliders = GetComponentInChildren <BoxCollider[]> ();
player = GameManager.instance.Player;
anim = GetComponent <Animator> ();
StartCoroutine (attack());
}
// Update is called once per frame
void Update()
{
if(Vector3.Distance(transform.position,GameManager.instance.Player.transform.position) < range)
{
playerInRange = true;
}else{
playerInRange = false;
}
}
public IEnumerator attack()
{
Debug.Log("Hello");
if(playerInRange && !GameManager.instance.GameOver)
{
anim.Play("Attack");
yield return new WaitForSeconds(timeBetweenAttacks);
}
yield return null;
StartCoroutine(attack());
}
public void EnemyBeginAttack(){
foreach(var weapon in weaponColliders){
weapon.enabled = true;
}
}
public void EnemyEndAttack(){
foreach(var weapon in weaponColliders){
weapon.enabled = false;
}
}
}
The issue is likely the code weaponColliders = GetComponentInChildren<BoxCollider[]>();. GetComponentInChildren should only be called with component types (or interface types), but BoxCollider[] is an array type.
You should instead use GetComponentsInChildren<BoxCollider>();.

How to keep player skin through restart

I'm trying to keep the player skin, even when reloading the scene, or moving on to a new one. The player object changes every scene.
The player skin is chosen in a pause menu, with three buttons. Each one of those buttons calls a function in the script below. I'm trying to call one of these functions, based on what value the PlayerPrefs int holds, and the function does get called; But throws the error MissingReferenceException: The object of type 'GameObject' has been destroyed but you are still trying to access it
Below is what i have already tried, but this throws an error on scene reload (death)
i don't know what i'm doing wrong here.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class Pausemenu : MonoBehaviour
{
public static bool gameIsPaused = false;
public GameObject pauseMenuUI;
public Material BelgianMat;
public Material Ball2;
public Material Rainbow;
public GameObject Player;
// Update is called once per frame
void Update()
{
if (Input.GetKeyDown(KeyCode.Escape)) {
if (gameIsPaused) {
Resume();
} else {
Pause();
}
}
}
public void Resume(){
pauseMenuUI.SetActive(false);
Time.timeScale = 1f;
gameIsPaused = false;
}
void Pause() {
pauseMenuUI.SetActive(true);
Time.timeScale = 0f;
gameIsPaused = true;
}
public void LoadMenu() {
Time.timeScale = 1f;
gameIsPaused = false;
SceneManager.LoadScene("Menu");
}
public void QuitGame() {
Debug.Log("Quitting");
Application.Quit();
}
public void ApplyBelgian() {
Player.GetComponent<Renderer>().material = BelgianMat;
PlayerPrefs.SetInt("playerMat", 0);
}
public void ApplyBall2() {
Player.GetComponent<Renderer>().material = Ball2;
Debug.Log("Applied ball two");
PlayerPrefs.SetInt("playerMat", 1);
}
public void ApplyRainbow() {
Player.GetComponent<Renderer>().material = Rainbow;
PlayerPrefs.SetInt("playerMat", 2);
}
void OnEnable()
{
Debug.Log("OnEnable called");
SceneManager.sceneLoaded += OnSceneLoaded;
}
// called second
void OnSceneLoaded(Scene scene, LoadSceneMode mode)
{
Debug.Log("OnSceneLoaded: " + scene.name);
Debug.Log(mode);
if (PlayerPrefs.GetInt("playerMat") == 0) {
ApplyBelgian();
}
else if (PlayerPrefs.GetInt("playerMat") == 1) {
Debug.Log("gonna apply ball 2");
ApplyBall2();
}
else if (PlayerPrefs.GetInt("playerMat") == 2) {
ApplyRainbow();
}
}
}
I don't know why but it seems like the reference to the Player object may be broken after loading the scene. If this is the case, add a "Player" tag to your Player object and add this to the OnEnable function: Player = GameObject.FindWithTag("Player");

How do I enable and disable multiple game objects in Unity?

I Need to Enable and Disable Multiple Gameobjects that contain Same Tag in Unity using C#.Thanks
You can use GameObject.FindGameObjectsWithTag() to return an array of all game objects with a given tag, then use GameObject.SetActive() to enable or disable them. Something like:
string tag = ""; // your tag
GameObject[] taggedObjects = GameObject.FindGameObjectsWithTag(tag);
foreach (GameObject tagged in taggedObjects){
tagged.Setactive(false); // or true
}
Unfortunately GameObject.FindGameObjectsWithTag() does not return inactive gameobjects. So you can leave all objects active before scene start and re close them in awake() or start().
And unity 2020 would have that feature which find inactive gameobjects too.
Above answers mess up with my camera or sort of. So, I Did my own code based on the answers.( Which is Inserted Below) (Posting It for Future Uses) Thanking Everyone who Answered.
using UnityEngine;
using UnityEngine.SceneManagement;
using System.Collections;
public class GameManager : MonoBehaviour
{
public float restarttimer = 3f;
public GameObject Ninja;
public GameObject Covid;
public GameObject[] Buttons;
public GameObject[] Ground;
public GameObject[] HP;
public GameObject[] panelgo;
void Start()
{
//Ninja
Debug.Log("Generating Hero");
Ninja.SetActive(true);
//enemy
Debug.Log("Generating Enemy");
Covid.SetActive(true);
//ground
Debug.Log("Generating Ground");
foreach (GameObject tagged in Ground)
{
tagged.SetActive(true); // or true
}
//HP
foreach (GameObject tagged in HP)
{
tagged.SetActive(true); // or true
}
//Buttons
foreach (GameObject tagged in Buttons)
{
tagged.SetActive(true); // or true
}
//GameOver
foreach (GameObject tagged in panelgo)
{
tagged.SetActive(false); // or true
}
}
public void GameOver()
{
Ninja.SetActive(false);
Covid.SetActive(false);
foreach (GameObject tagged in Ground)
{
tagged.SetActive(false); // or true
}
foreach (GameObject tagged in HP)
{
tagged.SetActive(false); // or true
}
foreach (GameObject tagged in Buttons)
{
tagged.SetActive(false); // or true
}
foreach (GameObject tagged in panelgo)
{
tagged.SetActive(true); // or true
}
}
public void buttonrestart()
{
Invoke("restart", restarttimer);
}
public void restart()
{
SceneManager.LoadScene(SceneManager.GetActiveScene().name);
}
}
P.S COVID Funny Name for enemy ;)
-------------------THE THREAD IS CLOSED--------------------------

C# Unity script for item pick up choice

I currently have a script that instantiates 2 prefabs as GameObjects. Which have attached to them a script that the game-object is set active to false, then is added to my inventory array. Which is another script, but my issue is the other game object that wasn't selected is still there. It is supposed to be you have a choice of 2. Once you take one the other disappears. I have no idea how to do this, could anyone please help.
public int moralityCounter=0;
public bool Inventory;
public void Store()
{
if (gameObject.CompareTag("Good"))
{
moralityCounter++;
Debug.Log(moralityCounter);
gameObject.SetActive(false);
}
if (gameObject.CompareTag("Bad"))
{
moralityCounter--;
Debug.Log(moralityCounter);
gameObject.SetActive(false);
}
}
If there's only the single good and single bad tagged objects, you can just set everything tagged good and bad to be inactive.
private void DeactivateAllGoodBads()
{
// Deactivate all goods
GameObject[] goodObjects = GameObject.FindGameObjectsWithTag("Good");
foreach (GameObject goodObject in goodObjects)
{
goodObject.SetActive(false);
}
// Deactivate all bads
GameObject[] badObjects = GameObject.FindGameObjectsWithTag("Bad");
foreach (GameObject badObject in badObjects)
{
badObject.SetActive(false);
}
}
public void Store()
{
bool isGood = gameObject.CompareTag("Good");
bool isBad = gameObject.CompareTag("Bad");
if (isGood)
{
moralityCounter++;
Debug.Log(moralityCounter);
}
if (isBad)
{
moralityCounter--;
Debug.Log(moralityCounter);
}
if (isGood || isBad)
{
DeactivateAllGoodBads();
}
}
If there are multiple, you can do something like only disable ones closer to the Stored object than some distance.
private void DeactivateCloseGoodBads(Vector3 position, float maxDistance)
{
// Deactivate close goods
GameObject[] goodObjects = GameObject.FindGameObjectsWithTag("Good");
foreach (GameObject goodObject in goodObjects)
{
// Check distance of found good
if (Vector3.Distance(position, goodObject.transform.position) <= maxDistance) {
goodObject.SetActive(false);
}
}
// Deactivate close bads
GameObject[] badObjects = GameObject.FindGameObjectsWithTag("Bad");
foreach (GameObject badObject in badObjects)
{
// Check distance of found bad
if (Vector3.Distance(position, badObject.transform.position) <= maxDistance) {
badObject.SetActive(false);
}
}
}
public void Store()
{
bool isGood = gameObject.CompareTag("Good");
bool isBad = gameObject.CompareTag("Bad");
if (isGood)
{
moralityCounter++;
Debug.Log(moralityCounter);
}
if (isBad)
{
moralityCounter--;
Debug.Log(moralityCounter);
}
if (isGood || isBad)
{
DeactivateCloseGoodBads(gameObject.transform.position, 10f);
}
}

Null GameObjects in foreach loop

I am trying to iterate through a list of GameObjects and find the first GameObject that is not active in the hierarchy and return that GameObject.
The problem I am having is my foreach statement keep returning null on "enemy"
"enemy" in this statement below is where the problem is
"GameObject enemy in pizzaEnemyList"
I do have one Gameobject inside of the list. Included in picture below
private List<GameObject> pizzaEnemyList = new List<GameObject> ();
private GameObject FetchPizzaEnemy()
{
GameObject pizzaEnemy = null;
int count = 0;
foreach (GameObject enemy in pizzaEnemyList)
{
if (enemy.activeInHierarchy == false)
{
pizzaEnemy = pizzaEnemyList [count];
pizzaEnemyList.Remove (enemy);
return pizzaEnemy;
}
count += 1;
}
return pizzaEnemy;
}
//Function I am using to add the enemies to the list.
public void DeactivateAndStoreEnemy(GameObject enemy)
{
//decativates the enemy
enemy.SetActive(false);
//Store the enemy into the correct list
if (enemy.name == "PizzaGuy")
{
pizzaEnemyList.Add (enemy);
}
else if (enemy.name == "FiresGuy")
{
friesEnemyList.Add (enemy);
}
else if (enemy.name == "SodaGuy")
{
sodaEnemyList.Add (enemy);
}
}
public int PizzaListUnactiveEnemyCount()
{
int unactiveEnemiesCount = 0;
foreach (GameObject enemies in pizzaEnemyList)
{
if (enemies.activeInHierarchy == false)
{
unactiveEnemiesCount += 1;
}
}
return unactiveEnemiesCount;
}
I have tested your code and can tell you it works if the gameObject are added properly and that they are actually not active.
Your problem is most probably not adding the game objects correctly to the list and maybe also not making sure that pizzaEnemyList has at least 1 item that is set inactive. When all item are active in your list its normal that it returns null because it will never go in if (enemy.activeInHierarchy == false)
It would be better if you had a public List<GameObject> pizzaEnemyList; that you setup in the inspector of unity. Unless if this solution doesn't fit with the game you're building.
As Serlite said you don't need to keep a counter when using foreach, your code could look like this :
private GameObject FetchPizzaEnemy()
{
GameObject pizzaEnemy = null;
foreach (GameObject enemy in pizzaEnemyList)
{
if (enemy.activeInHierarchy == false)
{
pizzaEnemy = enemy;
pizzaEnemyList.Remove(enemy);
return pizzaEnemy;
}
}
return pizzaEnemy;
}
Edit after your edit:
I've tested your code with this and it works :
private List<GameObject> pizzaEnemyList = new List<GameObject>();
void Start()
{
GameObject pizzaGuy = GameObject.Find("PizzaGuy");
DeactivateAndStoreEnemy(pizzaGuy);
Debug.Log(FetchPizzaEnemy());
}
private GameObject FetchPizzaEnemy()
{
GameObject pizzaEnemy = null;
foreach (GameObject enemy in pizzaEnemyList)
{
if (enemy.activeInHierarchy == false)
{
pizzaEnemy = enemy;
pizzaEnemyList.Remove(enemy);
return pizzaEnemy;
}
}
return pizzaEnemy;
}
public void DeactivateAndStoreEnemy(GameObject enemy)
{
enemy.name = "PizzaGuy";
//decativates the enemy
enemy.SetActive(false);
//Store the enemy into the correct list
if (enemy.name == "PizzaGuy")
{
pizzaEnemyList.Add(enemy);
}
}
I have a gameobject named PizzaGuy in my scene.

Categories

Resources