Respawning enemies from other scenes in unity - c#

Im probably go about this the wrong way, but i've hit a road block. In my game sitting at a souls like camp fire should respawn all enemies with a certain type on them and I cant think of a way to get this to work from other scenes when the player has rested.
I've created the respawning script but it only works when resting in the same room as the enemy.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EnemyManager : MonoBehaviour
{
public GameObject enemyCore;
private Core core;
enum DeathType { respawnOnEnter, respawnOnRest, neverRespawn}
[SerializeField] DeathType deathType;
private Death Death => death ? death : core.GetCoreComponent(ref death);
private Death death;
private bool canRespawn = true;
private bool justRested = false;
private bool justRespawned = false;
public void Start()
{
core = enemyCore.GetComponent<Core>();
if (ES3.KeyExists(core.transform.parent.gameObject.name + "canRespawn"))
canRespawn = ES3.Load<bool>(core.transform.parent.gameObject.name + "canRespawn");
if (ES3.KeyExists("justRested"))
canRespawn = ES3.Load<bool>("justRested");
switch (deathType)
{
case DeathType.respawnOnEnter:
canRespawn = true;
break;
case DeathType.respawnOnRest:
if(justRested || justRespawned)
{
canRespawn = true;
justRespawned = false;
}
break;
}
ES3.Save(core.transform.parent.gameObject.name + "canRespawn", canRespawn);
if (!canRespawn)
{
core.transform.parent.gameObject.SetActive(false);
}
}
public void Rested()
{
justRested = true;
justRespawned = true;
ES3.Save("justRested", justRested);
}
public void Update()
{
if(Death.JustDied)
{
switch (deathType)
{
case DeathType.respawnOnEnter:
canRespawn = true;
break;
case DeathType.respawnOnRest:
canRespawn = false;
break;
case DeathType.neverRespawn:
canRespawn = false;
break;
}
ES3.Save(core.transform.parent.gameObject.name + "canRespawn", canRespawn);
Death.JustDied = false;
}
switch (deathType)
{
case DeathType.respawnOnRest:
if (justRested)
{
canRespawn = true;
justRested = false;
ES3.Save(core.transform.parent.gameObject.name + "canRespawn", canRespawn);
}
break;
}
}
private void OnEnable()
{
PlayerRestState.RestAction += Rested;
}
private void OnDisable()
{
PlayerRestState.RestAction -= Rested;
}
}
Heres the code I have written, the script should go on each enemy individually.
Thanks for the help.

Fixed by using scriptable objects meaning I could access data from any enemy from any scene. If anyone was wondering.

Related

change scene upon reaching specific score

