I want to create a game in which the camera moves in the y-axis (upwards) with gradually increasing speed.
void Update () {
float translation = 0.5f;
transform.Translate (0, translation, 0);
I used this code, but I want to increase the rate of speed
One method would be to create a timer and increment the speed every time X amount of seconds has passed:
float translation = 0.5f;
float timer = 0f;
void Update()
{
timer += Time.deltaTime;
if (timer > 1f) //after 1 second has passed...
{
timer = 0; // reset timer
translation += 0.5f; //increase speed by 0.5
}
transform.Translate (0, translation, 0);
}
Functions like Vector3.Lerp(), Vector3.MoveTowards and Mathf.Lerp(), Mathf.MoveTowards() will help you do just that.
You can also multiply your translation by Time.deltaTime and control the speed by controlling the translation value.
public float BaseTranslationSpeed = 0.5f ;
public float TranslationSpeedIncreaseRate = 1 ;
private float translationSpeed ;
void Start()
{
translationSpeed = BaseTranslationSpeed ;
}
void Update ()
{
translationSpeed += TranslationSpeedIncreaseRate ;
// Multiplying by Time.deltaTime is advised in order to be frame independant
transform.Translate (0, translationSpeed * Time.deltaTime , 0);
}
You can even use an Animation curve to control the speed :
public AnimationCurve SpeedOverTime ; // Change the curve in the inspector
private float startTime ;
void Start()
{
startTime = Time.time ;
}
void Update ()
{
// Multiplying by Time.deltaTime is advised in order to be frame independant
transform.Translate (0, SpeedOverTime.Evaluate( Time.time - startTime ) * Time.deltaTime , 0);
}
Related
I'm new in unity and in C# in general.
I was trying to make an animation with scale of a rectangle where it's getting bigger and smaller with time. I tried to use the statement transform.localScale but I didn't know how to make it with time, like a loop. So it gets big and small in a time frame of the 30s for example.
cube.transform.localScale = new Vector3(2.0f, 2.0f, 2.0f);
float TotalTime;
float Scale = 1;
GameObject Target;
// Start is called before the first frame update
void Start()
{
Target = this.gameObject;
}
// Update is called once per frame
void Update()
{
TotalTime += Time.deltaTime;
if (TotalTime < 30)
{
Scale += 0.01f;
Target.transform.localScale = Vector3.one * Scale;
}
}
I I set the lerp to 1 or to 10 the transform is moving to the target too fast.
At the top :
public AnimationCurve curve = AnimationCurve.Linear(0.0f, 0.0f, 1.0f, 1.0f);
public float duration = 10.0f;
private float t;
At Start()
void Start()
{
t = 0.0f;
}
At Update()
void Update()
{
switch (state)
{
case TransitionState.MovingTowards:
var v = targetTransform.position - transform.position;
if (v.magnitude < 0.001f)
{
state = TransitionState.Transferring;
originTransform = targetTransform;
timer = 0;
return;
}
t += Time.deltaTime;
float s = t / duration;
transform.position = Vector3.Lerp(transform.position,
targetTransform.position, curve.Evaluate(s));
break;
}
}
The curve animation in the editor :
You seem to lerp from Transform.Position to your TargetPosition. That means that everytime you move you lerp from a new starting position. This will make your object move exponantially. Try lerping from a fixed start position to a fixed end position. (Unless this is what you actually want to happen)
If I read your code correctly your duration is the exact duration in seconds that your lerp should take. So I assume that's correct, just fix the "start" position of your lerp.
I am trying to rotate the hand of the clock on click, but nothing is actually happening, none of the arrows is actually moving so I probably did something wrong... any help would be much appreciated, thank you
script below
public class Clock : MonoBehaviour {
public GameObject minuteHand;
public GameObject hourHand;
private Quaternion targetRotation;
float speed = 0.1f;
void Start()
{
targetRotation = transform.rotation;
}
void Update()
{
if (Input.GetMouseButtonDown(0))
{
minuteHand.transform.rotation = Quaternion.Lerp(minuteHand.transform.rotation, targetRotation, Time.deltaTime * speed);
}
} }
Your code is only executed exactly in one single frame when the mouse button goes down.
Also that is not how Lerp works. Lerp expects a factor between 0 and 1 and interpolates both values. If you multiply your speed (0.1) and the Time.deltaTime which for 60FPS has a value of about 1/60f = 0.017f you get a resulting factor of about 0.0017f => You will always stay pretty close to the first value
especially since additionally your targetRotation always equals the current transform.rotation!
I assume what you wanted is: Every click move the minute 6° ahead (360°/60 minutes = 6°/minute).
Once a full circle is done move the hour 30° ahead (360°/12 hours = 30°/hour)
public class Clock : MonoBehaviour
{
public GameObject minuteHand;
public GameObject hourHand;
Quaternion originalRotationMinute;
Quaternion originalRotationHour;
int minutes;
int hours;
// Store original orientations
void Start()
{
originalRotationMinute = minuteHand.transform.rotation;
originalRotationHour = hourHand.transform.rotation;
}
void Update()
{
if (Input.GetMouseButtonDown(0))
{
// First calculate the new time
minutes++;
if(minutes == 60)
{
minutes = 0;
hours++;
if(hours = 12)
{
hours = 0;
}
}
// Now update the rotations with the new time
// I'm assuming here you want to rotate around the Z axis
// if this is not the case change this according to your needs
var targetMinuteRotation = originalRotationMinute * Quaternion.Euler(0, 0, 6.0f * minutes);
var targetHourRotation = originalRotationHour * Quaternion.Euler(0, 0, 30.0f * hours);
minuteHand.transform.rotation = targetMinuteRotation;
hourHand.transform.rotation = targetHourRotation;
}
}
}
This would make the clock "jump" to the target rotations. If what you rather wanted is a smooth rotation (what I assume from the usage of Lerp) I would probably use a Coroutine for that:
public class Clock : MonoBehaviour
{
public GameObject minuteHand;
public GameObject hourHand;
float speed = 0.1f;
Quaternion originalRotationMinute;
Quaternion originalRotationHour;
int minutes;
int hours;
void Start()
{
originalRotationMinute = minuteHand.transform.rotation;
originalRotationHour = hourHand.transform.rotation;
}
void Update()
{
if (Input.GetMouseButtonDown(0))
{
// cancel the current routines
StopAllCoroutines();
// calculate the new time
minutes++;
if(minutes == 60)
{
minutes = 0;
hours++;
if(hours = 12) hours = 0;
}
// I'm assuming here you want to rotate around the Z axis
// if this is not the case change this according to your needs
var targetMinuteRotation = originalRotationMinute * Quaternion.Euler(0, 0, 6.0f * minutes);
var targetHourRotation = originalRotationHour * Quaternion.Euler(0, 0, 30.0f * hours);
// This time instead of directly setting the values start coroutines
// to rotate the hands smoothly according to the given speed
StartCoroutine (RotateTo(minuteHand, targetMinuteRotation));
StartCoroutine (RotateTo(hourHand, targetHourRotation));
}
}
// rotate the given object to the given target rotation
// according to the given speed
private IEnumerator RotateTo(GameObject obj, Quaternion targetRotation)
{
var targetTransform = obj.transform;
var current = targetTransform.rotation;
// I your are not rotating on the Z axis change this accordingly to your needs
var difference = targetRotation.eulerAngels.z - current.eulerAngles.z;
if(Mathf.Approximately(0, difference)) yield break;
var duration = difference / speed;
var timePassed = 0f;
while(timePassed <= duration)
{
var factor = timePassed / duration;
targetTransform.rotation = Quaternion.Lerp(current, targetRotation, factor);
timePassed += Time.deltaTime;
yield return null;
}
// t be sure set the final rotation once in the end
targetTransform.rotation = targetRotation;
}
}
Typed on smartphone but I hope the idea gets clear
For me only this works. You can't modify speed to make it even slower, but it looks fine (may be it will be helpful to someone)
float speed = 0.1f //how fast rotate
private void FixedUpdate()
{
nextRot = hour * -30;
transform.rotation = Quaternion.Lerp(transform.rotation, Quaternion.Euler(0, 0, nextRot), speed);
}
I'm trying to create an ability of sprinting in 2d Unity (C#) that has an energy bar so it can't be used endlessly. What am I missing?
I've tried making sprint a function and call it when the X key was pressed. Tried to multiply the position of it but I got a blinking ability over a short distance.
\\ this is my movement script, other variables we're declared earlier in the code
void Update() {
Vector2 mi = new Vector2(Input.GetAxisRaw("Horizontal"), Input.GetAxisRaw("Vertical"));
mv = mi.normalized * speed;
}
private void FixedUpdate() {
rb.MovePosition(rb.position + mv * Time.fixedDeltaTime);
}
I expect the code to make the player go twice the normal speed when the X key is pressed but it can only be used when the energy hasn't ran out.
Don't see your implementation of "energy" but I would simply use a
public float energy;
// How much is energy reduced per second?
public float decreaseSpeed;
for increasing the speed if x is pressed do
private void Update()
{
Vector2 mi = new Vector2(Input.GetAxisRaw("Horizontal"), Input.GetAxisRaw("Vertical"));
mv = mi.normalized * speed;
if(Input.GetKey(KeyCode.X) && energy > 0)
{
// Reduce energy by decreaseSpeed per second
energy -= decreaseSpeed * Time.deltaTime;
// if needed avoid negative value
energy = Mathf.Max(0, energy);
// double the move distance
mv *= 2;
}
}
Btw ot is recommended to use Time.deltaTime instead of Time.fixedDeltaTime also in FixedUpdate (see Time.fixedDeltaTime)
In Update check if sprint axis (create a Sprint axis in the project input settings). Also, have a variable for how fast your energy bar drains while sprinting:
public float energyBarDrainRate = 1f;
private bool isSprinting = false;
void Update() {
isSprinting = Input.GetAxis("Sprint") > 0f;
Vector2 mi = new Vector2(Input.GetAxisRaw("Horizontal"), Input.GetAxisRaw("Vertical"));
mv = mi.normalized * speed;
}
Then in fixedupdate, check if your energy bar has enough to drain for that frame, and if it does then drain it and increase the effective movespeed that frame:
private void FixedUpdate() {
float energyToDrain = energyBarDrainRate * Time.deltaTime
bool drainSprint = energyAmount > energyToDrain ;
float effectiveMv = mv;
if (drainSprint && isSprinting) {
effectiveMv = mv * 2f;
energyAmount -= energyToDrain;
}
rb.MovePosition(rb.position + effectiveMv * Time.deltaTime);
}
While the game is running and i press none stop on the key p i see the spaceship moving faster and faster. But the value of the variable thrust is all the 5 never change. Then what value show and change that make the acceleration ? And what the thrust do ? If i change the thrust from 5 to 10 ?
I added to my spaceship a Rigidbody component.
The way i'm doing it is the right way to add acceleration to my spaceship ?
I want to display in the OnGUI the value of the acceleration each time i press the p key.
using UnityEngine;
using System.Collections;
public class ControlShip : MonoBehaviour {
public int rotationSpeed = 75;
public int movementspeed = 10;
private int thrust = 5;
Rigidbody _rigidbody;
void Start () {
_rigidbody = GetComponent<Rigidbody>();
Debug.Log("Acc Speed: " + thrust);
}
void Update () {
var v3 = new Vector3(Input.GetAxis("Vertical"), Input.GetAxis("Horizontal"), 0.0f);
transform.Rotate(v3 * rotationSpeed * Time.deltaTime);
transform.position += transform.forward * Time.deltaTime * movementspeed;
if (Input.GetKey(KeyCode.Z))
transform.Rotate(Vector3.forward * rotationSpeed * Time.deltaTime);
if (Input.GetKey("p"))
{
_rigidbody.AddRelativeForce(0f, 0f, thrust, ForceMode.Acceleration);
}
}
void OnGUI()
{
GUI.Label(new Rect(100, 100, 200, 200), "Acc Speed: " + thrust);
}
}
Update
My script now after changes. When i press the p key the spaceship is gone fast and the value of the acceleration is 0 all the time in the OnGUI:
using UnityEngine;
using System.Collections;
public class ControlShip : MonoBehaviour {
public int rotationSpeed = 75;
public int movementspeed = 10;
private int thrust = 5;
bool isPKeyDown = false;
float acceleration = .0f;
Vector3 previousPosition = Vector3.zero;
Rigidbody _rigidbody;
// Use this for initialization
void Start () {
_rigidbody = GetComponent<Rigidbody>();
Debug.Log("Acc Speed: " + thrust);
}
// Update is called once per frame
void Update () {
var v3 = new Vector3(Input.GetAxis("Vertical"), Input.GetAxis("Horizontal"), 0.0f);
transform.Rotate(v3 * rotationSpeed * Time.deltaTime);
transform.position += transform.forward * Time.deltaTime * movementspeed;
if (Input.GetKey(KeyCode.Z))
transform.Rotate(Vector3.forward * rotationSpeed * Time.deltaTime);
if (Input.GetKey("p"))
{
isPKeyDown = Input.GetKey("p");
float distance = Vector3.Distance(previousPosition, transform.position);
float acceleration = distance / Mathf.Pow(Time.deltaTime, 2);
previousPosition = transform.position;
_rigidbody.AddRelativeForce(0f, 0f, acceleration, ForceMode.Acceleration);
}
}
void OnGUI()
{
if (isPKeyDown)
{
GUI.Label(new Rect(100, 100, 200, 200), "Acc Speed: " + acceleration);
}
}
}
Starting from the beginnig, thrust is the value of the actual force ( a push force ) for your starship. So the bigger the value the stronger it "pushes" your starship.
If your script works then yes it is a good way of adding acceleration ( that depends on what you think )
To be able to show acceleration value when user pushes "P" key you should calculate the acceleration value ( how to calculate, or just use #Dan Wilson answer/comment ).
Then you should modify your Update method:
public void Update(){
isPKeyDown = Input.GetKey("p");
// ... rest of your code
}
update your class members:
bool isPKeyDown = false;
float acceleration = .0f;
update your OnGUI method:
public void OnGUI(){
if ( isPKeyDown ) {
GUI.Label(new Rect(100, 100, 200, 200), "Acc Speed: " + acceleration);
}
}
and to calculate your acceleration and playing with rigidbody i would recommend using fixed update:
public void FixedUpdate(){
// calculate acceleration here...
acceleration = ... ;
if ( isPKeyDown ) {
_rigidbody.AddRelativeForce(0f, 0f, thrust, ForceMode.Acceleration);
}
}
EDIT:
Easiest way of finding out the acceleration:
// as a member field
Vector3 previousPosition = Vector3.Zero;
// in update
float distance = Vector3.Distance(previousPosition, transform.Position);
float acceleration = distance / Mathf.Pow(Time.deltaTime, 2);
previousPosition = transform.Position;
EDIT2:
updated code on pastebin
I think what you're looking for is velocity. And to see the acceleration over a specific time interval you need to compare the difference in velocity divided by the time between them. The value 5 you're printing is the value you add, not the value of the spaceship.
acceleration = (rigidbody.velocity - lastVelocity) / Time.fixedDeltaTime;
lastVelocity = rigidbody.velocity;
Further reading with this example here