UI canvas Index - c#

I have and script below that does the following:
The player starts with 3 hearts [0] if it suffers damage loses one heart and changes the texture to 2 hearts 1, if he wins one extra heart back to the texture [0] .. If you're having only one heart [ 2] and suffers an injury, the game ends.
This code works perfectly, but I would like to convert it to UI Canvas Image. How do I do this?
using UnityEngine;
using System.Collections;
public class Hearts : MonoBehaviour {
public Texture2D[]initialHeart;
private int hearts;
private int currentHearts;
// Use this for initialization
void Start () {
GetComponent<GUITexture>().texture = initialHeart[0];
hearts = initialHeart.Length;
}
// Update is called once per frame
void Update () {
}
public bool TakeHeart()
{
if (hearts < 0) {
return false;
}
if (currentHearts < (hearts - 1)) {
currentHearts += 1;
GetComponent<GUITexture> ().texture = initialHeart [currentHearts];
return true;
} else {
return false;
}
}
public bool AddHeart() {
if (currentHearts > 0) {
currentHearts -= 1;
GetComponent<GUITexture> ().texture = initialHeart [currentHearts];
return true;
} else {
return false;
}
}
}
Edit:
Look what is happening:
In the object inspector, HealthBar I put 3 hearts as image (first imagem attached). But when I go into the script and try to select the images to be changed according to the user's progress, is not allowed to use image, objects only (second imagem attached).

1.Change Texture2D to Sprite.
2.Then change GetComponent<GUITexture>().texture = initialHeart[0]; to GetComponent<Image>().sprite = initialHeart[0];
3.And the two GetComponent<GUITexture> ().texture = initialHeart [currentHearts]; to GetComponent<Image>().sprite = initialHeart[currentHearts];
Note: Doing GetComponent<GUITexture> ().texture and GetComponent<Image>().sprite is not good. If you need to access any component multiple times, you need to cache it. That means you do GetComponent<Image>() once and save it to variable. That variable you can now use many other times. I noticed this in your other questions/codes too and decided it's time to tell you that. Take a look at the code below to understand it more. Code not tested but it compiles.
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
public class Hearts : MonoBehaviour
{
public Sprite[] initialHeart;
private int hearts;
private int currentHearts;
// Use this for initialization
//Used for chaching Image so that you won't be doing GetComponent<Image>(); each time
Image heartImage;
void Start()
{
//Cache the Image once so that you won't be doing GetComponent<Image>(); each time
heartImage = GetComponent<Image>();
heartImage.sprite = initialHeart[0];
hearts = initialHeart.Length;
}
// Update is called once per frame
void Update()
{
}
public bool TakeHeart()
{
if (hearts < 0)
{
return false;
}
if (currentHearts < (hearts - 1))
{
currentHearts += 1;
heartImage.sprite = initialHeart[currentHearts];
return true;
}
else
{
return false;
}
}
public bool AddHeart()
{
if (currentHearts > 0)
{
currentHearts -= 1;
heartImage.sprite = initialHeart[currentHearts];
return true;
}
else
{
return false;
}
}
}
EDIT: I change changed the initialHeart from Image to Sprite so that you can put Sprite directly. Don't forget to remove GUITexture from the GameObject this script will be attached to. Also make sure that the GameObject you are attaching this script to has an Image attached to it. If you don't, GetComponent<Image>(); will fail.

Related

How to get Panel to show when character lands on a specific position on game board after dice roll in Unity

