Trying to make a timer which resets at the main Menu - visual-studio

I have a timer for a game in Unity and I have it carrying across to each new scene and working. The issue is I also want the timer to reset when the MainMenu scene has loaded and I can not for the life of me get this to work. Help would be appreciated, code's below -
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.SceneManagement;
public class Timer : MonoBehaviour
{
public Text TimerText;
public float StartTime = 0f;
// Start is called before the first frame update
void Start()
{
string Scene = SceneManager.GetActiveScene().name;
if (Scene == "MainMenu")
{
Destroy(this.gameObject);
}
else
{
DontDestroyOnLoad(this.gameObject);
}
}
void Update()
{
float t = Time.time - StartTime;
string minutes = ((int)t / 60).ToString();
string seconds = (t % 60).ToString("f2");
TimerText.text = minutes + ":" + seconds;
}
}

1 SceneManager.sceneLoaded += OnSceneLoaded;
2 public void OnSceneLoaded(Scene scene, LoadSceneMode mode)
3 {
4 }
Then check the current scene, and reset the timer if the new scene is the menu

Don't destroy the game object when main menu is loaded. Just set the time to 0 and make the game object last for all the scenes. Thus since the game object is available to all the scenes, create a bool variable called shouldCountTime. In the update function, just say if shouldCountTime == true then timer code is executed else not. When main menu is loaded, set time to zero and shouldCountTime to false. In start check if the scene loaded is not the main menu, then set shouldCountTime to true.
Code should look like:
void Start() {
if(SceneManager.getActiveScene.name != "MainMenu") {
shouldCountTime = true;
} else {
shouldCountTime = false;
Time = 0;
}
void Update(){
if(shouldCountTime){
Time += Time.deltaTime;
//All the timer code
}}

Related

Unity Instantiate objects appear in hierarchy but not visible

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MakePipe : MonoBehaviour
{
public GameObject pipe;
float timer = 0;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
timer += Time.deltaTime;
if (timer > 1)
{
Instantiate(pipe);
timer = 0;
}
}
}
I am trying to instantiate pipes using prefab, and with the code, a new set of pipes should spawn and move left from the original position where the first set of pipes spawned, but they are not visible.
They are generated as clones in the hierarchy, but when I double-click them to check the position, it points towards the first pipe position.
My guess is that new clones are generated and overlapped in the first pipe as they move together.
Please help
Thanks for your reply.
Sorry I didn't add a separate cs code 'move', I should have added gif..
The following code is to move the pipe left with certain speed. There is no problem there.
However from the 'MakePipe' code that I originally posted, I used instantiate to keep reproducing the pipe. Maybe I should add some lines to 'Start()' part to set original spawn location?
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Move : MonoBehaviour
{
public float speed;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
transform.position += Vector3.left * speed * Time.deltaTime;
// Debug.Log(transform.position);
}
}
I had to delete photos because error message tells me I should have more than 10 reps to edit :(
I don't have enough rep to comment, I'll attempt to give you a answer and update it for what you need.
The Object.Instantiate method has some parameters that you can use to get your pipes into place.
public static Object Instantiate(Object original, Vector3 position, Quaternion rotation, Transform parent);
And without the overloads it will use the original prefab's parameters. So they will spawn in the same location. You have to calculate the next position and pass it in the Instantiate method (Vector3 position).
I misunderstood what you are trying to do at first. #Geeky Quentin
gave the right answer in the first comment.
[SerializeField] private GameObject pipe;
float timer = 0;
float offset = 1.5f;
void Start()
{
}
void Update()
{
timer += Time.deltaTime;
transform.position += new Vector3(-Time.deltaTime/offset, 0, 0);
if (timer > 1)
{
GameObject lastPipe = Instantiate(pipe);
lastPipe.transform.SetParent(transform);
timer = 0;
}
}
I still don't have enough rep to comment. Regarding your last changes. I tested your code out.
Are you parenting the instantiated pipe to the PipeMaker in another script? If not this is the effect it spawns but it does not move:
To make it work you need to parent the instantiated pipe and change it's position MakePipe.cs:
public GameObject pipe;
float timer = 0;
private GameObject _newPipe;
void Update()
{
timer += Time.deltaTime;
if (timer > 1)
{
//instatiate with parent on transform
_newPipe = Instantiate(pipe, transform);
//Set positiion to orginal prefab position
_newPipe.transform.position = pipe.transform.position;
timer = 0;
}
}
This is the effect:
My PipeSpawner has the Move and MakePipe scripts attached to it. And the prefab is in a hidden PipePrefab object that's unrelated to the rest of the system.
You could also set the position of the original spawn location in your Start() method as you said, it's up to you.

How to move a cube 3 second in one direction, and next 3 seconds in oppposite direction, alternatively

I am new to unity, and trying something like below, but I can either move only in one direction, or not moving at all.
My cube is a trigger, and is not using gravity. I have checked the Kitematic box. I am trying to make the cube move to and fro, so that player have difficuly collecting it.
using System.Collections;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using UnityEngine;
public class movedanger : MonoBehaviour
{
private int mytime = 0;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
MyMover(mytime);
}
void MyMover(int mytime)
{
if (mytime <= 3)
{
transform.Translate(Vector3.forward * Time.deltaTime);
mytime++;
}
else
{
transform.Translate(-Vector3.forward * Time.deltaTime);
mytime = 1;
}
}
}
What you are looking for is to and fro movement of an object. You can achieve this with Mathf.PingPong() function instead of using translate. I have tested it with a cube, you can set the minimum and maximum distance it should move to and the speed at which it travels. Since you want the cube to move 3 seconds in one direction at a time. You can calculate the speed as distance/time so the max distance it should travel to from the current distance and the time (3 seconds) it takes. Hope this helps.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MoveCube : MonoBehaviour {
public float min = 2f;
public float max = 8f;
public float SpeedOfMovement = 2f;
// Start is called before the first frame update
void Start () {
}
// Update is called once per frame
void Update () {
transform.position = new Vector3 (Mathf.PingPong (Time.time * SpeedOfMovement, max - min) + min, transform.position.y, transform.position.z);
}
}
With InvokeRepeating you will call the same MoveCube method every 3 seconds.
using UnityEngine;
public class MoveDanger: MonoBehaviour
{
public bool isForward = false;
private void Start()
{
InvokeRepeating("MoveCube", 0f, 3f);
}
private void MoveCube()
{
if (isForward)
{
transform.Translate(Vector3.back);
isForward = false;
}
else
{
transform.Translate(Vector3.forward);
isForward = true;
}
}
}
Honestly the best and easiest way to do something like this, once you get used to it, is just to
Use Unity's incredibly simple animator system:
(Essentially just click "new animation" and then drag the object around as you want it animated.)
There are 100s of tutorials online explaining how to use it.
It's one of those things where once you use it and see how easy it is, you will do a "facepalm" and never bother again with other ways.
It's really "the Unity way" to achieve the goal here, dead easy and flexible.