I'm very new to unity and coding so I have some doubt here. I'm current creating a multiple choice quiz game. can someone help w the coding for my question. My question here is I need to change scene upon reaching certain point. for example, when my score hits 30 I want winner page to appear and when my score hits 0 I want you lose page to appear. how?
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.SceneManagement;
public class AnswerButtons : MonoBehaviour {
public GameObject answerAbackBlue; // blue is waiting
public GameObject answerAbackGreen; // green is correct
public GameObject answerAbackRed; // red is wrong answer
public GameObject answerBbackBlue; // blue is waiting
public GameObject answerBbackGreen; // green is correct
public GameObject answerBbackRed; // red is wrong answer
public GameObject answerCbackBlue; // blue is waiting
public GameObject answerCbackGreen; // green is correct
public GameObject answerCbackRed; // red is wrong answer
public GameObject answerDbackBlue; // blue is waiting
public GameObject answerDbackGreen; // green is correct
public GameObject answerDbackRed; // red is wrong answer
public GameObject answerA;
public GameObject answerB;
public GameObject answerC;
public GameObject answerD;
public AudioSource CorrectFX;
public AudioSource WrongFX;
public GameObject currentScore;
public int scoreValue;
void Update() {
currentScore.GetComponent<Text>().text = "SCORE: " + scoreValue;
if (scoreValue > 300)
SceneManager.LoadScene("WinnerPage");
if (scoreValue < 50)
SceneManager.LoadScene("LoserPage");
}
public void AnswerA() {
if (QuestionGenarate.actualAnswer == "A") {
answerAbackGreen.SetActive(true);
answerAbackBlue.SetActive(false);
CorrectFX.Play();
scoreValue += 10;
} else {
answerAbackRed.SetActive(true);
answerAbackBlue.SetActive(false);
WrongFX.Play();
scoreValue -= 5;
}
answerA.GetComponent<Button>().enabled = false;
answerB.GetComponent<Button>().enabled = false;
answerC.GetComponent<Button>().enabled = false;
answerD.GetComponent<Button>().enabled = false;
StartCoroutine(NextQuestion());
}
public void AnswerB() {
if (QuestionGenarate.actualAnswer == "B") {
answerBbackGreen.SetActive(true);
answerBbackBlue.SetActive(false);
CorrectFX.Play();
scoreValue += 10;
} else {
answerBbackRed.SetActive(true);
answerBbackBlue.SetActive(false);
WrongFX.Play();
scoreValue -= 5;
}
answerA.GetComponent<Button>().enabled = false;
answerB.GetComponent<Button>().enabled = false;
answerC.GetComponent<Button>().enabled = false;
answerD.GetComponent<Button>().enabled = false;
StartCoroutine(NextQuestion());
}
public void AnswerC() {
if (QuestionGenarate.actualAnswer == "C") {
answerCbackGreen.SetActive(true);
answerCbackBlue.SetActive(false);
CorrectFX.Play();
scoreValue += 10;
} else {
answerCbackRed.SetActive(true);
answerCbackBlue.SetActive(false);
WrongFX.Play();
scoreValue -= 5;
}
answerA.GetComponent<Button>().enabled = false;
answerB.GetComponent<Button>().enabled = false;
answerC.GetComponent<Button>().enabled = false;
answerD.GetComponent<Button>().enabled = false;
StartCoroutine(NextQuestion());
}
public void AnswerD() {
if (QuestionGenarate.actualAnswer == "D") {
answerDbackGreen.SetActive(true);
answerDbackBlue.SetActive(false);
CorrectFX.Play();
scoreValue += 10;
} else {
answerDbackRed.SetActive(true);
answerDbackBlue.SetActive(false);
WrongFX.Play();
scoreValue -= 5;
}
answerA.GetComponent<Button>().enabled = false;
answerB.GetComponent<Button>().enabled = false;
answerC.GetComponent<Button>().enabled = false;
answerD.GetComponent<Button>().enabled = false;
StartCoroutine(NextQuestion());
}
IEnumerator NextQuestion() {
yield return new WaitForSeconds(2);
answerAbackGreen.SetActive(false);
answerBbackGreen.SetActive(false);
answerCbackGreen.SetActive(false);
answerDbackGreen.SetActive(false);
answerAbackRed.SetActive(false);
answerBbackRed.SetActive(false);
answerCbackRed.SetActive(false);
answerDbackRed.SetActive(false);
answerAbackBlue.SetActive(false);
answerBbackBlue.SetActive(false);
answerCbackBlue.SetActive(false);
answerDbackBlue.SetActive(false);
answerA.GetComponent<Button>().enabled = true;
answerB.GetComponent<Button>().enabled = true;
answerC.GetComponent<Button>().enabled = true;
answerD.GetComponent<Button>().enabled = true;
QuestionGenarate.displayingQuestion = false;
}
}
It is hard to answer because you didn't show us the exact code where you count scores. But I will try to help you as much as I can.
Enter your code where you count scores (where you have that variable that stores scores). Now, above the code, among other "using" statements add
using UnityEngine.SceneManagement;
So you just added a scene manager into your script to have control over scenes. Now inside your Update() function add
if (score<0)
{
SceneManager.LoadScene("LoserPage"); //player lost
}
if (score>29)
{
SceneManager.LoadScene("WinnerPage"); //player won
}
In the code above score is a variable that stores your scores. Change that to whatever you have that does it. LoserPage and WinnderPage are the names of the scenes that you have created. Change their names to whatever you have to make it work. Don't forget to add your scenes in Build settings in the correct order.

How can I disable the audio for a specific scene?

