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);
}
Related
So I am making game and I need good PlayerMovement Script but there is little problem. You see I made so that my player is following this path (I didn't make it I downloaded it from marketplace) and he can go only forward. Then I put another Vector3 (horizontalMove) value and hooked it to transform.position and didn't get what I really wanted. When I hit play everything works and I can go Left to Right but my position does not stay the same. The moment I let go of my keys (a, d) my player returns to track, resets in middle. I need it to stay in the position I left him. And too, just adding rb.position in my transform.position just send me flying in the air. I need help.
`public class PathFollower : MonoBehaviour
{
public PathCreator pathCreator;
public EndOfPathInstruction endOfPathInstruction;
public float speed = 5;
float distanceTravelled;
float horizontalInput;
[SerializeField] float horizontalMultiplier = 2;
public Rigidbody rb;
void Start() {
if (pathCreator != null)
{
// Subscribed to the pathUpdated event so that we're notified if the path changes during the game
pathCreator.pathUpdated += OnPathChanged;
}
}
void Update()
{
if (pathCreator != null)
{
horizontalInput = Input.GetAxis("Horizontal");
Vector3 horizontalMove = transform.right * horizontalInput * speed * Time.fixedDeltaTime * horizontalMultiplier;
distanceTravelled += speed * Time.deltaTime;
Debug.Log();
transform.position = pathCreator.path.GetPointAtDistance(distanceTravelled, endOfPathInstruction) + new Vector3 (0,1,0) + horizontalMove;
transform.rotation = pathCreator.path.GetRotationAtDistance(distanceTravelled, endOfPathInstruction);
}
}
// If the path changes during the game, update the distance travelled so that the follower's position on the new path
// is as close as possible to its position on the old path
void OnPathChanged() {
distanceTravelled = pathCreator.path.GetClosestDistanceAlongPath(transform.position);
}
}
}`
You need a global variable that holds the value of horizontalMove, so it isn't reset in the update loop.
Vector3 horizontalMove;
void Update()
{
if (pathCreator != null)
{
horizontalInput = Input.GetAxis("Horizontal");
Vector3 horizontalMove += transform.right * horizontalInput * speed * Time.deltaTime * horizontalMultiplier;
distanceTravelled += speed * Time.deltaTime;
Debug.Log();
transform.position = pathCreator.path.GetPointAtDistance(distanceTravelled, endOfPathInstruction) + new Vector3 (0,1,0) + horizontalMove;
transform.rotation = pathCreator.path.GetRotationAtDistance(distanceTravelled, endOfPathInstruction);
}
}
I also took the liberty to change fixedDeltaTime to deltaTime, since that is the appropriate variable for an Update context.
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 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);
}
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
I am building an infinite vertical platformer for mobile platforms and I am using the accelerometer to move the player left and right. The further the device is tilted the faster the player moves across the screen. Currently my player is a little too shakey and I would like to create a more fluid movement across the screen. Here is my code to move the character:
/********************************* Variables **************************************/
// Variables
float jumpForce = 700f;
float maxSpeed;
float acceleration;
/********************************* Start Method ************************************/
void Start ()
{
acceleration = Mathf.Abs (Input.acceleration.y);
}
/************************************ Fixed Update *************************************/
void FixedUpdate () {
if (acceleration < 0.2f) {
maxSpeed = 17;
} else if (acceleration < 0.9f) {
maxSpeed = 25;
} else {
maxSpeed = 40;
}
float move = Input.acceleration.x;
rigidbody2D.velocity = new Vector2 (move * maxSpeed, rigidbody2D.velocity.y);
/******************************* Collision Function ******************************/
void OnCollisionEnter2D(Collision2D coll)
{
foreach(ContactPoint2D contact in coll.contacts)
{
rigidbody2D.AddForce (new Vector2(0, jumpForce));
}
}
Can't you just use your Input.acceleration.y as the speed? That way you wont need the if conditions. If that's not enough, then multiply it by a multiplier.
void Update () {
maxSpeed = Mathf.Abs(Input.acceleration.y);
speedMultiplier = 30;
float move = Input.acceleration.x;
rigidbody2D.velocity = new Vector2 (move * maxSpeed * speedMultiplier, rigidbody2D.velocity.y);
You can just adjust the speedMultiplier to match your needs afterwards.
Also if you have some physics works (in this case rigidbody2D.velocity), you should use Update() instead of FixedUpdate().
You can use Mathf.Lerp method for smoothing the velocity values.
Try to use
maxSpeed = Mathf.Lerp(maxSpeed, 17, Time.deltaTime);
instead of
maxSpeed = 17;