Getting errors when i try to get game to restart when i hit an obstacle or fall of ground

Please excuse me I'm a complete novice at all this but I'm trying to make a game following "Brackeys How To Make A Video Game" I'm on video 8 if that helps. I can't seem to find what i have done wrong i have added my scripts for "player movement", "player collision" and "game manager". Please if there is anything else you need to help me please ask i really don't want to give up just yet was really enjoying doing this.
Thank you all
using UnityEngine;
public class PlayerMovement : MonoBehaviour {
// This is a reference to the Rigidbody component called "rb"
public Rigidbody rb;
public float forwardForce = 2000f; // Variable that determines the forward force
public float sidewaysForce = 500f; // Variable that determines the sideways force
// We marked this as "Fixed"Update because we
// are using it to mess with physics.
void FixedUpdate ()
{
// Add a forward force
rb.AddForce(0, 0, forwardForce * Time.deltaTime);
if (Input.GetKey("d")) // If the player is pressing the "d" key
{
// Add a force to the right
rb.AddForce(sidewaysForce * Time.deltaTime, 0, 0, ForceMode.VelocityChange);
}
if (Input.GetKey("a")) // If the player is pressing the "a" key
{
// Add a force to the left
rb.AddForce(-sidewaysForce * Time.deltaTime, 0, 0, ForceMode.VelocityChange);
}
if (rb.position.y < -1f)
{
FindObjectOfType<GameManager>().EndGame();
}
}
}
using UnityEngine;
public class PlayerCollision : MonoBehaviour {
public PlayerMovement movement; // A reference to our PlayerMovement script
// This function runs when we hit another object.
// We get information about the collision and call it "collisionInfo".
void OnCollisionEnter (Collision collisionInfo)
{
// We check if the object we collided with has a tag called "Obstacle".
if (collisionInfo.collider.tag == "Obstacle")
{
movement.enabled = false; // Disable the players movement.
FindObjectOfType<GameManager>().EndGame();
}
}
}
using UnityEngine;
using UnityEngine.SceneManagement;
public class GameManager : MonoBehaviour {
bool gameHasEnded = false;
public float restartDelay = 1f;
public GameObject completeLevelUI;
public void CompleteLevel ()
{
completeLevelUI.SetActive(true);
}
public void EndGame ()
{
if (gameHasEnded == false)
{
gameHasEnded = true;
Debug.Log("GAME OVER");
Invoke("Restart", restartDelay);
}
}
void Restart ()
{
SceneManager.LoadScene(SceneManager.GetActiveScene().name);
}
}
when i fall off ground:
NullReferenceException: Object reference not set to an instance of an object
PlayerMovement.FixedUpdate () (at Assets/Scripts/PlayerMovement.cs:32)
when i hit an obstacle:
NullReferenceException: Object reference not set to an instance of an object
PlayerCollision.OnCollisionEnter (UnityEngine.Collision collisionInfo) (at Assets/Scripts/PlayerCollision.cs:15)
It seems to me that FindObjectOfType<GameManager>() is returning null, which is causing a null reference exception when you attempt to call the EndGame function. This most likely means that there is no object in your scene with the GameManager component on it. The solution to this problem is simple:
Create an empty object in your scene and add the GameManager component to it. This will fix the error in this instance, but it could happen in the future if you're not careful. It is also a good idea to check if you found an object or not before calling functions on it:
GameManager gm = FindObjectOfType<GameManager>();
if (gm != null)
{
gm.EndGame();
}