I'm using this line :
AudioListener.pause = true;
The problem is that I have two scenes loaded, I'm loading another scene with the
LoadSceneMode.Additive
Then the audio pausing is effecting both scenes.
This is my full code for pausing/resuming the game. Index 0 is the Main Menu scene and index 1 is the Game scene. I have two scenes the Main Menu and the Game.
When I hit the escape key to the main menu I want to pause the audio in the Game scene and then when hitting the escape ley again back to the game I want to resume the audio in the game scene.
using System.Collections;
using System.Collections.Generic;
using TMPro;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
public class BackToMainMenu : MonoBehaviour
{
public GameObject[] objsToDisable;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
if (Input.GetKeyDown(KeyCode.Escape))
{
if (Time.timeScale == 0)
{
DisableEnableUiTexts(true);
AudioListener.pause = false;
SceneManager.UnloadSceneAsync(0);
Cursor.visible = false;
Time.timeScale = 1;
}
else
{
Time.timeScale = 0;
MenuController.LoadSceneForSavedGame = false;
AudioListener.pause = true;
SceneManager.LoadScene(0, LoadSceneMode.Additive);
SceneManager.sceneLoaded += SceneManager_sceneLoaded;
Cursor.visible = true;
}
}
}
private void SceneManager_sceneLoaded(Scene arg0, LoadSceneMode arg1)
{
DisableEnableUiTexts(false);
}
private void DisableEnableUiTexts(bool enabled)
{
foreach (GameObject go in objsToDisable)
{
if (go.name == "Cameras")
{
foreach(Transform child in go.transform)
{
if(child.name == "Main Camera")
{
if (enabled == false)
{
child.GetComponent<Camera>().enabled = false;
}
else
{
child.GetComponent<Camera>().enabled = true;
}
}
}
}
else
{
go.SetActive(enabled);
}
}
}
}
As mentioned one possibility is to use AudioSource.mute but of course you'd have to use it on all sources of according scene.
When you already know the index you can do e.g.
var scene = SceneManager.GetSceneAtBuildIndex(1);
if(scene.isValid)
{
// Iterate through the scene Hierarchy and get all sources (also inactive/disabled ones)
var audioSources = new List<AudioSource>();
foreach (var root in scene.GetRootGameObjects())
{
audioSources.AddRange(root.GetComponentsInChildren<AudioSource>(true));
}
foreach(var source in audioSources)
{
source.mute = !enabled;
//Or
source.pause = !enabled;
}
}
Alternatively you could use the AudioMixer which I'd say is more convenient for this.
Here would simply but all the sources into a certain AudioMixerGroup and make the volume an exposed parameter.
Then you can simply silent that entire group by using SetFloat.
Btw be very careful with naming your method parameters like already existing fields/properties! Yes, they will be shadowed anyway but it only leads to confusion for you and other readers. There already is Behavior.enabled which MonoBehavior and thus your class derives from.
Can you try using audio_source_name.mute = true &/or audio_source_name.Stop()?
Example:
void Update()
{
if (Input.GetKeyDown(KeyCode.Escape))
{
if (Time.timeScale == 0)
{
DisableEnableUiTexts(true);
// AudioListener.pause = true;
audio_source_name.mute = false; // <--------
SceneManager.UnloadSceneAsync(0);
Cursor.visible = false;
Time.timeScale = 1;
}
else
{
Time.timeScale = 0;
MenuController.LoadSceneForSavedGame = false;
// AudioListener.pause = true;
audio_source_name.mute = false; // <--------
SceneManager.LoadScene(0, LoadSceneMode.Additive);
SceneManager.sceneLoaded += SceneManager_sceneLoaded;
Cursor.visible = true;
}
}
}
You could also do it this way (Source: Unity - Scripting API: AudioSource.mute):
// Mutes-Unmutes the sound from this object each time the user presses space.
using UnityEngine;
using System.Collections;
public class ExampleClass : MonoBehaviour
{
AudioSource audioSource;
void Start()
{
audioSource = GetComponent<AudioSource>();
}
void Update()
{
if (Input.GetKeyDown(KeyCode.Space))
audioSource.mute = !audioSource.mute;
}
}

Despite the name of the file and the name of the class being the same, Unity still can't find the class