I have a 3D board game in Unity. I would like to move my character without having to press a key, but most importantly I would like to show a dynamic panel in canvas for whatever square the character lands on. So far I have the dice rolling and the character moving (after pressing a key) the correct amount of squares, but I am unable to figure out how to activate the panel based on the square color. Any help would be appreciated.
Here is my CharacterScript:
public class CharacterScript : MonoBehaviour
{
public Path currentPath;
public int squarePosition;
public int squares;
bool isMoving;
public GameObject PinkSquarePanel = GameObject.FindGameObjectWithTag("PinkSquare");
public GameObject CyanSquarePanel = GameObject.FindGameObjectWithTag("CyanSquare");
public GameObject WhiteSquarePanel = GameObject.FindGameObjectWithTag("WhiteSquare");
// Update is called once per frame
void Update()
{
if (Input.GetKeyDown(KeyCode.Escape) && !isMoving)
{
squares = DiceNumberTextScript.diceNumber;
}
StartCoroutine(Move());
if (squares == 0)
{
ActivateSquarePanel();
}
}
IEnumerator Move()
{
if (isMoving)
{
yield break;
}
isMoving = true;
while (squares > 0)
{
Vector3 nextPosition = currentPath.squareList[squarePosition + 1].position;
while (MoveToNextSquare(nextPosition))
{
yield return null;
}
yield return new WaitForSeconds(0.1f);
squares--;
squarePosition++;
}
isMoving = false;
}
bool MoveToNextSquare(Vector3 goal)
{
return goal != (transform.position = Vector3.MoveTowards(transform.position, goal, 4f * Time.deltaTime));
}
void ActivateSquarePanel()
{
if (squarePosition.Equals(PinkSquarePanel))
{
PinkSquarePanel.GetComponent<CanvasGroup>().alpha = 1;
}
else if (squarePosition.Equals(CyanSquarePanel))
{
CyanSquarePanel.GetComponent<CanvasGroup>().alpha = 1;
}
else if (squarePosition.Equals(WhiteSquarePanel))
{
WhiteSquarePanel.GetComponent<CanvasGroup>().alpha = 1;
}
}
}
And here is my PathScript:
public class Path : MonoBehaviour
{
Transform[] squareObjects;
public List<Transform> squareList = new List<Transform>();
GameObject[] PinkSquares = GameObject.FindGameObjectsWithTag("PinkSquare");
PinkSquare[] pinkList = new PinkSquare[1];
GameObject[] CyanSquares = GameObject.FindGameObjectsWithTag("CyanSquare");
CyanSquare[] cyanList = new CyanSquare[1];
GameObject[] WhiteSquares = GameObject.FindGameObjectsWithTag("WhiteSquare");
WhiteSquare[] whiteList = new WhiteSquare[1];
private void OnDrawGizmos()
{
Gizmos.color = Color.black;
FillSquares();
for (int i = 0; i < squareList.Count; i++)
{
Vector3 currentPosition = squareList[i].position;
if (i > 0)
{
Vector3 previousPosition = squareList[i - 1].position;
Gizmos.DrawLine(previousPosition, currentPosition);
if(currentPosition.Equals(PinkSquares))
{
pinkList[i] = new PinkSquare();
}
else if (currentPosition.Equals(CyanSquares))
{
cyanList[i] = new CyanSquare();
}
else if (currentPosition.Equals(WhiteSquares))
{
whiteList[i] = new WhiteSquare();
}
}
}
}
void FillSquares()
{
squareList.Clear();
squareObjects = GetComponentsInChildren<Transform>();
foreach (Transform square in squareObjects)
{
if (square != this.transform)
{
squareList.Add(square);
}
}
}
}
I believe your issue is in your comparisons, you are trying to use an Equals to compare your currentPosition which is a Vector3 type to a GameObject[] which is an array of gameObjects. As I mentioned in my comments, this comparison will always fail as an array of gameObjects can not be equal to a vector.
Instead of using these lines, try this line:
if(squareList[i].gameObject.tag.CompareTag("PinkSquare")
The full snippet of if else would look like
if(squareList[i].gameObject.tag.CompareTag("PinkSquare")
{
pinkList[i] = new PinkSquare();
}
else if(squareList[i].gameObject.tag.CompareTag("CyanSquare")
{
cyanList[i] = new CyanSquare();
}
else if(squareList[i].gameObject.tag.CompareTag("WhiteSquare")
{
whiteList[i] = new WhiteSquare();
}
Your CharacterScript is going to need to get the gameObject or Transform from the Path script as it is only keeping track of indexes. Your issue in this script is you are comparing an integer to a GameObject which would never be true. I would also recommend not using OnDrawGizmos() as it is an editor only script and should only be used to render editor debugging tools. The only reference to a Gizmo I see in the function is Gizmos.color = Color.black; which does nothing as you are not rendering a gizmo anywhere. I would move this code to a different function and call it from your CharacterScript. Have the return type be GameObject or Transform of the square you are on, so the CharacterSCript can check which color it lands on. Using an Integer nor Vector3 to compare to a GameObject[] will never work.
I am not sure if there are issues elsewhere in the code, but as this comparison would always fail, none of these statements would get broken into. What this means is your panels would never have the chance to get their alpha set nor get created.

How to fix the items in my shop staying locked until both items individual if-statement requirements are met?

I already have character selection down, but what I can't get working is the unlocking feature of my game's shop. My idea for how the player would unlock characters is that there is an invisible game object that will disappear once the player clicks on it with sufficient funds. This will then allow him to use the character because he has just unlocked it. My problem is that the 2 current game object locks I have are both not interactable until the player meets both of the if-statement requirements.
Also, the gold game object is a gold background behind the player that is supposed to go away after the character is purchased and owned.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class Locked : MonoBehaviour
{
public static int totalScore;
public Button locked;
public Text totalscore;
public GameObject gold;
int wizNum;
int snailNum;
private void Start()
{
totalScore = PlayerPrefs.GetInt("TotalScore", 0);
wizNum = PlayerPrefs.GetInt("WizNum", 0);
snailNum = PlayerPrefs.GetInt("SnailNum", 0);
if (wizNum == 1)
{
gold.gameObject.SetActive(false);
locked.gameObject.SetActive(false);
}
if (snailNum == 1)
{
gold.gameObject.SetActive(false);
locked.gameObject.SetActive(false);
}
}
private void Update()
{
if (totalScore >= 500 && wizNum == 0)
locked.interactable = true;
else
locked.interactable = false;
if (totalScore >= 1500 && snailNum == 0)
locked.interactable = true;
else
locked.interactable = false;
}
public void BuyWizard()
{
totalScore -= 500;
PlayerPrefs.SetInt("TotalScore", totalScore);
totalscore.text = PlayerPrefs.GetInt("TotalScore", 0).ToString();
PlayerPrefs.SetInt("WizNum", 1);
locked.gameObject.SetActive(false);
gold.gameObject.SetActive(false);
}
public void BuySnail()
{
totalScore -= 1500;
PlayerPrefs.SetInt("TotalScore", totalScore);
totalscore.text = PlayerPrefs.GetInt("TotalScore", 0).ToString();
PlayerPrefs.SetInt("SnailNum", 1);
locked.gameObject.SetActive(false);
gold.gameObject.SetActive(false);
}
}

I have a for loop in C#, which works in conjuction with Unity engine. But how do i make it so it only calls the loop once?

To give some context:
In unity I have 2 boxes, which are both tagged "box"
One box is on a plane and the other in the air, when the game is played on box falls on the other.
Here is the console for the engine:
Material 1 (UnityEngine.Material)
UnityEngine.Debug:Log(Object)
colourChangeArray:OnCollisionEnter(Collision) (at Assets/colourChangeArray.cs:28)
With material 1 changing to material 2, 3, 4 to 5 and then doing the 1-5 cycle 10-20 times
Below is the code i'm using
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class colourChangeArray : MonoBehaviour
{
public int trigger = 1;
public Material[] material;
Renderer rend;
// Use this for initialization
void Start()
{
rend = GetComponent <Renderer> ();
rend.enabled = true;
rend.sharedMaterial = material[0];
}
// Update is called on collision
void OnCollisionEnter(Collision col)
{
if (col.gameObject.tag == "box")
{
for(int i = 0; i <material.Length; i++){
rend.sharedMaterial = material[i];
Debug.Log(rend.sharedMaterial);
}
}
else
{
rend.sharedMaterial = material[0];
Debug.Log(rend.sharedMaterial);
}
}
}
The cycle between materials happen a few times because of the internal bounciness of the objects in unity. You can decrease it somehow (which I don't remember) but, I had a similar case once and no matter how much you decrease that it happens. So the best approach would be to store a value indicating it has been done before like this:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class colourChangeArray : MonoBehaviour
{
public int trigger = 1;
public Material[] material;
Renderer rend;
private bool changeMaterialDone;
// Use this for initialization
void Start()
{
rend = GetComponent <Renderer> ();
rend.enabled = true;
rend.sharedMaterial = material[0];
changeMaterialDone = false;
}
// Update is called on collision
void OnCollisionEnter(Collision col)
{
if (!changeMaterialDone && col.gameObject.tag == "box")
{
changeMaterialDone = true;
for(int i = 0; i <material.Length; i++)
{
rend.sharedMaterial = material[i];
Debug.Log(rend.sharedMaterial);
}
}
else
{
rend.sharedMaterial = material[0];
Debug.Log(rend.sharedMaterial);
}
}
}
I hope it helps you :)

Blink GameObject

I am a bit of a noob to programming and I am trying to make a GameObject , deactivate and reactivate over a set amount of seconds.For example I want my star to slowly blink before it goes away, to create a cool looking effect. If there is a better way of using this method done with out using SetActive(false) and what not , please feel free to give me your method - This is my code , Sorry if its messy i gotta get better at this but i will in due time
Thanks guys
//Timers
public float ScoreTimer;
public float[] TimeMarkStamp;
//Scoring
public int totalCollStars;
[Space]
public int maxStars = 5;
public GameObject[] StarImages;
// Use this for initialization
void Start()
{
}
// Update is called once per frame
void Update()
{
ScoreTimer += Time.deltaTime;
if (ScoreTimer <= TimeMarkStamp[0])
{
Debug.Log("It works");
StarImages[0].SetActive(false);
}
else if (ScoreTimer <= TimeMarkStamp[1])
{
Debug.Log("It workds" + TimeMarkStamp[1]);
StarImages[1].SetActive(false);
}
else if (ScoreTimer <= TimeMarkStamp[2])
{
Debug.Log("It works" + TimeMarkStamp[2]);
StarImages[2].SetActive(false);
}
else if (ScoreTimer <= TimeMarkStamp[3])
{
//This is not working
InvokeRepeating("flickerEffect", 3f, 1f);
}
}
void flickerEffect()
{
bool flickCheck = false;
if (flickCheck == false)
{
StarImages[3].SetActive(true);
flickCheck = true;
}
else if (flickCheck == true)
{
StarImages[3].SetActive(false);
flickCheck = false;
}
}
}
If there is a better way of using this method done with out using
SetActive(false) and what not
Yes, there is a better way, other than using the SetActive function. You should change the alpha color of the GameObject from 0 to 1 back and forth. After that you can then disable the GameObject with SetActive. This saves how much garbage would have been generated when repeatedly calling the SetActive function.
If this is a 3D GameObject, change the Rendering Mode from Opaque(default) to Fade or Transparent.
A simple function that can do this:
void blink(GameObject obj, float blinkSpeed, float duration)
{
StartCoroutine(_blinkCOR(obj, blinkSpeed, duration));
}
IEnumerator _blinkCOR(GameObject obj, float blinkSpeed, float duration)
{
obj.SetActive(true);
Color defualtColor = obj.GetComponent<MeshRenderer>().material.color;
float counter = 0;
float innerCounter = 0;
bool visible = false;
while (counter < duration)
{
counter += Time.deltaTime;
innerCounter += Time.deltaTime;
//Toggle and reset if innerCounter > blinkSpeed
if (innerCounter > blinkSpeed)
{
visible = !visible;
innerCounter = 0f;
}
if (visible)
{
//Show
show(obj);
}
else
{
//Hide
hide(obj);
}
//Wait for a frame
yield return null;
}
//Done Blinking, Restore default color then Disable the GameObject
obj.GetComponent<MeshRenderer>().material.color = defualtColor;
obj.SetActive(false);
}
void show(GameObject obj)
{
Color currentColor = obj.GetComponent<MeshRenderer>().material.color;
currentColor.a = 1;
obj.GetComponent<MeshRenderer>().material.color = currentColor;
}
void hide(GameObject obj)
{
Color currentColor = obj.GetComponent<MeshRenderer>().material.color;
currentColor.a = 0;
obj.GetComponent<MeshRenderer>().material.color = currentColor;
}
Usage:
void Start()
{
blink(gameObject, 0.2f, 5f);
}
If this is a SpriteRender, you have to replace all the obj.GetComponent<MeshRenderer>().material.color code with obj.GetComponent<SpriteRenderer>().color.

Unity3d C# respawning

If I test my game in Unity and I respawn I get my 3 lifes back.
But when I build the game, and I respawn I only get 2 lifes back.
Here is my code (not the full code) that I used for the respawning:
public int StarterLives; // 3
public GameObject plr; // My Player
public float maxVoidDist; // -10
public Object respawnLevel; // Level01 (My first and only asset)
public Text LivesHolder; // The text object (UI)
private Vector3 respawnPoint; // This gets updated in Start() and becomes the first position of the player
private string deadLevel; // This gets updated in Start() and becomes the name of my respawnlevel
private int lives; // This gets updated in Start() and becomes StarterLives (3)
private bool delay1 = false;
void Update () {
if ((plr.transform.position.y <= maxVoidDist) && (delay1.Equals(false)))
{
delay1 = true;
if((lives - 1) <= 0)
{
Application.LoadLevel(deadLevel);
lives = StarterLives + 1;
} else
{
plr.transform.position = respawnPoint;
}
lives = lives - 1;
updateLives();
delay1 = false;
}
}
void updateLives()
{
LivesHolder.text = "Lives: " + lives;
}
Full code:
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
public class GameController : MonoBehaviour {
public int StarterLives;
public GameObject plr;
public float maxVoidDist;
public Object respawnLevel;
public Text LivesHolder;
private Vector3 respawnPoint;
private string deadLevel;
private int lives;
private bool delay1 = false;
void Awake()
{
QualitySettings.vSyncCount = 1;
}
// Use this for initialization
void Start () {
respawnPoint = plr.transform.position;
deadLevel = respawnLevel.name;
lives = StarterLives;
updateLives();
}
// Update is called once per frame
void Update () {
if ((plr.transform.position.y <= maxVoidDist) && (delay1.Equals(false)))
{
delay1 = true;
if((lives - 1) <= 0)
{
Application.LoadLevel(deadLevel);
lives = StarterLives + 1;
} else
{
plr.transform.position = respawnPoint;
}
lives = lives - 1;
updateLives();
delay1 = false;
}
}
void updateLives()
{
LivesHolder.text = "Lives: " + lives;
}
}
I see some strange things, in your code, I hope they can represent the issue:
1)
if((lives - 1) <= 0)
With this test, if you have 1 life remaining, you would restart the level. Is it what you want?
2)
Application.LoadLevel(deadLevel);
lives = StarterLives + 1;
In this snippet, the second line is useless because, as soon as you invoke LoadLevel(), the new scene is loaded and the rest of your code is not executed. So, lives = StarterLives + 1; is dead code.
3) Regarding the second point, let's suppose that the order of those lines is inverted (so, they are in the "right" order). It seems that you're trying to update some values in order to have them as the level restarts. But I can't see a DontDestroyOnLoad in your code, so values' preservation is useless.
Hope this helps!

Categories

Resources