what i am doing is on my level the timer counts down from 50 to 0 using Time.deltaTime this works great. now on the PlayerControl Script when i pickup a coin i want the timer to Add on 3 seconds. My code is below.
//this is PlayerControl when i pick up PlusOrb Object.
public class PlayerCTRL : MonoBehaviour
{
public Text timerText;
public TimerCount timerScript;
public Image DamagedOverlay;
public float speed;
public Text CountText;
private int count;
public GameObject TakeDamage;
public Text scoreText;
public TEMPLE_score scoreScript;
public TEMPLE_GlobalSettings globalSettings;
void Start()
{
CountText.text = CoinCounter.ToString();
playerLife = 3;
count = 0;
SetCountText();
playerAS = GetComponent<AudioSource>();
timerScript = GetComponent<TimerCount>();
damaged = false;
}
void OnTriggerEnter2D(Collider2D other)
{
if (other.gameObject.CompareTag("PlusOrb"))
{
Destroy(other.gameObject);
count = count + 1;
SetCountText();
//score
scoreScript.myscore += 2;
scoreText.text = scoreScript.myscore.ToString();
//timer
timerScript.timer + 3f;// this is the problem i am having
PlayerPrefs.SetInt("CoinCount", PlayerPrefs.GetInt("CoinCount") + 1);
}
}
}
//This is the Timer Script.
public class TimerCount : MonoBehaviour
{
public Text TimeText;
public float timer1 = 50;
float SceneTimer = 0;
TEMPLE_GlobalSettings globalSettings;
public Sprite lives0;
public GameObject Gore;
public PlayerCTRL PlayerController;
int ouch;
void Start()
{
timer1 = 50;
}
void Update()
{
this.GetComponent<Text>().text = timer1.ToString("F0");
timer1 -= Time.deltaTime;
print(timer1);
if (timer1 < 1)
{
timer1 = 0;
PlayerController.playerLife = 0;
SceneTimer += Time.deltaTime;
//if (SceneTimer > 2)
//{
//SceneManager.LoadScene("TEMPLE");
//}
}
}
void GameOver()
{
GameObject thisGore = Instantiate(Gore, transform.position, transform.rotation) as GameObject;
thisGore.GetComponent<ParticleSystem>().Play();
GameObject.Find("Lives").GetComponent<Image>().sprite = lives0;
Destroy(gameObject);
}
}
Replace
timerScript.timer + 3;// this is the problem i am having
with
timerScript.timer += 3f;
Or
timerScript.timer = timerScript.timer + 3f;
This is a basic C# stuff. You should learn C# before working with Unity. There are many of tutorials out there.
EDIT:
With the updated script in your question, there is no variable named timer in your TimerCount script. A similar variable name in your TimerCount script is named timer1. You should either rename it to timer or timerScript.timer1 += 3f;.
At the end of the day, this means that you need to learn basic C#. Please don't take this as an insult. It necessary to understand basic C# or you will be asking more similar questions like this one. You are accessing a variable is is not declared.
Related
I am working through the unity tutorials and I was wondering how to stop a timer when you hit 12 of count.
I currently have two scripts I am using.
PlayerController
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.InputSystem;
using TMPro;
public class PlayerController : MonoBehaviour
{
public float speed;
public TextMeshProUGUI countText;
public GameObject winTextObject;
private float movementX;
private float movementY;
private Rigidbody rb;
private int count;
// At the start of the game..
void Start()
{
rb = GetComponent<Rigidbody>();
count = 0;
SetCountText();
winTextObject.SetActive(false);
}
void FixedUpdate()
{
// Create a Vector3 variable, and assign X and Z to feature the horizontal and vertical float variables above
Vector3 movement = new Vector3(movementX, 0.0f, movementY);
rb.AddForce(movement * speed);
}
void OnTriggerEnter(Collider other)
{
// ..and if the GameObject you intersect has the tag 'Pick Up' assigned to it..
if (other.gameObject.CompareTag("Pickup"))
{
other.gameObject.SetActive(false);
// Add one to the score variable 'count'
count = count + 1;
// Run the 'SetCountText()' function (see below)
SetCountText();
}
if (other.gameObject.CompareTag("SpeedPickup"))
{
other.gameObject.SetActive(false);
speed = speed + 25;
count = count + 1;
}
}
void OnMove(InputValue value)
{
Vector2 v = value.Get<Vector2>();
movementX = v.x;
movementY = v.y;
}
void SetCountText()
{
countText.text = "Count: " + count.ToString();
if (count >= 12)
{
winTextObject.SetActive(true);
}
}
}
And a second script Timer.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using TMPro;
public class Timer : MonoBehaviour
{
[SerializeField]
private TextMeshProUGUI timerUILabel; //drag UI Text object here via Inspector
private float t_offset = 0f; // set to nothing, can be set to an offset if needed.
private int t_minutes;
private int t_seconds;
private int t_milliseconds;
private bool finished = false;
private void Update()
{
float t = Time.time - t_offset;
//Debug.Log("currentTime in seconds = " + t);
t_minutes = ((int)t / 60); // t(seconds) / 60 = total minutes
t_seconds = ((int)t % 60); // t(seconds) % 60 = remaining seconds
t_milliseconds = ((int)(t * 100)) % 100; // (total seconds * 1000) % 1000 = remaining milliseconds
//display the text in a 00:00:00 format
timerUILabel.text = string.Format("{0:00}:{1:00}:{2:00}", t_minutes, t_seconds, t_milliseconds);
}
}
My questions are
Do I need to import the Timer.cs script into the PlayerController to get this functionality to work? If so how? (is it as simple as using a using statement?)
I am thinking I need to put in an additional conditional to change the win condition from false to true. Is that the right path?
Thanks for all your help!
Why not use a coroutine?
private int _time;
private Coroutine _cr;
void Start ()
{
//Call this to start it and save coroutine to a variable
_cr = StartCoroutine(Timer());
//Then to stop it call:
//StopCoroutine(_cr);
//And read the value of _time to get seconds since start.
}
private IEnumerator Timer ()
{
yield return new WaitForSeconds(1);
_time++;
_cr = StartCoroutine(Timer());
}
can you help me to make timed powerup that will effect for certain time
here is my code
public int jumpTrig = 0;
public int speed = 0;
public int health = 0;
public float duration = 0;
public float timer = 0;
void OnTriggerEnter2D(Collider2D coli)
{
if (coli.gameObject.tag == "Player")
{
coli.gameObject.GetComponent<PlayerMove>().jumpForce += jumpTrig;
coli.gameObject.GetComponent<PlayerMove>().speed += speed;
coli.gameObject.GetComponent<Health>().health += health;
Destroy(this.gameObject);
}
}
I would actually not recommend to use a timer in Update here because it hinders you to already at least deactivate the according GameObject. The same also applies to a Corotuine.
In both cases you can not Destroy or SetActive(false) the PowerUp item which would bother me.
But you can use Invoke for this!
Afaik it still breaks if the object gets destroyed but it works on an inactive GameObject!
So instead disable it first and Destroy it later.
Some more points:
In general you should use GetComponent as little as possible since it is quite expensive. Rather store the reference and reuse it.
And you should rather use CompareTag instead of using == directly. CompareTag is (very slightly) faster but the more important point: It throws an exception if the provided Tag is e.g. spelled wrong/doesn't exist. The == hides such a "bug" and rather simply fails which can cost you some development time and nerves ;)
Note that I would also give your fields better names
So your code might look like
public int jumpBonus = 0;
public int speedBonus = 0;
public int healthBonus = 0;
public float duration = 0;
private PlayerMove playerMove;
private Health playerHealth;
private void OnTriggerEnter2D(Collider2D coli)
{
if (!coli.CompareTag("Player")) return;
playerMove = coli.gameObject.GetComponent<PlayerMove>();
playerHealth = coli.gameObject.GetComponent<Health>();
playerMove.jumpForce += jumpBonus;
playerMove.speed += speedBonus;
playerHealth.health += healthBonus;
gameObject.SetActive(false);
// Calls ResetEffect after "duration" seconds even if gameObject is inactive
Invoke(nameof(ResetEffect), duration);
}
private void ResetEffect()
{
playerMove.jumpForce -= jumpBonus;
playerMove.speed -= speedBonus;
playerHealth.health -= healthBonus;
Destroy(gameObject);
}
You can do a single timer using Update and DeltaTime to work over a float of your desired time.
public float powerTime = 0.0f
private bool poweredUp = false;
void OnTriggerEnter2D(Collider2D coli)
{
if (coli.gameObject.tag == "Player")
{
powerTime = 10.0f;
}
}
Update()
{
powerTime -= Time.deltaTime;
if (powerTime > 0.0f && !poweredUp)
{
poweredUp = true;
doPowerUp();
}
else if (poweredUp)
{
doPowerEnd()
}
void doPowerUp()
{
coli.gameObject.GetComponent<PlayerMove>().jumpForce += jumpTrig;
coli.gameObject.GetComponent<PlayerMove>().speed += speed;
coli.gameObject.GetComponent<Health>().health += health;
}
void doPowerEnd()
{
poweredUp = false;
Destroy(this.gameObject);
//reset to your normal values.
}
I have a SceneController that's supposed to initialize a set of empty GameObject spawners, each working together at the same rhythm. The RockSpawners receive an array of time delays and wait the X seconds between spawning another rock.
I set the _nextSpawn = float.maxValue when the spawners start and plan to overwrite this after "Initializing" them (my own method), however even though my debug logs say I've overwritten my _nextSpawn value while initializing, the update loop is still reporting float.maxValue and nothing ends up spawning because _timeSinceLastSpawn hasn't exceeded float.maxValue seconds.
Is there something I'm missing with the scope of my _nextSpawn variables? It doesn't seem to be a "this" vs "local" issue, at least at first glance.
Debug output: 0 0 3 3. 0's stay the same, 3's will vary based on rng.
SceneController.cs:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SceneController : MonoBehaviour {
[SerializeField] private GameObject _rockSpawnerPrefab;
public int numRocks = 6;
public int minSpawnDelaySec = 1;
public int maxSpawnDelaySec = 3;
private bool spawnersInitialized = false;
void Start () {
InitializeSpawners();
}
void Update () {
}
void InitializeSpawners() {
float[] pattern = new float[numRocks];
for (int i = 0; i < numRocks; i++) {
// Generate delays at half second increments within bounds
float delay = Mathf.Floor(Random.value * ((float)(maxSpawnDelaySec + 0.5f - minSpawnDelaySec) / 0.5f));
delay = delay * 0.5f + minSpawnDelaySec;
pattern[i] = delay;
}
GameObject spawner = Instantiate(_rockSpawnerPrefab) as GameObject;
spawner.transform.position = new Vector3(0, 4, 0);
RockSpawner rockSpawnerScript = spawner.GetComponent<RockSpawner>();
rockSpawnerScript.Initialize(pattern);
}
}
RockSpawner.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class RockSpawner : MonoBehaviour {
[SerializeField] private GameObject _rockPrefab;
public float minSpawnDelay = 3f;
public float maxSpawnDelay = 6f;
private float[] _pattern;
private int _currentPattern;
private float _timeSinceLastSpawn;
private float _nextSpawn;
void Start () {
_currentPattern = -1;
_nextSpawn = float.MaxValue;
}
void Update () {
if (_pattern == null) return;
_timeSinceLastSpawn += Time.deltaTime;
if (_timeSinceLastSpawn > _nextSpawn) {
GameObject rock = Instantiate(_rockPrefab) as GameObject;
rock.transform.position = transform.position;
NextTimer();
}
}
public void Initialize(float[] pattern) {
_pattern = pattern;
NextTimer();
}
private void NextTimer() {
_timeSinceLastSpawn = 0;
_currentPattern += 1;
Debug.Log(_nextSpawn);
Debug.Log(this._nextSpawn);
this._nextSpawn = _pattern[_currentPattern];
Debug.Log(_nextSpawn);
Debug.Log(this._nextSpawn);
}
}
It's not about scoping, it's about call order. When you create a GameObject its Start method is called on the frame it's enabled, not when the object is created. So your code will call Initialize first, then Start which overwrites the values.
Remove the code in Start and handle everything in Initialize and it should work as you want.
I am trying to set a Slider value through C# code.
I have a Main.scene which includes a slider called Slider.
The main camera has a game manager script attached to it.
The slider is not Interactable (so I can display the value but the user can't change it).
I defined a variable:
[SerializeField] private Slider sliderObj;
and put my slider in the inspector in this field
I have a float s variable that I want to reflect in the slider:
s = player1Time / (player1Time + player2Time) * 100.0f;
but when I write:
sliderObj.value = s;
I see this error:
'Slider' does not contain a definition for 'value' and no extension method 'value' accepting a first argument of type 'Slider' could be found (are you missing a using directive or an assembly reference?) [Assembly-CSharp]
any ideas?
Here is the entire script:
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
public class GameManager : MonoBehaviour
{
public static GameManager instance = null; //this is to create a singleton => only one instance of this script running in memory
//so we only have one Game Manager running on memory
private int activePlayer = 1; //1 = down position 2 = up position
[SerializeField]
private GameObject playerObj;
[SerializeField]
private Text timer1Text; //player1 timer text
[SerializeField]
private Text timer2Text; //player2 timer text
[SerializeField]
private GameObject startBtn;
[SerializeField]
private Texture stopTexture;
[SerializeField]
private Slider sliderObj;
private Slider sli;
public float sli_val;
private RawImage img;
private float startTime;
private bool player1Active = true;
private static float player1Time;
private static float lastP1Time;
private static float player2Time;
private static float lastP2Time;
private bool gameOver = false;
private bool gameStarted = false;
private bool gameFinished = false;
void Awake()
{
if (instance == null)
{ //check if an instance of Game Manager is created
instance = this; //if not create one
}
else if (instance != this)
{
Destroy(gameObject); //if already exists destroy the new one trying to be created
}
DontDestroyOnLoad(gameObject); //Unity function allows a game object to persist between scenes
}
public bool GameStarted
{
get { return gameStarted; }
}
public bool GameOver
{
get { return gameOver; }
}
public void StartGame()
{
if (!gameStarted)
{
gameStarted = true;
//startTime = Time.time;
//player1Time = startTime;
player1Active = true;
//select start button
img = (RawImage)startBtn.GetComponent<RawImage>();
//replace it with stop button
img.texture = (Texture)stopTexture;
}
else
{
gameStarted = false;
gameOver = true;
}
Debug.Log("StartGame");
}
public void ChangePlayer()
{
float ty = 0f;
int smileyRotate = 180;
int sliderRotate = 180;
Quaternion smileyRotation = playerObj.transform.localRotation;
ty = playerObj.transform.position.y * -1;
if (activePlayer == 1)
{
player1Active = false;
activePlayer = 2;
smileyRotate = 180;
}
else
{
player1Active = true;
activePlayer = 1;
smileyRotate = 0;
}
playerObj.transform.position = new Vector2(playerObj.transform.position.x, ty);
smileyRotation.x = smileyRotate;
playerObj.transform.localRotation = smileyRotation;
}
// Use this for initialization
void Start()
{
}
// Update is called once per frame
private string FormatTime(float pt)
{
string hours, minutes, seconds, shaon;
hours = ((int)pt / 3600).ToString("00");
minutes = ((int)pt / 60).ToString("00");
seconds = (pt % 60).ToString("00");
if ((pt / 3600) > 1)
{
shaon = string.Format("{0:D1}:{1:D2}:{2:D2}", hours, minutes, seconds);
}
else
{
shaon = string.Format("{0:D2}:{1:D2}", minutes, seconds);
}
return shaon;
}
void Update()
{
float s;
GameObject sl1 = GameObject.Find("Slider");
if (GameStarted)
{
string zman;
if (player1Active)
{
player1Time += Time.deltaTime; //if player 1 active update his time
zman = FormatTime(player1Time);
timer1Text.text = zman;
//Debug.Log("player2Time: : "+ player2Time);
}
else
{
player2Time += Time.deltaTime; //if player 2 active update his time
zman = FormatTime(player2Time);
timer2Text.text = zman;
Debug.Log("player1Time: : " + player1Time);
}
s = player1Time / (player1Time + player2Time) * 100.0f;
//sliderObj.GetComponent<Slider>;
//sliderObj.=0.5f;
sli = GameObject.Find("Slider").GetComponent<Slider>();
sli.value = s;
sliderObj.value = s;
}
}
}
First of all, thanks for all your help.
Specially to bpgeck that chat with me and help me a lot.
Also Programmer was correct.
The main problem I had was the fatal error of calling the script attached to my slider Slider (I am still a noob, but learning)
I deleted that script and created a new one called Slider Percentage, in it I use the update function to change the value of the slider:
GameObject temp;
// Use this for initialization
void Start () {
temp = GameObject.Find("Slider");
}
// Update is called once per frame
void Update () {
temp.GetComponent<Slider>().value = GameManager.instance.GetPercentage;
}
The percentage value is still being calculated in the GameManager, but it is displayed using this script.
Now all works!! Thanks again for all your help :-)
I build the shooting game by C# and Unity.
I use GameController and GameStatus to show the score and time.
At first scene, I have no problem. It can run smoothly.
But the second scene, I copy scene from first and make new GameController for second scene.
It's work but running game slower.
I try to make new project by using same code, but it's slow even it's my first scene.
I don't know cause of this happen.
Below is my code, it's work.
using UnityEngine;
using System.Collections;
public class MyGameController2 : MonoBehaviour
private Gun gun;
public GUISkin mySkin2;
private GameStatus gameStatus;
public float countDownTime2;
private float scoreTime2;
private float menuTime2;
// Use this for initialization
void Start () {
countDownTime2 = 60.0f;
scoreTime2 = countDownTime2+3;
menuTime2 = countDownTime2+5;
gameStatus = (GameStatus)GetComponent(typeof(GameStatus));
}
// Update is called once per frame
void Update () {
countDownTime2 -= Time.deltaTime;
if(gameStatus.score >= 300){Application.LoadLevel("MainScene2");}
if(countDownTime2 <= 0.0f)
{gameStatus.isGameOver = true;
countDownTime2 = 0.0f;
gameStatus.score +=0;
}
scoreTime2 -= Time.deltaTime;
menuTime2 -= Time.deltaTime;
}
void OnGUI()
{
float sw = Screen.width;
float sh = Screen.height;
GUI.skin = mySkin2;
int mScore = gameStatus.score;
if(countDownTime2 > 0.0f){
GUI.Label (new Rect(50,0,sw/2,sh/2), "Score : " + mScore.ToString(),"scoreStyle");
GUI.Label (new Rect(400,0,0,0), "Time : " + countDownTime2.ToString("000") ,"timeStyle");
}
if(gameStatus.isGameOver)
{GUI.Label (new Rect(120,100,sw/2,sh/4),"Game Over","messageStyle");}
if (scoreTime2 <= 0.0f)
{
GUI.Label (new Rect(130,50,0,0), "Your Score is " + mScore.ToString(),"scoreStyle2");
}
if(menuTime2 <= 0.0f){
// Make the first button. If it is pressed, Application.Loadlevel (1) will be executed
if(GUI.Button(new Rect(100,220,80,20), "Retry")) {
Application.LoadLevel("MainScene");}
if(GUI.Button(new Rect(300,220,80,20), "Menu")) {
Application.LoadLevel("TitleScene");}
}
}
}