Despite the many times I have rewritten the file and made sure the class and the file name match up unity is still saying it can't find the script class. I even made sure all the spelling important words were correct, and it still says it can't find the script class. The name of the file is BasicAI.cs This is what the file looks like.
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace UnityStandardAssets.Characters.ThirdPerson
{
public class BasicAI : MonoBehaviour
{
public UnityEngine.AI.NavMeshAgent agent;
public ThirdPersonCharacteracter character;
public enum State {
PATROL,
CHASE
}
public State state;
private bool alive;
//Patrolling
public GameObject[] markers;
private int markerID=0;
public float patrolSpeed=0.0f;
//Chasing
public float chaseSpeed=1f;
public GameObject target;
// Start is called before the first frame update
void Start()
{
agent = GetComponent<UnityEngine.AI.NavMeshAgent>();
character = GetComponent<ThirdPersoncharacter>();
agent.updatePosition = true;
agent.updateRotation = false;
state = BasicAI.State.PATROL;
alive = true;
StartCoroutine("FiniteState");
}
IEnumerator FiniteState()
{
while(alive)
{
switch(state)
{
case State.PATROL:
Patrol();
break;
case State.CHASE:
Chase();
break;
}
yield return null;
}
}
void Patrol()
{
agent.speed = patrolSpeed;
if(Vector3.Distance(this.transform.position, markers[markerID].transform.position) >= 2)
{
agent.setDestionation(markers[markerID].transform.position);
character.move(agent.desiredVelocity, false, false);
}
else if(Vector3.Distance(this.transform.position, markers[markerID].transform.position) <= 2)
{
markerID += 1;
if(markerID>markers.Length)
{
markerID = 0;
}
}
else
{
character.move(Vector3.zero, false, false);
}
}
void Chase()
{
agent.speed = chaseSpeed;
agent.setDestionation(target.transform.position);
character.move(agent.desiredVelocity, false, false);
}
void OnTriggerEnter(Collider other)
{
if (other.tag == "Player")
{
state = basicAI.State.CHASE;
target = other.GameObject;
}
}
}
}

UNET SyncVar on server side not updated

