The script:
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class LightsEffects : MonoBehaviour
{
private Renderer[] renderers;
private float lastChangeTime;
private int greenIndex = 0;
public void LightsEffect(List<GameObject> objects, Color instantiateColor, Color colorEffect)
{
renderers = new Renderer[objects.Count];
for (int i = 0; i < renderers.Length; i++)
{
renderers[i] = objects[i].GetComponent<Renderer>();
renderers[i].material.color = Color.red;
}
// Set green color to the first one
greenIndex = 0;
renderers[greenIndex].material.color = Color.green;
}
/// <summary>
/// Running the effect
/// </summary>
/// <param name="changeDirection">Changing the lights movement directions - false = forward, true = backward.</param>
public void LightsEffectCore(float delay, bool changeDirection)
{
// Change color each `delay` seconds
if (Time.time > lastChangeTime + delay)
{
lastChangeTime = Time.time;
// Set color of the last renderer to red
// and the color of the current one to green
renderers[greenIndex].material.color = Color.red;
if (changeDirection == true)
{
Array.Reverse(renderers);
changeDirection = false;
}
greenIndex = (greenIndex + 1) % renderers.Length;
renderers[greenIndex].material.color = Color.green;
}
}
}
The part of the direction change:
if (changeDirection == true)
{
Array.Reverse(renderers);
changeDirection = false;
}
The problem is that now it will be true all the time and next time it will be changed to false i will need to reverse the array again but then since it's false it will reverse the array all the time:
if (changeDirection == true)
{
Array.Reverse(renderers);
changeDirection = false;
}
else
{
Array.Reverse(renderers);
changeDirection = true;
}
But now when it will be change back to false or if the game start as false it will change right back to true and will reverse the array and so on.
I want that when it's true keep it true and once changing it to false keep it false until changing again.
I got messed the flag states and the reversing.
Related
Hello i have 2 scripts one is for Flashlight "Battery UI script" Storing how many batteries i have left
for reload a flashlight max 5 that script is working totally fine but when i try to loot a battery it occur a error
and i dont understand why because i setup input "Use" in Project Settings correctly because another key "Grab" is working fine on Key "Q" but "Use" on Key "F" not working and i getting this error what i do wrong?!
i will paste code bellow with screenshots as well
" Get Error in this line (see screenshot) "
Click for code screenshot error
battery GUI on top right corner 3/5 collected batteries
using UnityEngine;
using UnityEngine.UI;
using System.Collections;
public class BatteryPickup : MonoBehaviour {
private Transform myTransform;
private GameObject MessageLabel;
private GameObject BatteryUIScript;
public bool EnableMessageMax = true;
public bool Enabled;
public float BatteryAdd = 0.01f;
public AudioClip pickupSound;//sound to playe when picking up this item
public string MaxBatteryText = "You have Max Batteries";
public Color MaxBatteryTextColor = Color.white;
public bool PickupMessage;
public string PickupTEXT = "Battery +1";
public Color PickupTextColor = Color.white;
void Start () {
myTransform = transform;//manually set transform for efficiency
}
public void UseObject (){
BatteryUIScript = GameObject.Find("Flashlight");
BatteryUI BatteryComponent = BatteryUIScript.GetComponent<BatteryUI>();
if (BatteryComponent.EnableBattery == true)
{
Enabled = true;
}
if(BatteryComponent.EnableBattery == false){
Enabled = false;
if(EnableMessageMax){StartCoroutine(MaxBatteries());}
}
if(Enabled){
StartCoroutine(SendMessage());
BatteryComponent.Batteries += BatteryAdd;
if(pickupSound){AudioSource.PlayClipAtPoint(pickupSound, myTransform.position, 0.75f);}
this.GetComponent<Renderer>().enabled = false;
this.GetComponent<Collider>().enabled = false;
}
}
public IEnumerator SendMessage (){
MessageLabel = GameObject.Find("UI_MessageLabel");
Text Message = MessageLabel.GetComponent<Text>();
/* Message Line */
EnableMessageMax = false;
Message.enabled = true;
Message.color = PickupTextColor;
Message.text = PickupTEXT;
yield return new WaitForSeconds(2);
Message.enabled = false;
EnableMessageMax = true;
}
public IEnumerator MaxBatteries (){
MessageLabel = GameObject.Find("UI_MessageLabel");
Text Message = MessageLabel.GetComponent<Text>();
/* Message Line */
if(!Enabled){
EnableMessageMax = false;
Message.enabled = true;
Message.color = MaxBatteryTextColor;
Message.text = MaxBatteryText;
yield return new WaitForSeconds(3);
Message.CrossFadeAlpha(0f, 2.0f, false);
yield return new WaitForSeconds(4);
Message.enabled = false;
EnableMessageMax = true;
}
}
}
I am trying to prevent a click if a move is invalid based on an the int lastClickedValuex and o respectively
Not sure how to do the check. Last thing I have to do before my code is complete and driving me insane.
Basically
if (lastclickedvaluex >= boardsquarevalue || boardsquarevalue == 0){
allow move;
} else {
dont show the sprite;
dont switch turns;
restart the players turn;
dont change the value of lastclickedvaluex;
make like player never clicked I suppose;
}
Im at hour 20 so its probably something immensely stupid.
using UnityEngine;
using UnityEngine.UI;
public class GameController : MonoBehaviour
{
public int playerTurn; //0 = X && 1 = O
public int turnCountX; //Tally Player X Turns
public int turnCountO; //Tally Player O Turns
public GameObject[] bigTurnIcons; //Player Icons Array
public Sprite[] playerGamePieces; //GamePieces Array
public Button[] gameBoardSquares; //GameBoard Array
public int lastPlayedSquareValueX; //Store Value of Last Clicked Square
public int lastPlayedSquareValueO; // ""
public bool gameOver; // End Game
public bool isValidMove; // Check For Valid Move
public int boardSquareValue; //Value of Each Square from Value Script
public int[] markedSquare; //Win Check Array
void Awake()
{
GameSetup();
}
public void GameSetup()
{
isValidMove = true;
playerTurn = 0; //Set Player Turn To X Goes First
turnCountX = 0; //Set X Turn Count to 0
turnCountO = 0; //Set O Turn COunt to 0
bigTurnIcons[0].SetActive(true); //Set X Turn Icon to Active
bigTurnIcons[1].SetActive(false); //Set O Turn Icon to Inactive
for (int i = 0; i < gameBoardSquares.Length; i++) //Initialize Squares (GameBoard) Array
{
gameBoardSquares[i].interactable = true; //Make All Squares Clickable
gameBoardSquares[i].GetComponent<Image>().sprite = null; //Set TurnIcons To Off
}
for (int j = 0; j < markedSquare.Length; j++) //Initialize MarkedSquare Array
{
markedSquare[j] = -100; //Set Value To Wacky Number So It Doesn't Interfere With Formula FOr Win Check
}
}
public void PlaySquareButton(int WhichNumber) //OnClick Function
{
markedSquare[WhichNumber] = playerTurn + 1; //OnClick Store Which PLayer Clicked Which Square
gameBoardSquares[WhichNumber].image.sprite = playerGamePieces[playerTurn]; //OnClick Check To Place Correct Symbol (GamePiece)
gameBoardSquares[WhichNumber].interactable = false; //OnClick Set Button.Interactable To False So It Cannot Be CLicked Again
boardSquareValue = gameBoardSquares[WhichNumber].GetComponent<Value>().boardSquareValue; //OnClick Set The Square's Value To The BoardSquareValue Variable in the Value Script
if (turnCountO > 3 || turnCountX > 3) //Check For Wins After 3 Turns
{
CheckForWinner(); //Iterate Through The MarkedSpaces Array To Check For A Winner
}
if (playerTurn == 0)
{
playerTurn = 1; //Player O Turn
bigTurnIcons[0].SetActive(false);
bigTurnIcons[1].SetActive(true);
Debug.Log(boardSquareValue); //Show Value of Clicked Square in Console
lastPlayedSquareValueX = boardSquareValue; //Set Last CLicked Value to Current Clicked Square
turnCountX++; //Increment Player Turn Count
}
else
{
playerTurn = 0;
bigTurnIcons[0].SetActive(true);
bigTurnIcons[1].SetActive(false);
Debug.Log(boardSquareValue);
lastPlayedSquareValueO = boardSquareValue;
turnCountO++;
}
}
Thank you for any help
GameBoard
As per your comments, you may be missing:
public PlaySquareButton(int WhichNumber){
if(playerTurn)
{
if(WhichNumber > lastPlayedSquareValueX){
markedSquare[WhichNumber] = playerTurn + 1; //OnClick Store Which PLayer Clicked Which Square
gameBoardSquares[WhichNumber].image.sprite = playerGamePieces[playerTurn]; //OnClick Check To Place Correct Symbol (GamePiece)
gameBoardSquares[WhichNumber].interactable = false; //OnClick Set Button.Interactable To False So It Cannot Be CLicked Again
...
}
}else{
if(WhichNumber > lastPlayedSquareValueO){
markedSquare[WhichNumber] = playerTurn + 1; //OnClick Store Which PLayer Clicked Which Square
gameBoardSquares[WhichNumber].image.sprite = playerGamePieces[playerTurn]; //OnClick Check To Place Correct Symbol (GamePiece)
gameBoardSquares[WhichNumber].interactable = false; //OnClick Set Button.Interactable To False So It Cannot Be CLicked Again
...
}
}
}
Basically before you start your functionality you check if the WhichNumber, that I guess comes from the square once clicked, is greater than the lastPlayedSquareValueX
So I have a canvas which doesnt get destroyed because it holds and slider whih shows a progressbar. It also has a button which is interactable when the progress of loading is 0.9.. The problem i am having is when I click the button (see activateNewScene()). Basically what happens is when I click on the button is that i load my scene and my disable my canvas. But the problem is that after I disable my canvas the old scene is still shown for about 0.5 sec and than the new scene is loaded. What I want is that after the canvas gets disabled the new scene should show up. without seeing the old scene for short time.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class SceneLoaderGameObject : MonoBehaviour {
private SceneLoader sl;
public Canvas cav;
void Start () {
sl = new SceneLoader ();
cav.GetComponent<Canvas> ().enabled = false;
DontDestroyOnLoad (this.gameObject);
DontDestroyOnLoad (cav.transform.parent);
}
public void setNewNameAndLoadScene(string name){
if (cav != null) {
Slider slid = cav.transform.GetChild (1).GetComponent<Slider> ();
Text tx = cav.transform.GetChild (2).GetComponent<Text> ();
Button bttn = cav.transform.GetChild (3).GetComponent<Button> ();
sl.setNewScene (name);
sl.setSliderAndTextToChange (slid, tx);
bttn.onClick.AddListener (() => activateNewScene ());
cav.GetComponent<Canvas> ().enabled = true;
cav.GetComponent<Canvas> ().sortingOrder = 1;
StartCoroutine (sl.LoadAsynchron (name, bttn));
}
}
public void activateNewScene(){
sl.AsgetOP().allowSceneActivation=true;
cav.GetComponent<Canvas> ().sortingOrder = 1;
cav.GetComponent<Canvas> ().enabled = false;
}
}
EDIT: Here is the code which loads the scene:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
public class SceneLoader {
AsyncOperation operation;
string sceneName;
private Text txx =null;
private Slider slider=null;
public SceneLoader(){
}
public void setSliderAndTextToChange(Slider sl, Text tx){
txx = tx;
slider = sl;
}
public void setNewScene(string sceneName){
if (sceneName.Length == 0) {
throw new UnityException ("Please enter a name");
}
this.sceneName = sceneName;
}
public IEnumerator LoadAsynchron(string myMain, Button bttn){
operation = SceneManager.LoadSceneAsync (myMain);
operation.allowSceneActivation = false;
while (operation.isDone == false) {
float progress = Mathf.Clamp01 (operation.progress / 0.9f);
slider.value = progress;
txx.text = progress * 100f + " %";
if (progress * 100f == 100f) {
bttn.interactable = true;
}
yield return null;
}
}
public AsyncOperation AsgetOP(){
return operation;
}
}
I see. I think its because of the canvas. Try to put the code where you disable the canvas and set the order to 0 in the function OnLevelWasLoaded . So basically this:
void OnLevelWasLoaded(){
cav.GetComponent<Canvas> ().sortingOrder = 0;
cav.GetComponent<Canvas> ().enabled = false;
}
public void activateNewScene(string name){
sl.AsgetOP ().allowSceneActivation = true;
Scene sc = SceneManager.GetSceneByName(name);
if (sc.IsValid ()) {
SceneManager.SetActiveScene(sc);
}
}
I added the scene name to the function to activate it.
When SceneManager was first released, it is known that isDone will only be true in when two conditions are met:
1.When the scene is done loading
2.When scene is activated
I don't know if this is still true but I will assume it is.
Basically, when you set allowSceneActivation to false, condition 2 is not met and you will run into issues. It looks like while (operation.isDone == false) will still be executing causing bttn.interactable = true; to also be executing every frame while you are trying to load new scene. This is my guess.
Replace while (operation.isDone == false) with while (operation.progress < 0.9f) then add bttn.interactable = true; to the end of that function just in-case.
public IEnumerator LoadAsynchron(string myMain, Button bttn)
{
operation = SceneManager.LoadSceneAsync(myMain);
operation.allowSceneActivation = false;
while (operation.progress < 0.9f)
{
float progress = Mathf.Clamp01(operation.progress / 0.9f);
slider.value = progress;
txx.text = progress * 100f + " %";
if (progress * 100f == 100f)
{
bttn.interactable = true;
}
yield return null;
}
if (!bttn.interactable)
bttn.interactable = true;
}
If that does not work, I suggest you use SceneManager.SetActiveScene function. See the enableScene function from this post. I've also seen bugs with this, you may want to file for bug report from the Editor if this is still a problem.
thanks for reading.
I'm currently building a small memory card game in Unity using C#. I have the main portion of code finished but when I press the play button on a certain scene Unity freezes.
I believe it is due to an infinite While loop, but I can not find the issue. I would really appreciate any help anyone can offer. I will leave my code below. Thanks in advance.
using System.Collections;
using System.Collections.Generic;
using UnityEngine.UI;
using UnityEngine.SceneManagement;
using UnityEngine;
public class Pairs : MonoBehaviour {
public Sprite[] face; //array of card faces
public Sprite back;
public GameObject[] deck; //array of deck
public Text pairsCount;
private bool deckSetUp = false;
private int pairsLeft = 13;
// Update is called once per frame
void Update () {
if (!deckSetUp)
{
SetUpDeck();
}
if (Input.GetMouseButtonUp(0)) //detects left click
{
CheckDeck();
}
}//Update
void SetUpDeck()
{
for (int ix = 0; ix < 2; ix++)
{
for(int i = 1; i < 14; i++)//sets up card value (2-10 JQKA)
{
bool test = false;
int val = 0;
while (!test)
{
val = Random.Range(0, deck.Length);
test = !(deck[val].GetComponent<Card>().SetUp);
}//while
//sets up cards
deck[val].GetComponent<Card>().Number = i;
deck[val].GetComponent<Card>().SetUp = true;
}//nested for
}//for
foreach (GameObject crd in deck)
{
crd.GetComponent<Card>().setUpArt();
}
if (!deckSetUp)
{
deckSetUp = true;
}
}//SetUpDeck
public Sprite getBack()
{
return back;
}//getBack
public Sprite getFace(int i)
{
return face[i - 1];
}//getFace
void CheckDeck()
{
List < int > crd = new List<int>();
for(int i = 0; i < deck.Length; i++)
{
if(deck[i].GetComponent<Card>().State == 1)
{
crd.Add(i);
}
}
if(crd.Count == 2)
{
CompareCards(crd);
}
}//CheckDeck
void CompareCards(List<int> crd)
{
Card.NO_TURN = true; //stops cards turning
int x = 0;
if(deck[crd[0]].GetComponent<Card>().Number ==
deck[crd[1]].GetComponent<Card>().Number)
{
x = 2;
pairsLeft--;
pairsCount.text = "PAIRS REMAINING: " + pairsLeft;
if(pairsLeft == 0) // goes to home screen when game has been won
{
SceneManager.LoadScene("Home");
}
}
for(int j = 0; j < crd.Count; j++)
{
deck[crd[j]].GetComponent<Card>().State = x;
deck[crd[j]].GetComponent<Card>().PairCheck();
}
}//CompareCards
}
I believe the issue lies in the while(!test) but i do not know why test never become true.
using System.Collections;
using System.Collections.Generic;
using UnityEngine.UI;
using UnityEngine;
public class Card : MonoBehaviour {
public static bool NO_TURN = false;
[SerializeField]
private int cardState; //state of card
[SerializeField]
private int cardNumber; //Card value (1-13)
[SerializeField]
private bool _setUp = false;
private Sprite back; //card back (Green square)
private Sprite face; //card face (1-10 JQKA)
private GameObject pairsManager;
void Begin()
{
cardState = 1; //cards face down
pairsManager = GameObject.FindGameObjectWithTag("PairsManager");
}
public void setUpArt()
{
back = pairsManager.GetComponent<Pairs>().getBack();
face = pairsManager.GetComponent<Pairs>().getFace(cardNumber);
turnCard();//turns the card
}
public void turnCard() //handles turning of card
{
if (cardState == 0)
{
cardState = 1;
}
else if(cardState == 1)
{
cardState = 0;
}
if (cardState == 0 && !NO_TURN)
{
GetComponent<Image>().sprite = back; // shows card back
}
else if (cardState == 1 && !NO_TURN)
{
GetComponent<Image>().sprite = face; // shows card front
}
}
//setters and getters
public int Number
{
get {return cardNumber;}
set { cardNumber = value;}
}
public int State
{
get { return cardState; }
set { cardState = value; }
}
public bool SetUp
{
get { return _setUp; }
set { _setUp = value; }
}
public void PairCheck()
{
StartCoroutine(pause ());
}
IEnumerator pause()
{
yield return new WaitForSeconds(1);
if (cardState == 0)
{
GetComponent<Image>().sprite = back;
}
else if (cardState == 1)
{
GetComponent<Image>().sprite = face;
}
}
}
Thank you for reading, I will post a link to the github repository if that helps.
github repository
Your deck array has at least one card in it that has _setUp set to true which would make it go in a infinite loop.
The reason it goes in a infinite loop is because it will have set all available _setUp to true and it would keep looking for _setUp that are set to false and it will never find any.
The reason you need at least 26 object that have _setUp to false is because in the nested for loop you loop 13 times and then you do that twice which gives a total of 26 loops. So you need at least 26 objects.
What you can do to make sure that they're all false is to set them all to false before entering the for loop
for(int i = 0; i < deck.Length; i++)
{
deck[i].GetComponent<Card>().SetUp = false;
}
Good Day! I have this code but I have an error, for example (I set two players me, and 1 computer). I take the first turn, and the dice respawn with a value of 4 (just an example), the game piece then move from 1st to 4th tile when I touch the screen, when computer turns, it also move from 1st to 4th tile (because I set the result to 4 just an example). Now its my turn again, the dice never respawn and it doesn't wait to touch the screen if (Input.GetMouseButtonDown(0)) and move again by 4...
public class singlePlay : MonoBehaviour {
//Player
public GameObject[] playerprefab;
//Player Clone
public GameObject[] playerprefabC;
//Game Cards and Dice
public GameObject[] situationCard;
public GameObject dice;
int diceresult;
//Game Cards and Dice clone
public GameObject diceclone;
public int currentPlayer;
public int compPlayer;
public int playerTurn;
public string compPlayerstring;
public string playerTurnstring;
//GUI Boolean
bool play = false;
//Game Boolean
bool pieces = false;
bool giveturn = false;
bool myturn = false;
bool diceSpawn = false;
bool moving = false;
bool routine = false;
bool checking = false;
bool compturn = false;
//icon1
public GameObject[] icon;
//population
int[] population = new int[3];
//Tile
public GameObject[] Tile;
int[] playerTile = new int[3]; //current location
int[] playerTileUp = new int [3]; // updated location after dice roll
bool endTurn = false;
void Update ()
{
if (giveturn == true) {
int h = 0;
Giveturn(h);
giveturn = false;
}
if (play == true) {
if (pieces == true){
SpawnPlayer();
pieces = false;
}
if (myturn == true){
compturn = false;
if(diceSpawn == true) {
dice.transform.position = new Vector3(0,0,-1);
diceclone = Instantiate(dice, dice.transform.position, Quaternion.identity) as GameObject;
diceSpawn = false;
}
if (Input.GetMouseButtonDown(0))
{
Debug.Log("click");
diceresult = 4;
Destroy(diceclone);
moving = true;
Updateposition(diceresult);
}
}
else
{
Debug.Log("comp");
myturn = false;
diceresult = 4;
moving = true;
Updateposition(diceresult);
}
}
}
void Giveturn(int k)
{
Debug.Log("" + k);
currentPlayer = k;
if (k == playerTurn) {
Debug.Log("Yes");
compturn = false;
myturn = true;
diceSpawn = true;
moving = false;
}
else
{
Debug.Log("No");
compturn = true;
myturn = false;
moving = false;
}
}
void Updateposition(int diceresult)
{
if (moving == true) {
playerTileUp[currentPlayer] = playerTile[currentPlayer] + diceresult;
Debug.Log("" + playerTileUp[currentPlayer]+ " " +currentPlayer);
routine = true;
StartCoroutine(MyMethod());
}
moving = false;
}
IEnumerator MyMethod()
{
if (routine == true) {
if (myturn == true) {
compturn = false;
}
else
{
myturn = false;
}
int f = playerTile[currentPlayer] + 1;
Debug.Log(" " + currentPlayer );
while (f <= playerTileUp[currentPlayer]) {
Debug.Log("waiting");
yield return new WaitForSeconds(1);
Debug.Log(" " + Tile[f]);
playerprefabC[currentPlayer].transform.position = Tile[f].transform.position;
Debug.Log(" " + currentPlayer);
f++;
}
checking = true;
TrapCheck();
}
routine = false;
}
void TrapCheck()
{
if (checking == true) {
if (playerTileUp[currentPlayer] == 8) {
Debug.Log("Trap spawning");
Instantiate(situationCard[0], situationCard[0].transform.position, Quaternion.identity);
population[currentPlayer] = population[currentPlayer] -1;
}
playerTile[currentPlayer] = playerTileUp[currentPlayer];
Endturn();
myturn = false;
compturn = false;
checking = false;
}
}
void Endturn()
{
currentPlayer++;
Debug.Log(" " + currentPlayer);
if (currentPlayer > compPlayer) {
currentPlayer = 0;
}
Giveturn(currentPlayer);
}
}
There are few things that I could see wrong there already. First while the coroutine is running, it seems you are not preventing the update from running since play remains true. In TrapCheck, you call EndTurn which call GiveTurn and sets myTurn (true) and compTurn (false) booleans. But those two are reset in TrapCheck, myTurn is set back to false. You need to rethink the logic of your class.
A solution would be to use delegate. This would remove many of your boolean that you set and reset. Here is a basic idea:
Action currentUpdate;
bool playerTurn = true;
void Start(){
SetTurn();
}
void Update(){
if(currentUpdate != null)currentUpdate();
}
void SetTurn(){
// Prepare initial setting for moving
if(playerTurn == true){ currentUpdate = PlayerTurn; }
else{ currentUpdate = CompTurn; }
playerTurn = !playerTurn;
}
void PlayerTurn(){
// Check input
// Get dice value
currentUpdate = Move;
}
void CompTurn(){
// Get dice value
currentUpdate = Move;
}
void Move(){
if(position != target){
}else{
SetTurn();
}
}
This is fairly simplified but once you get the thing about delegate (maybe you already know), this will make it all so much more flexible.