OpenTK Integers Stop Changing Values after Window Open

I need to Have Integers that change in the Background while the GameWindow is Open in OpenTK i tested Some Things and It Totaly didn't work, after this code:
GameWindow polyWindow = new GameWindow(1024, 768);
polyWindow.Run(200);
the Folowwing Code:
if (Gamesets.Polygon.Playfield.timer == 2)
{
polyWindow.Close();
}
Does Not Execute, its Just a Basic Timer that Closes the Window after 2
Seconds, The Code for That is Here:
public static int timer;
public static int ms_timer;
public static void playfield()
{
while (true)
{
ms_timer = + ms_timer + 1;
System.Threading.Thread.Sleep(10);
Console.WriteLine(timer + "S"+ms_timer + "MS");
if (ms_timer == 100) { timer = timer + 1; ms_timer = 0; }
if (timer == 10)
{
}
and it Does Not Work after the GameWindow is Shown
Any code written after the GameWindow.Run() statement will not be executed until after the window has been closed. So the code checking if the time is equal to 2 will not run until polywindow.close() has already been executed or you manualy close the window.
Alternatively what you could do, is check the timer from within the Opentk window in the Update or Render methods and execute the Close() method there.
For example:
protected override void OnUpdateFrame(FrameEventArgs e)
{
base.OnUpdateFrame(e);
if (Gamesets.Polygon.Playfield.timer == 2)
{
Close();
}
}

xna 4.0 animation looping

Hello everyone I have been following this tutorial here http://www.gogo-robot.com/2011/05/30/xna-skinned-model-animations/ and so far its great got the animations playing and everything, but now I want to expand it and stop the continuous loops say for instance i press the a key to make the model jump when i release the a key i want him to stop jumping but if i hold the a key i want him to keep jumping. Here what i have tried so far
and none of it works.
I am stumped here on how to do this thanks for any help with this.
private void HandleInput(GameTime gameTime)
{
currentGamePadState = GamePad.GetState(PlayerIndex.One);
// Check for changing anims
//SkinningData skinningData = model.Tag as SkinningData;
SkinningData sd = jumper.model.Tag as SkinningData;
if (currentGamePadState.Buttons.A == ButtonState.Pressed)
{
if (jumper.animationPlayer.CurrentClip.Name != "Fire")
jumper.animationPlayer.StartClip(sd.AnimationClips["Fire"]);
}
if (currentGamePadState.Buttons.X == ButtonState.Pressed)
{
if (jumper.animationPlayer.CurrentClip.Name != "DieF")
jumper.animationPlayer.StartClip(sd.AnimationClips["DieF"]);
}
//does not work
if (currentGamePadState.Buttons.X == ButtonState.Released)
{
if (jumper.animationPlayer.CurrentClip.Name == "DieF")
jumper.animationPlayer.StartClip(sd.AnimationClips["Idel"]);
}
if (currentGamePadState.Buttons.Y == ButtonState.Pressed)
{
if (jumper.animationPlayer.CurrentClip.Name != "Idel")
jumper.animationPlayer.StartClip(sd.AnimationClips["Idle"]);
}
//does not work
if (jumper.animationPlayer.CurrentTime == jumper.animationPlayer.CurrentClip.Duration)
{
//set him back to idel
jumper.animationPlayer.StartClip(sd.AnimationClips["Idle"]);
}
I have tried these configuration with no luck in the game
// Starts playing the entirety of the given clip
public void StartClip(string clip, bool loop)
{
AnimationClip clipVal = skinningData.AnimationClips[clip];
StartClip(clip, TimeSpan.FromSeconds(0), clipVal.Duration, loop);
}
// Plays a specific portion of the given clip, from one frame
// index to another
public void StartClip(string clip, int startFrame, int endFrame, bool loop)
{
AnimationClip clipVal = skinningData.AnimationClips[clip];
StartClip(clip, clipVal.Keyframes[startFrame].Time,
clipVal.Keyframes[endFrame].Time, loop);
}
// Plays a specific portion of the given clip, from one time
// to another
public void StartClip(string clip, TimeSpan StartTime, TimeSpan EndTime, bool loop)
{
CurrentClip = skinningData.AnimationClips[clip];
currentTime = TimeSpan.FromSeconds(0);
currentKeyframe = 0;
Done = false;
this.startTime = StartTime;
this.endTime = EndTime;
this.loop = loop;
// Copy the bind pose to the bone transforms array to reset the animation
skinningData.BindPose.CopyTo(BoneTransforms, 0);
}
Can you not attach a bool on the animation clip to tell it to play only once, or an active variable that can be called.

Resources