I am trying to use SyncVar but I do not fully understand what I am doing wrong, if I do it wrong that is. Here is the situation:
I have two public SyncVar's: redFunds and blueFunds and two local "old"-version to compare with
I initiate the SyncVar in Start by using Cmd_UpdateXxx, that works
I have two buttons, one for each SyncVar
In Update I compare the SyncVar vs. the oldXxxFunds. If a hit I display on scene
When I run the code it does display the correct numbers on the scen on both players (Red & Blue) but that is not fully reflected in the editor when looking at the "public" SyncVar's. When pressing the red button it only reflect, in the editor, on the red player not the Blue.
Can someone explain to me what i am doing wrong here? ...if I am doing something wrong that is. Shouldn't I see the changes in the editor as well?
[SyncVar] public int redFunds;
[SyncVar] public int blueFunds;
public int oldRedFunds;
public int oldBlueFunds;
private void Start ()
{
if (!isLocalPlayer)
return;
Cmd_UpdateRed (10);
Cmd_UpdateBlue (20);
}
// Button
void btn_Red ()
{
if (!hasAuthority)
return;
Cmd_UpdateRed (10000);
}
void btn_Blue ()
{
if (!hasAuthority)
return;
Cmd_UpdateBlue (20000);
}
[Command]
void Cmd_UpdateRed (int _value)
{
redFunds = _value;
}
[Command]
void Cmd_UpdateBlue (int _value)
{
blueFunds = _value;
}
void Update ()
{
if (redFunds != oldRedFunds)
{
txt_RedTotalFunds = GameObject.Find ("txt_RedTotalFunds").GetComponent<Text> ();
txt_RedTotalFunds.text = "$" + redFunds;
oldRedFunds = redFunds;
}
if (blueFunds != oldBlueFunds)
{
txt_BlueTotalFunds = GameObject.Find ("txt_BlueTotalFunds").GetComponent<Text> ();
txt_BlueTotalFunds.text = "$" + blueFunds;
oldBlueFunds = blueFunds;
}
}
The best way I can think is to use a GameRoomInfo as an network object owned by the server.
It can be done with 2 simple scripts as follows:
GameRoomInfo Script
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.UI;
using System.Collections;
public class GameRoomInfo : NetworkBehaviour
{
public Text txt_RedTotalFunds;
public Text txt_BlueTotalFunds;
public int oldRedFunds = 0;
public int oldBlueFunds = 0;
[SyncVar]
public int redFunds;
[SyncVar]
public int blueFunds;
void Update()
{
if (redFunds != oldRedFunds)
{
//txt_RedTotalFunds = GameObject.Find("txt_RedTotalFunds").GetComponent<Text>();
txt_RedTotalFunds.text = "$" + redFunds;
Debug.Log("Red - $" + redFunds);
oldRedFunds = redFunds;
}
if (blueFunds != oldBlueFunds)
{
//txt_BlueTotalFunds = GameObject.Find("txt_BlueTotalFunds").GetComponent<Text>();
txt_BlueTotalFunds.text = "$" + blueFunds;
Debug.Log("Blue - $" + blueFunds);
oldBlueFunds = blueFunds;
}
}
}
Player Script
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.UI;
using System.Collections;
public class Player : NetworkBehaviour
{
public enum PlayerColor
{
Red,
Blue
};
//used to update the right variables (Blue player updates blueFunds and Red player updates redFunds)
[SyncVar]
PlayerColor playerColor;
static int colorSelect = 0;
void Start()
{
if(isServer)
{
// the server selects the player color when created
switch(colorSelect % 2)
{
case 0:
playerColor = PlayerColor.Red;
break;
case 1:
playerColor = PlayerColor.Blue;
break;
}
colorSelect++;
}
}
void Update()
{
if (!isLocalPlayer)
return;
if (hasAuthority && Input.GetKeyDown(KeyCode.KeypadPlus))
{
Cmd_UpdateAdd(10);
}
}
// Button
void btn_Update()
{
if (!hasAuthority)
return;
Cmd_Update(0);
}
void btn_Add()
{
if (!hasAuthority)
return;
Cmd_Update(10);
}
[Command]
public void Cmd_Update(int _value)//The command updates the GameRoomInfo variables according to the player color
{
switch (playerColor)
{
case PlayerColor.Red:
FindObjectOfType<GameRoomInfo>().redFunds = _value;
break;
case PlayerColor.Blue:
FindObjectOfType<GameRoomInfo>().blueFunds = _value;
break;
default:
break;
}
}
[Command]
public void Cmd_UpdateAdd(int _value)
{
switch (playerColor)
{
case PlayerColor.Red:
FindObjectOfType<GameRoomInfo>().redFunds += _value;
break;
case PlayerColor.Blue:
FindObjectOfType<GameRoomInfo>().blueFunds += _value;
break;
default:
break;
}
}
}
I have made some small changes to help testing. Feel free to adapt to your needs.

How can i set animation command only once in the Update function?

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Animations : MonoBehaviour
{
public enum AnimatorStates
{
WALK, RUN, IDLE
}
private Animator _anim;
void Awake()
{
_anim = GetComponent<Animator>();
}
public void PlayState(AnimatorStates state)
{
string animName = string.Empty;
switch (state)
{
case AnimatorStates.WALK:
animName = "Walk";
break;
case AnimatorStates.RUN:
animName = "Run";
break;
}
if (_anim == null)
_anim = GetComponent<Animator>();
_anim.Play(animName);
}
void Update()
{
if (MyCommands.walkbetweenwaypoints == true)
{
PlayState(AnimatorStates.RUN);
}
else
{
PlayState(AnimatorStates.IDLE);
}
}
}
The code is working fine but i don't think it's right to call the PlayState so many times in the Update. I want that if it's RUN or IDLE state to call it only once in the Update function.
Once walkbetweenwaypoints is true or false it will call the state nonstop in the Update function.
Save the last state in Update method and only update if state has actually changed:
AnimatorStates lastState = AnimatorStates.IDLE;
public void PlayState(AnimatorStates state)
{
if(state != lastState)
{
string animName = string.Empty;
switch (state)
{
case AnimatorStates.WALK:
animName = "Walk";
break;
case AnimatorStates.RUN:
animName = "Run";
break;
}
if (_anim == null)
_anim = GetComponent<Animator>();
_anim.Play(animName);
lastState = state;
}
}

Categories