- Home /
2D Collect Item C# Increase Acceleration
Hello all, I'm having an issue with collection a speed boosting item, I need to be able to collect a power up that increases my players speed a little more, but I don't want it to be an instant jump like it is now, I need it to accelerate gradually.
Here is what I've tried so-far:
void OnTriggerEnter2D(Collider2D other) {
if (other.tag == "SpeedBoost") {
transform.position = new Vector2(Mathf.Lerp(minimum, maximum, Time.time));
//transform.position += Vector3.right * horizontalSpeed * Time.deltaTime;
Destroy (other.gameObject);
}
}
Any ideas? All help is greatly appreciated!
Answer by savlon · Jun 15, 2015 at 08:02 AM
You are incorrectly using Mathf.Lerp. The Unity documentation on this is horrible. Mathf.Lerp takes in 'From', 'To' and 'T' parameters. It interpolates your value From to To over T. The T parameter should be a value between 0 and 1. 0 is equal to your From value and 1 is equal to your To value.
For example:
From = 1
To = 2
Difference = To - From = 1
So if T were equal to 0.5, the returned value would be 1.5
I'm not entirely sure what your exact plans for this idea are, but I have constructed a basic script for you to read over and understand what is happening.
using UnityEngine;
using System.Collections;
public class PowerUpTest : MonoBehaviour
{
public float minSpeed = 1.0f; //Minimum powerup speed 'From'
public float maxSpeed = 10.0f; //Maximum powerup speed 'To'
public float incrementRate = 0.1f; //The rate you want the speed to change
public string powerUpName = "SpeedBoost"; //The tag of the powerup gameobject
private bool executePowerUp = false; //Checks whether to execute the powerup
private float currentSpeed; //The current speed of your powerup boost value
private float lerpTime; //The lerp time 'T'
void Start ()
{
currentSpeed = minSpeed; //Set current speed to equal the minimum speed
}
void Update ()
{
if (executePowerUp) //If the executePowerUp bool is true
{
if (lerpTime <= 1) //If the lerp time has not reached the maximum value ('To')
{
lerpTime += Time.deltaTime * incrementRate; //Increase the lerp time by deltaTime multiplied by the rate
currentSpeed = Mathf.Lerp (minSpeed, maxSpeed, lerpTime); //Set the current speed to the current lerped value
print (currentSpeed); //print the current speed for you to see the change in the value
}
else //If the lerp time has exceeded the 'To' value
{
executePowerUp = false; //Turn execute powerup to false
lerpTime = 0; //Reset the lerp time
}
}
}
void OnTriggerEnter2D (Collider2D other)
{
if (other.CompareTag (powerUpName)) //If the trigger object tag is equal to the powerup tag
{
executePowerUp = true; //Set execute power to true to initiate the lerp code
Destroy (other.gameObject); //Remove the collided object
}
}
}
The code is fully commented. If you don't understand something, post a comment.
Thank you very much savlon, I actually managed to work out a similar solution a few hours ago, it involves almost the same principles only this one I have it connected to the power up item and having it reference the player ins$$anonymous$$d, here is what I ended up with:
void OnTriggerEnter2D(Collider2D other) {
if (other.gameObject.tag == "Player")
{
collected = true;
GameObject.FindGameObjectWithTag("Player").GetComponent<Player$$anonymous$$ove>().forwardsSpeed+=bonusGain;
gameObject.renderer.enabled = false;
}
if (other.gameObject.tag == "Bounds") {
Destroy (gameObject);
}
}
void Update()
{
if (collected == true) {
timer += Time.deltaTime;
if (timer >= bonusTime) {
GameObject.FindGameObjectWithTag ("Player").GetComponent<Player$$anonymous$$ove> ().forwardsSpeed = speedReset;
Destroy (gameObject);
collected = false;
}
if (collected == false){
GameObject.FindGameObjectWithTag ("Player").GetComponent<Player$$anonymous$$ove> ().forwardsSpeed = speedReset;
}
}
transform.position -= Vector3.right * speedItemLocation * Time.deltaTime;
}
}
Let me know if you think it is inefficient or anything and if there is something I should change to make it more efficient.
I've marked your answer as correct anyway since I believe it would have easily worked/led me to the answer, so thanks again!
You don't have to search the scene for the Player when the trigger is fired when you want to change the forwardsSpeed
You can obtain a Player$$anonymous$$ove reference from the collided GameObject by using other.gameObject.GetComponent ();
ins$$anonymous$$d of GameObject.FindGameObjectWithTag("Player").GetComponent()
Obviously you'd need to check if that reference is not equal to null before you attempted to change the forwardsSpeed. Other than that, if it works and there are no issues then its fine. If later on you start seeing performance issues, then you can refactor it. Nice work.
Thank you! Yeah I'll just leave it for now, this is going to be for mobile, so once I start testing on that, if I find performance issues, then I'll tweak some things. Good to know you don't need to reference the player's tag when colliding though, that'll help save time for projects in the future.
Thanks again salvon, appreciate it!
Answer by HarshadK · Jun 12, 2015 at 12:22 PM
Firstly Mathf.Lerp
inside OnTriggerEnter2D()
should actually be places inside the Update()
method as OnTriggerEnter2D()
will be executed for one frame only which is undesired for lerping. Also Lerp using Time.deltaTime
instead of Time.time
. Since as time passes after you started playing game the value of Time.time
will be higher resulting in a jump inside of Lerp
.
For position you should provide two values as you are using Vector2
where as currently you are using only one which is lerped.
And you can set the value of maximum
inside OnTriggerEnter2D()
, considering maximum is your maximum speed of player.
Alright, I've fixed some of those things you've mentioned about the 2 values and the Time.deltaTime, but I'm not sure how I would go about moving half of this to update with the other half in this OnTriggerEnter2D function..
transform.position = new Vector2($$anonymous$$athf.Lerp($$anonymous$$imum, maximum, Time.deltaTime),0);
This is where the last part of the answer comes in. You can put Lerp inside Update and set the value of maximum inside OnTriggerEnter2D.
As:
void OnTriggerEnter2D(Collider2D other) {
if (other.tag == "SpeedBoost") {
maximum += 5f; // Just added 5 to the maximum speed
Destroy (other.gameObject);
}
}
And now put that Lerp inside Update().
Alright thanks, I've tried it now and my character and also the speed boost, both disappear immediately when I hit play, this is for a 2D game and I'm trying to get it to go to the right, am I doing it correctly? Or is both my player and my speed boost getting destroyed instantly or something?
You are actually setting the position of the player equal to the value returned by your lerp for speed.
You should update the position of the player based on current position plus the delta in the position based on the speed. Something like:
// Get the speed value for the player using lerp for acceleration
float speed = $$anonymous$$athf.Lerp($$anonymous$$imum, maximum, Time.deltaTime);
// Update position of player using the current position and speed
Vector2 pos = transform.position;
pos.x += speed * Time.deltaTime; // Just added the delta position to the current position of player
transform.position = pos;
Alright, well at least my character isn't disappearing instantly now, but now he's just accelerating off of the screen rapidly, changing float variables isn't changing anything either.
public float $$anonymous$$imum = 0.0f;
public float maximum = 20.0f;
public float acceleration = 2.0f;
void Update() {
//transform.position = new Vector2($$anonymous$$athf.Lerp($$anonymous$$imum, maximum, Time.deltaTime),0);
// Get the speed value for the player using lerp for acceleration
float speed = $$anonymous$$athf.Lerp ($$anonymous$$imum, maximum, Time.deltaTime);
// Update position of player using the current position and speed
Vector2 pos = transform.position;
pos.x += speed * Time.deltaTime; // Just added the delta position to the current position of player
transform.position = pos;
if (Input.Get$$anonymous$$ey ($$anonymous$$eyCode.F)) {
transform.position += Vector3.right * horizontalSpeed * Time.deltaTime;
} else {
transform.position -= Vector3.right * backwardsSpeed * Time.deltaTime;
}
}
void OnTriggerEnter2D(Collider2D other) {
if (other.tag == "$$anonymous$$iniFish") {
maximum += 5f; // Just added 5 to the maximum speed
//transform.position = new Vector2($$anonymous$$athf.Lerp($$anonymous$$imum, maximum, Time.deltaTime),0);
//transform.position += Vector3.right * horizontalSpeed * Time.deltaTime;
Destroy (other.gameObject);
}
}
}
Is there something I'm missing or not doing here?
Your answer
Follow this Question
Related Questions
How to Set the Game Speed Based on the Player's Current Score? 1 Answer
Multiple Cars not working 1 Answer
Distribute terrain in zones 3 Answers
Even / Constant Speed and Jumping 2D 1 Answer
Bullet not moving from script 3 Answers