I'm working on a 3D BMX sidescroller with a trick system and points. I've all ready got check points in for when you crash and they work well. The problem I'm having is when you crash your score doesn't go back to what it was when you first passed the checkpoint, meaning people can just get a high score by doing a really big trick and crashing over and over again. Every tutorial, and I mean literally every one, has been about saving a high score at the end of a level. Here's the relevant script
private float flipScore;
private float spinScore;
void FixedUpdate()
if (!IsGrounded())
flipScore += (transform.localEulerAngles.x) * Time.deltaTime * 0.5f;
spinScore += transform.localEulerAngles.y * Time.deltaTime * 1f;
An example for anyone who needs extra clarification.
You reach the first checkpoint with 12345 points. You do a few tricks to get up to 15000 but crash before the next checkpoint then you start back at the first checkpoint with 12345 points.
I've tried pretty much everything I've seen in the tutorials but to no avail.
Store the points when you reach a checkpoint.
When resetting to the checkpoint, set the score to what was stored.
private float checkpointSpinScore;
private float checkpointFlipScore;
private void OnCheckpointReached()
{
checkpointSpinScore = spinScore;
checkpointFlipScore = flipScore;
}
private void OnResetToCheckpoint()
{
spinScore = checkpointSpinScore;
flipScore = checkpointFlipScore;
}
Related
new to unity and C# and currently going through the create with code course. For the Prototype 2 exercise im trying to set it so that dogs are spawned between 2 and 5 seconds, each time varying slightly with randomness. However what happens at the moment is that they are spawned in random intervals, however there is then a huge increase in the amount of dogs spawned and it quickly fills up the scene and uses alot of processing power:
My SpawnManager script is as follows:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SpawnManager : MonoBehaviour
{
public GameObject[] dogPrefabs;
private float spawnRangeX = 10;
private float spawnPosZ = 20;
private float startDelay = 2;
private float startspawnDelay = 1.5f;
public float RandomSpawnBeg = 2; //* Time.deltaTime;
public float RandomSpawnEnd = 5; //* Time.deltaTime;
public float RandomSpawn = Random.Range(RandomSpawnBeg, RandomSpawnEnd);
//public float boneDelay = 2.0f;
// Start is called before the first frame update
void Start()
{
InvokeRepeating("SpawnRandomAnimal", startDelay, RandomSpawn); //calls SpawnRandomAnimals method, after 2 seconds, every 1.5 seconds.
}
// Update is called once per frame
void Update()
{
}
void SpawnRandomAnimal()
{
int animalIndex = Random.Range(0, dogPrefabs.Length);
Vector3 spawnPos = new Vector3(Random.Range(-spawnRangeX, spawnRangeX), 0, spawnPosZ); //creating a Vector3 variable which sets a random value for the x axis between the spawnRange vars, 0 on the y axis, and the spawnPosZ var for the z axis.
Instantiate(dogPrefabs[animalIndex], spawnPos, dogPrefabs[animalIndex].transform.rotation); // spawn an animal from the index with an updated vector 3 position and rotation
//InvokeRepeating("SpawnRandomAnimal", startDelay, RandomSpawn);
Debug.Log("Spawn time is " + RandomSpawn);
}
}
Im a bit lost as to what could be causing this onslaught of dogs. I though that it may be telling it to do it every 2 - 5 frames as oppose to seconds, however when i * RandomSpawnBeg and RandomSpawnEnd by time.deltatime its still performing the same way.
Im really enjoying learning C# and unity but getting a bit stuck on how time works within it, if anyone can shed some light on this for me i would really appreciate it!
Thanks
first of all the InvokeRepeating function
public void InvokeRepeating(string methodName, float time, float repeatRate);
Invokes the method methodName in time seconds, then repeatedly every repeatRate seconds.
example InvokeRepeating("LaunchProjectile", 2.0f, 0.3f); it means that i'll create a projectile after 2 seconds from the Start frame and each 0.3 second i'll call this LaunchProjectile again . This is for the invoke repeating now we attack your problem :
Start() the Start() function is called in Unity once and only once at the first frame before calling the Update().
So basically you are invoking repeatedly with the same amount of frame rate each time because the randomizing happens only once.
To fix this just change where you call the randomizing function to this :
void Start()
{
InvokeRepeating("SpawnRandomAnimal", startDelay,Random.Range(RandomSpawnBeg, RandomSpawnEnd));
}
Now test this my friend and I hope your journey in Unity is full of joy.
I advice you to review this documentation it will help you out in many ways
Order of execution
I currently learn unity3d and start to create an endless game, and I want to add score by a distance that player has traveled on + x axis, so I want to calculate only how far the player traveled on + x axis.. how to calculate it?
this is my scripts
public class Score : MonoBehaviour
public float distance;
public Transform player;
private float score = 0f;
public Text scoreText;
void Awake()
{
distance = Vector3.Distance(player.position, transform.position);
}
void Update()
{
if (distance > player.transform.position.x)
{
score = distance ++;
scoreText.text = distance.ToString();
}
}
}
You can have something like this to get you started. I set it to 0.1 distance to get +1 score but that number can be anything of course.
private const float DISTANCE_REQUIRED_FOR_1_POINT = 0.1f;
private Vector3 previousPlayerPosition;
private float distanceSinceLastScore;
public Transform player;
private float score = 0f;
public Text scoreText;
void Awake()
{
//At the start save the start position.
previousPlayerPosition = player.position;
}
void Update()
{
//Calculate the distance travvelled since last update.
distanceSinceLastScore += player.position.x - previousPlayerPosition.x;
//Set the previous position the current.
previousPlayerPosition = player.position;
int scoreToAdd = 0;
while (distanceSinceLastScore > DISTANCE_REQUIRED_FOR_1_POINT)
{
//Calculate how many points to add in this update. (Likely always 1 or none)
++scoreToAdd;
distanceSinceLastScore -= DISTANCE_REQUIRED_FOR_1_POINT;
}
if (scoreToAdd > 0)
{
score += scoreToAdd;//Add to the total score.
scoreText.text = score.ToString();//refresh the text display.
}
}
To be honest, you gave very little information about the game. But I will try to come up with some possible scenarios and solutions.
First of all, you stated that this is an endless game, then I don't know what distance are you calculating between the player and a point. So, your code didn't make much sense to me, please explain if I'm missing something.
Now, you said you want to calculate the score based on the distance that the player has traveled on + x-axis. So, take a look at this code:
float previousPlayerX;
public Transform player;
private float score;
void Awake()
{
previousPlayerX= player.position.x;
score = 0;
}
void Update()
{
if (previousPlayerX < player.position.x)
{
score += player.position.x - previousPlayerX;
previousPlayerX = player.transform.position.x
}
}
This code will increase the score as long as the player is running to +x. If the player stops or even turns back, the score will not be updated. Also, note that if your starting position is 0, then you don't need to subtract the two positions to add the score, you can simply go ahead and say score = player.position.x and it should give you the same result. Furthermore, I would implement this code in a coroutine with a little bit of wait time to avoid possible bugs maybe.
Now, let's think about another scenario. I don't think the character doesn't go to infinity in endless run games, generally, the character object is stable and you kinda make that illusion of endless flow. So, let's say your character's position is not changing actually, but in the game, it seems like your character is running non-stop. In such a case, you may want to increase the score based on the time passing.
private float score;
void Awake()
{
score = 0;
StartCoroutine(UpdateScore());
}
IEnumerator UpdateScore()
{
while(true)
{
score += 1;
yield return new WaitForSeconds(1);
}
}
As you can see in the second code, I'm just assuming that my character runs non-stop and I'm just increasing the score by 1 every second. You can do it in every half a second, you can increase the score by multiplying with a speed value or you can put an if statement and don't increase the score if the character is stunned for example. So, it's all up to you.
I hope that answer helps and gives you a general idea. Let me know in the comments if you have any other questions related to this.
Trying to create simple endless moving platform with 3 cubes of scale 70 on z(Player will not move forward, will just move left/right). The RepositionPlatform script is attached to each platform/cube which is responsible for movement and checks the z position of each platform and if it is <= -100.0f, then position is changed to (0,0,200.0f).
Problem is sometimes there is a little gap between the platforms(cubes) or there is a little overlap which I don't want.
Platforms should be placed one after each other without any gap or overlap!!!
Can anyone help find the issue looking at the script or suggest any other better way ?
The script below is attached to 3 platform game objects!!!
public class RepositionPlatform : MonoBehaviour
{
private GameObject platformGO;
[SerializeField]
private float speed;
// Start is called before the first frame update
void Start()
{
platformGO = this.gameObject;
Debug.Log("In RepositionPlatform Start method - "+ platformGO.name);
}
// Update is called once per frame
void Update()
{
Debug.Log("In RepositionPlatform Update Method- " + platformGO.name);
platformGO.transform.Translate(Vector3.back * Time.deltaTime * speed);
Transform platformTransform = platformGO.transform;
if(platformTransform.position.z <= -100.0f)
{
platformTransform.position = new Vector3(0,0,200.0f);
}
}
}
Probably because speed is a floating point value. You should read up on them if you haven't already.
Long story short, you aren't accounting for how far below -100 the value might have gone, you're just resetting it.
If you translate it instead, you will preserve any extra distance beyond -100 that the transform might have gone.
Try this instead:
If (transform.position.z < -100){
transform.Translate(new Vector3(0,0,200));
}
Edit
Should be Z value, not X
I am working on a propably simple script. As I am new to coding and stuff, there is a high chance that my code looks horrible.
Okay, so here's the thing:
I have an enemy triggered, and only spawning when the player get's near a certain point. Then the Enemy has to follow the player, doesn't matter where he is, and keeping a certain range of 3 units.
To this point. Everything works fine.
Now, what doesn't seem to work is, that I need my enemy to "orbit" around my player, when he is in a certain range (3) and only then.
For now, it's orbiting right from the start...what did I miss??
Thats my code so far:
public Transform mTarget;
float mSpeed = 10.0f;
const float EPSILON = 3.0f;
public float speed;
void Start()
{
OrbitAround ();
}
void Update() {
transform.LookAt (mTarget.position);
if ((transform.position - mTarget.position).magnitude > EPSILON)
transform.Translate (0.0f, 0.0f, mSpeed * Time.deltaTime);
}
void OrbitAround() {
if(Vector3.Distance(transform.position, mTarget.transform.position) < 3) {
transform.RotateAround (mTarget.transform.position, Vector3.up, speed * Time.deltaTime);
}
}
Big Thanks in advance, if anyone can help me out.
Cheers,
As #Zibelas said, the Start function is only once.
The Unity documentation states:
Start is called on the frame when a script is enabled just before any of the Update methods is called the first time.
So try putting the call to OrbitAround() in the Update function and it should work
Well, didn't really fixed this problem exactly, but I found a way to work around it.
I just enabled the script to orbit around the target, when the enemy get close to it and disabled it, when the player goes away again.
void Update (){
if (Vector3.Distance (transform.position, mTarget.transform.position) < 15) {
script.enabled = true;
}
if(Vector2.Distance(transform.position, mTarget.transform.position) >15) {
script.enabled = false;
}
Still, thanks for the comments and information, guys.
Im creating a speedometer in Unity and I want my speedo arrow to smoothly lerp up to it's max angle based on the wither or not a button is pressed on. When the button is let go, I'd like the arrow to fall back to it's original rotation value.
However, I'm having issues trying to work out how to make my object lerp from its original position, to it's new position and back again. I've got it so when I press a button the objects jumps to a position, however, I need it to be smoother. Could someone please look over my code and point out what I need to do please?
float maxAngle = 100.0f;
float maxVel = 200.0f;
Quaternion rot0;
public float rotateValue;
// Use this for initialization
void Start ()
{
rot0 = transform.localRotation;
}
// Update is called once per frame
void Update ()
{
if(Input.GetKey(KeyCode.Space))
{
SetNeedle(rotateValue);
}
}
void SetNeedle(float vel)
{
var newAngle = vel * maxAngle / maxVel;
transform.localRotation = Quaternion.Euler(newAngle,0,0) * rot0;
float angle = Mathf.LerpAngle(minAngle, maxAngle, Time.time);
transform.eulerAngles = new Vector3(0, angle, 0);
}
From the documentation:
static float Lerp(float from, float to, float t);
Interpolates between a and b by t. t is clamped between 0 and 1.
Which means t goes from 0% to 100%. When t == 0.5f the result will be the middle angle between from to to.
Hence, if the needle needs to be moved in a smooth and constant speed, you should do:
time += Time.deltaTime; // time is a private float defined out of this method
if(time >= 1.5f) // in this example the needle takes 1.5 seconds to get to its maximum position.
time = 1.5f // this is just to avoid time growing to infinity.
float angle = Mathf.LerpAngle(from, to, time/1.5f); // time/1.5f will map the variation from 0% to 100%.
But that requires the from and to to be constant during the lerp fase.
So what you need to do is the following:
when you press Space, set time = 0, from = currentAngle and to = maxAngle; Obviously this must be done only once during the key down event.
when you release Space, set time = 0, from = currentAngle and to = 0. Also do this only once.
All right?
You should use Time.deltaTime, not Time.time. That should make it move correctly.
EDIT: deltaTime won't solve the problem alone, however. Sorry I didn't fully read your code at first.
In order to smoothly move the needle, you need to know where the needle is currently, where it needs to go, and how much time has elapsed since the last time it moved.
We know how much time has elapsed with Time.deltaTime. But your code currently doesn't take into consideration where the needle is. float angle = Mathf.LerpAngle(minAngle, maxAngle, Time.deltaTime); will always evaluate to roughly the same value, so your needle will never move beyond a tiny bit.
What you should do instead is lerp from the needle's current position towards the maxAngle.
float angle = Mathf.LerpAngle(currentAngle, maxAngle, Time.deltaTime);