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.
Related
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;
}
}
}
}
i'm new to both unity and c# .
i'm trying to make a text based game for practice .
the problem is different state of game have different number of buttons and i want to switch between these with Tags but it only works for the first state and then when i try to get to next state turn of all the buttons
here is the code :
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class Textadvanture0 : MonoBehaviour
{
[SerializeField]
Text text0;
[SerializeField]
Text text1;
[SerializeField]
Text text2;
[SerializeField]
Text text3;
[SerializeField]
Text text4;
[SerializeField]
State Startingstate;
State state;
string Flag;
public void ManageStates(int cnt)
{
var nextstate = state.GetNextStates();
if (cnt == 1) //left
{
state= nextstate[0];
}
}
void Start()
{
state = Startingstate;
FlagCheck();
}
void Update()
{
Debug.Log(state.GetChoiceN());
FlagCheck();
text0.text = state.GetStateStory(0);
text1.text = state.GetStateStory(1);
text2.text = state.GetStateStory(2);
text3.text = state.GetStateStory(3);
text4.text = state.GetStateStory(4);
}
void FlagDown()
{
GameObject[] gameObjectArray = GameObject.FindGameObjectsWithTag(Flag);
foreach (GameObject go in gameObjectArray)
{
go.SetActive(false);
}
}
void FlagOn()
{
GameObject[] gameObjectArray = GameObject.FindGameObjectsWithTag(Flag);
foreach (GameObject go in gameObjectArray)
{
go.SetActive(true);
}
}
void FlagCheck()
{
if (state.Choice == 1)
{
Flag = ("Mono Choice");
FlagOn();
Flag = ("Dual Choice");
FlagDown();
Flag = ("Triple Choice");
FlagDown();
}
else if (state.Choice == 2)
{
Flag = ("Mono Choice");
FlagDown();
Flag = ("Dual Choice");
FlagOn();
Flag = ("Triple Choice");
FlagDown();
}
else if (state.Choice == 3)
{
Flag = ("Mono Choice");
FlagDown();
Flag = ("Dual Choice");
FlagDown();
Flag = ("Triple Choice");
FlagOn();
}
}
}
And State class :
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[CreateAssetMenu(menuName = "State")]
public class State : ScriptableObject
{
[TextArea(10,14)] [SerializeField] string[] StoryText;
[SerializeField]
public int Choice;
[SerializeField]
State [] Nextstates;
public string GetStateStory(int Counter)
{
return StoryText[Counter];
}
public int GetChoiceN()
{
return Choice;
}
public State[] GetNextStates()
{
return Nextstates;
}
}
by the way i get index was outside the bound of the array error as well but it doesn't seem to affect the game in any way
any solution would be appreciated :)
The exception you're getting is probably due to the arguments you're passing to the TextArea, the 10 to 14. If you have small blocks of text you may not have 14 lines.
Without seeing how you're using these classes in Unity, my guess for why states are not being updated is because you're setting the value of your state in 2 places, the Start method which only gets called once after the object is enabled, and in your ManageStates method which is only wired to handle a cnt value of 1.
If the value of state.GetNextStates()[0] is the same state as the state that's loaded you won't see a change.
I have made a game manager making sure my data gets passed on from the first scene on to the next scene. Within the game manager, I have added certain scripts to ensure it gets passed. As you can see in the picture underneath.
The problem is that the score adds up at the first level, let's say I have 5 points. I go to level 2 and the UI shows my score as 0 (even tho I have nothing put as text within the score text) I kill 1 monster and the UI shows 6. So how can I put the UI to be showing it at all times? (Constant refresh?)
The second problem is that while the score manager does work. The health script cancels everything out when switching levels.
The user starts with 10 health. Takes damage in the first scene, but in the second scene, the user still has 10 health for some reason?
Game Manager
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class GameManager : MonoBehaviour {
public ActionButton PopupPrefab;
private ActionButton currentlySpawnedPopup;
public static GameManager instance = null;
void Awake () {
if (instance == null) {
instance = this;
} else if (instance != this) {
Destroy (gameObject);
}
Application.targetFrameRate = 60;
}
void Update () {
//if (Input.GetKeyDown(KeyCode.R)) {
// RestartScene ();
//}
}
public void InvokeRestartScene (float time) {
Invoke ("RestartScene", time);
}
public void RestartScene () {
SceneManager.LoadScene (0);
}
public void SpawnPopup (Vector2 position) {
DespawnPopup ();
currentlySpawnedPopup = Instantiate (PopupPrefab, position, Quaternion.identity) as ActionButton;
}
public void DespawnPopup () {
if (currentlySpawnedPopup != null) {
currentlySpawnedPopup.DestroySelf();
currentlySpawnedPopup = null;
}
}
public void FadePopup () {
if (currentlySpawnedPopup != null) {
currentlySpawnedPopup.FadeMe ();
currentlySpawnedPopup = null;
}
}
}
Score Manager
using UnityEngine;
using System;
using System.Collections;
public class ScoreManager : MonoBehaviour
{
public static ScoreManager Instance { get; private set; }
public int Score { get; private set; }
public int HighScore { get; private set; }
public bool HasNewHighScore { get; private set; }
public static event Action<int> ScoreUpdated = delegate {};
public static event Action<int> HighscoreUpdated = delegate {};
private const string HIGHSCORE = "HIGHSCORE";
// key name to store high score in PlayerPrefs
void Awake()
{
if (Instance)
{
DestroyImmediate(gameObject);
}
else
{
Instance = this;
DontDestroyOnLoad(gameObject);
}
}
void Start()
{
Reset();
}
public void Reset()
{
// Initialize score
Score = 0;
// Initialize highscore
HighScore = PlayerPrefs.GetInt(HIGHSCORE, 0);
HasNewHighScore = false;
}
public void AddScore(int amount)
{
Score += amount;
// Fire event
ScoreUpdated(Score);
if (Score > HighScore)
{
UpdateHighScore(Score);
HasNewHighScore = true;
}
else
{
HasNewHighScore = false;
}
}
public void UpdateHighScore(int newHighScore)
{
// Update highscore if player has made a new one
if (newHighScore > HighScore)
{
HighScore = newHighScore;
PlayerPrefs.SetInt(HIGHSCORE, HighScore);
HighscoreUpdated(HighScore);
}
}
}
Health Script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
public class Health : MonoBehaviour {
public UnityEvent OnTakeDamageEvent;
public UnityEvent OnTakeHealEvent;
public UnityEvent OnDeathEvent;
[Header ("Max/Starting Health")]
public int maxHealth;
[Header ("Current Health")]
public int health;
[Header ("IsDeathOrNot")]
public bool dead = false;
[Header ("Invincible")]
public bool invincible = false;
public bool becomeInvincibleOnHit = false;
public float invincibleTimeOnHit = 1f;
private float invincibleTimer = 0f;
[Header ("Perform Dead Events after x time")]
public float DieEventsAfterTime = 1f;
void Start () {
health = maxHealth;
}
void Update () {
if (invincibleTimer > 0f) {
invincibleTimer -= Time.deltaTime;
if (invincibleTimer <= 0f) {
if (invincible)
invincible = false;
}
}
}
public bool TakeDamage (int amount) {
if (dead || invincible)
return false;
health = Mathf.Max (0, health - amount);
if (OnTakeDamageEvent != null)
OnTakeDamageEvent.Invoke();
if (health <= 0) {
Die ();
} else {
if (becomeInvincibleOnHit) {
invincible = true;
invincibleTimer = invincibleTimeOnHit;
}
}
return true;
}
public bool TakeHeal (int amount) {
if (dead || health == maxHealth)
return false;
health = Mathf.Min (maxHealth, health + amount);
if (OnTakeHealEvent != null)
OnTakeHealEvent.Invoke();
return true;
}
public void Die () {
dead = true;
if (CameraShaker.instance != null) {
CameraShaker.instance.InitShake(0.2f, 1f);
}
StartCoroutine (DeathEventsRoutine (DieEventsAfterTime));
}
IEnumerator DeathEventsRoutine (float time) {
yield return new WaitForSeconds (time);
if (OnDeathEvent != null)
OnDeathEvent.Invoke();
}
public void SetUIHealthBar () {
if (UIHeartsHealthBar.instance != null) {
UIHeartsHealthBar.instance.SetHearts (health);
}
}
}
I have thought of adding the following script on to my Health Script
But then I get the following error messages:
" Cannot implicitly convert type 'int' to 'bool'"
"The left-hand side of an assignment must be a variable, property or indexer"
void Awake()
{
if (health)
{
DestroyImmediate(gameObject);
}
else
{
(int)health = this;
DontDestroyOnLoad(gameObject);
}
}
The problem is that the score adds up at the first level, let's say I have 5 points. I go to level 2 and the UI shows my score as 0 (even tho I have nothing put as text within the score text) I kill 1 monster and the UI shows 6. So how can I put the UI to be showing it at all times? (Constant refresh?)
You can make one of the scripts set the UI text score when the scene is loaded.
void Start(){
// Loads the scoreText on start
scoreText.text = yourCurrentScore.ToString();
// Will work unless it has a "DontDestroyOnLoad" applied to it
}
The second problem is that while the score manager does work. The
health script cancels everything out when switching levels. The user
starts with 10 health. Takes damage in the first scene, but in the
second scene, the user still has 10 health for some reason?
In your health script, you had this:
void Start () {
health = maxHealth;
}
This resets your health everytime the scene loads and starts (Aka when you load to the next level). This causes the issue.
" Cannot implicitly convert type 'int' to 'bool'"
if (health)
The () for the if statement should be a condition (a question).
For example, doing health < 0 is valid since its saying "Is health less than 0?"
Doing health is not, since its just saying "10" (or some number).
"The left-hand side of an assignment must be a variable, property or
indexer"
(int)health = this;
If you wanted to change the value of health, just do health = 10 or health = some_Variable_That_Is_An_Integer
I am trying to have a game, in which everyone can buy cars (and I save that data to playerprefs). So I have 9 trails for the cars in my game and I am trying to write some code so that when you press a button the car & the trail for that car will show up.
When the button next to it is clicked, it saves that data so when people restart the game, they will still have the car & trail open and won't need to press the button again.
Here's my code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine; using UnityEngine.UI;
public class GameManager : MonoBehaviour
{
public Button[] TrailLevel;
public GameObject[] Cars, Trails;
public Text text;
public int CurrentCarToSpawn = 0;
private void Start()
{ }
private void FixedUpdate()
{
UpdateCar();
}
public void InstantiateCar()
{
TrailLevel[CurrentCarToSpawn].gameObject.active = false;
MineLevel[CurrentCarToSpawn+1].interactable = true;
PlayerPrefs.SetInt("TrailCountA", PlayerPrefs.GetInt("TrailCountA") + 1);
PlayerPrefs.Save();
CurrentCarToSpawn++;
UpdateCar();
}
void UpdateCar()
{
int TrailCountA= PlayerPrefs.GetInt("TrailCountA", 1);
for (int i = 0; i < TrailLevel.Length; i++)
{
if (i + 1 > TrailCountA)
{
TrailLevel.interactable = false;
}
if (TrailLevel.interactable)
{
Trains[CurrentCarToSpawn].gameObject.active = true;
Mines[CurrentCarToSpawn].gameObject.active = true;
}
}
text.text = PlayerPrefs.GetInt("TrailCountA").ToString();
}
}
From what I can see with your code, this is how I would approach it:
using System.Collections;
using System.Collections.Generic;
using UnityEngine; using UnityEngine.UI;
public class GameManager : MonoBehaviour
{
public Button[] TrailLevel;
public GameObject[] Cars, Trails;
public Text text;
public int CurrentCarToSpawn = 0;
private void Start()
{
// Load the current car. ADDED
CurrentCarToSpawn = PlayerPrefs.getInt("savedSelection", 0);
// Since we are loading the last selection, we need to call our
// instantiation method so it can activate the appropriate
// GameObjects.
InstantiateCar();
}
private void FixedUpdate()
{
UpdateCar();
}
public void InstantiateCar()
{
TrailLevel[CurrentCarToSpawn].gameObject.active = false;
MineLevel[CurrentCarToSpawn+1].interactable = true;
PlayerPrefs.SetInt("TrailCountA", PlayerPrefs.GetInt("TrailCountA") + 1);
// Save that this is our current selection.
PlayerPrefs.SetInt("savedSelection", CurrentCarToSpawn);
PlayerPrefs.Save();
CurrentCarToSpawn++;
UpdateCar();
}
void UpdateCar()
{
int TrailCountA= PlayerPrefs.GetInt("TrailCountA", 1);
for (int i = 0; i < TrailLevel.Length; i++)
{
if (i + 1 > TrailCountA)
{
TrailLevel.interactable = false;
}
if (TrailLevel.interactable)
{
Trains[CurrentCarToSpawn].gameObject.active = true;
Mines[CurrentCarToSpawn].gameObject.active = true;
}
}
text.text = PlayerPrefs.GetInt("TrailCountA").ToString();
}
}
I'm trying to make a simple condition:
If the value I have, is less than the price it costs the item, the button is disabled.
If the value I have, is greater than or equal to the price it costs the item the button is enabled and I can buy it.
But when I test, I have some problems.
First, if I have less than the item cost the button is enabled, and only when I click on it it is when it disables.
Second, if I have less than the item cost and I click on it it disables, but if I get enough to purchase the item, the button is not enabled again.
How do I to be checked these variables all the time? If I have enough the button is enabled if you do not have it disables.
Bellow my scrip:
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
public class BuySkin : MonoBehaviour {
public int price;
public Button buyBee1;
void OnEnable ()
{
//Register Button Events
buyBee1.onClick.AddListener (() => buySkin (buyBee1));
}
public void buySkin(Button button)
{
if (BeeCoinScore.coin >= price) {
BeeCoinScore.coin -= price;
buyBee1.interactable = false;
}
if (BeeCoinScore.coin < price) {
buyBee1.interactable = false;
}
}
void OnDisable ()
{
//Un-Register Button Events
buyBee1.onClick.RemoveAllListeners ();
}
}
Try this out with some prefabs!
using UnityEngine;
using UnityEngine.UI;
using System.Collections;
using System.Collections.Generic;
public class GameController : MonoBehaviour
{
public int coins;
private int spherePrice = 100, cubePrice = 50;
public GameObject player;
public GameObject[] availablePrefabs;
public List<GameObject> mySkins;
public Button btnSphere, btnCube;
public Text txtSphere, txtCube;
void Start ()
{
string serializedMySkins = PlayerPrefs.GetString ("skins", "");
string serializedPlayer = PlayerPrefs.GetString ("player", "");
// skins desserialization
if (serializedMySkins == "")
mySkins = new List<GameObject> ();
else {
var a = serializedMySkins.Split (',');
for (int i = 0; i < a.Length; i++) {
if (a [i] == "Sphere") {
mySkins.Add (availablePrefabs [0]);
}
if (a [i] == "Cube") {
mySkins.Add (availablePrefabs [1]);
}
}
}
// player desserialization
if (serializedPlayer != "") {
if (serializedPlayer == "Sphere") {
player = availablePrefabs [0];
}
if (serializedPlayer == "Cube") {
player = availablePrefabs [1];
}
} else {
player = mySkins [0];
}
coins = PlayerPrefs.GetInt ("coins", 0);
coins = 1000;
}
void Update ()
{
if (mySkins.Contains (availablePrefabs [0])) {
txtSphere.text = "Usar esfera";
} else {
btnSphere.interactable = coins >= spherePrice;
}
if (mySkins.Contains (availablePrefabs [1])) {
txtCube.text = "Usar cubo";
} else {
btnCube.interactable = coins >= cubePrice;
}
}
public void play ()
{
player = (GameObject)Instantiate (player, new Vector2 (0, 0), Quaternion.identity);
}
public void verifySkin (GameObject skinPrefab)
{
if (mySkins.Contains (skinPrefab)) {
useSkin (skinPrefab);
} else if (coins >= priceOf (skinPrefab)) {
buySkin (skinPrefab, priceOf (skinPrefab));
}
}
public void buySkin (GameObject skinPrefab, int price)
{
mySkins.Add (skinPrefab);
coins -= price;
string skinsHash = "";
for (int i = 0; i < mySkins.Count; i++) {
skinsHash += mySkins [i].name + ",";
}
Debug.Log (skinsHash);
PlayerPrefs.SetInt ("coins", coins);
PlayerPrefs.SetString ("skins", skinsHash);
PlayerPrefs.Save ();
}
public void useSkin (GameObject skinPrefab)
{
player = skinPrefab;
PlayerPrefs.SetString ("player", player.name);
PlayerPrefs.Save ();
}
private int priceOf (GameObject skinPrefab)
{
if (skinPrefab == availablePrefabs [0])
return spherePrice;
else if (skinPrefab == availablePrefabs [1])
return cubePrice;
else
return 0;
}
}
OnEnable()is called when the object becomes enabled and active.
you need Update() as it is getting called every frame it will check whether your value is less than or greater than price of item.You may also try like this.
// I think that you are making an buymenu, so you can disable and enable your menu with ui button and check money you have
using System.Collections;
using UnityEngine.UI;
public class BuySkin : MonoBehaviour
{
public int price;
public static int money;// money you have
public Button thisbuyBee1;
public void buychkr()
{
if(price>= money)
{
thisbuyBee1.interactable = false;
}
else
{
thisbuyBee1.interactable = true;
}
}
void Update()
{
buychkr();
}
}