In-game Dash not consistent, I think effected by velocity - c#

I'm working on a 3D fps, and want a dash. The player uses a character controller, and no rigidbody. My original implementation:
x = Input.GetAxis("Horizontal"); //just gets ur wasd inputs by default
z = Input.GetAxis("Vertical");
Vector3 move = transform.right * x + transform.forward * z; //creates a movement vector
controller.Move(move * speed * Time.deltaTime); //moves the player
if (currentDashLength < dashLength ) //dashes for a set time period
{
currentDashLength += Time.deltaTime;
velocity.y = 0; //keeps you up in the air
controller.Move(move * Time.deltaTime * dashSpeed);
}
else
{
currentDashLength = dashLength;
isDashing = false;
}
if (Input.GetKeyDown(KeyCode.LeftShift) && dashTimer >= 1 && !isCrouching)
{
isDashing = true;
dashTimer -= 1;
currentDashLength = 0f;
health.GiveIFrames(dashLength);
}
This dash works fine, but I realized that if you had pressed shift right after starting to move, the dash would be significantly weaker. I assumed this was due to the fact that my current velocity was low, so the acceleration from the Move function didn't make me reach the speed I would when already moving at terminal velocity. I tried to fix this by multiplying the Move function inputs by 1/(the horizontal velocity of the player) but this didn't fix the issue. My full dashing code:
float dispX = transform.position.x - posX; //gets chnage in position since last frame, this is important to caluclate velocity, since the player isnt using a rigidbody
float dispY = transform.position.y - posY;
float dispZ = transform.position.z - posZ;
posX = transform.position.x;
posY = transform.position.y;
posZ = transform.position.z;
float horizontalVelocity = Mathf.Sqrt(dispX*dispX + dispZ*dispZ) / Time.deltaTime;
x = Input.GetAxis("Horizontal"); //just gets ur wasd inputs by default
z = Input.GetAxis("Vertical");
Vector3 move = transform.right * x + transform.forward * z; //creates a movement vector
controller.Move(move * speed * Time.deltaTime); //moves the player
if (currentDashLength < dashLength )
{
currentDashLength += Time.deltaTime;
velocity.y = 0;
if(horizontalVelocity == 0)
{
Debug.Log("Cannot dash while standing still");
}
else
{
controller.Move(move * Time.deltaTime * dashSpeed * (1 / horizontalVelocity));
}
}
else
{
currentDashLength = dashLength;
isDashing = false;
}
if (Input.GetKeyDown(KeyCode.LeftShift) && dashTimer >= 1 && !isCrouching)
{
isDashing = true;
dashTimer -= 1;
currentDashLength = 0f;
health.GiveIFrames(dashLength);
}
How would I go about ensuring that the dash speed is constant?
(I tried to post this on unity answers, but the website isn't responding to me)

To get the desired behaviour I have re-written your original script by quite a lot, hope that is okay! This code only give you movement and dash control, and nothing else. You'll have to add your crouch check and health stuff back in.
Essentially, we check if the player is dashing before applying any movement, this way we don't add the dash to the current movement. If the player is dashing, we ignore their forward input and apply forward movement based on the predetermined dash. If we aren't dashing then we apply the calculated movement as usual.
private CharacterController controller;
public float speed = 10.0f;
public float dashSpeed = 20.0f;
public float dashLength = 0.5f;
private float currentDashLength = 0;
private bool isDashing = false;
private void Start()
{
controller = GetComponent<CharacterController>();
}
private void Update()
{
float x = Input.GetAxis("Horizontal");
float z = Input.GetAxis("Vertical");
// Same as before
Vector3 move = new Vector3(x, 0, z);
// gets the move direction
// before we move, check if dashing
if (isDashing)
{
currentDashLength += Time.deltaTime;
move = new Vector3(move.x * dashSpeed, move.y, 1 * dashSpeed);
// this gets the current player movement, and replaces the forward velocity rather than adding to it. We add to the sideways velocity to allow for slight directional control.
// do this instead if you want the dash to only move the player in the forward direction, and prevent strafing: move = new Vector3(move.x, move.y, 1 * dashSpeed);
if (currentDashLength >= dashLength) // when we run out of time, set dash to false
{
isDashing = false;
}
}
else // if we are not dashing then move as normal
{
move *= speed;
if (Input.GetKeyDown(KeyCode.LeftShift) && move.magnitude > 0) // stops the dash ability being used when stationary
{
isDashing = true;
currentDashLength = 0;
}
}
controller.Move(move * Time.deltaTime);
}

float dispX = transform.position.x - posX;
float dispY = transform.position.y - posY;
float dispZ = transform.position.z - posZ;
posX = transform.position.x;
posY = transform.position.y;
posZ = transform.position.z;
float horizontalVelocity = Mathf.Sqrt(dispX*dispX + dispZ*dispZ) / Time.deltaTime;
x = Input.GetAxis("Horizontal");
z = Input.GetAxis("Vertical");
Vector3 move = transform.right * x + transform.forward * z;
controller.Move(move * speed * Time.deltaTime);
if (currentDashLength < dashLength )
{
currentDashLength += Time.deltaTime;
velocity.y = 0;
Vector3 dashMove = move * Time.deltaTime * dashSpeed; // Calculates the dash movement vector
// Move the player based on the dash movement vector
controller.Move(dashMove);
}
else
{
currentDashLength = dashLength;
isDashing = false;
}
if (Input.GetKeyDown(KeyCode.LeftShift) && dashTimer >= 1 && !isCrouching)
{
isDashing = true;
dashTimer -= 1;
currentDashLength = 0f;
health.GiveIFrames(dashLength);
}
By calculating the dash movement vector independently from the player's horizontal velocity, you can ensure that the dash speed remains constant regardless of whether the player is moving before dashing or not.
I think this is what you were trying to achieve? Hope it helps!

Related

Clamp RotateAround object Unity

I am making a script to rotate my camera around a sphere but I need to clamp the y axis so the camera does not co over the polls of the sphere I am using rotate around to move my camera.
Thanks!
My current code
public float sensitivity = 1;
public float moveSpeed = 10;
public float maxUp = 45f;
public float maxDown = -45f;
public Transform target;
void Update()
{
transform.LookAt(target);
float HorizontalAxis = Input.GetAxis("Horizontal") * moveSpeed;
float VerticalAxis = Input.GetAxis("Vertical") * moveSpeed;
if (HorizontalAxis >= 1 || VerticalAxis >= 1 || HorizontalAxis <= -1 || VerticalAxis <= -1)
{
Quaternion targetPos = transform.rotation;
targetPos.x += HorizontalAxis * sensitivity;
targetPos.y += VerticalAxis * sensitivity;
transform.RotateAround(target.position, Vector3.left, targetPos.y);
transform.RotateAround(target.position, Vector3.up, targetPos.x);
}
}
Your code makes no sense to begin with.
You do
Quaternion targetPos = transform.rotation;
targetPos.x += HorizontalAxis * sensitivity;
targetPos.y += VerticalAxis * sensitivity;
Just to then use these as parameters in
transform.RotateAround(target.position, Vector3.left, targetPos.y);
transform.RotateAround(target.position, Vector3.up, targetPos.x);
A Quaternion has not three but four components x, y, z and w and they move in ranges between -1 and 1. You never touch the individual component of a Quaternion except you really know exactly what you are doing!
You rather simply want to use the HorizontalAxis and VerticalAxis directly as the parameters to RotateAround.
You could rather simply remember and clamp how much you already rotated like e.g.
private float rotatedY;
private void Update()
{
transform.LookAt(target);
// why two different multipliers anyway though?
var HorizontalAxis = Input.GetAxis("Horizontal") * moveSpeed * sensitivity;
var VerticalAxis = Input.GetAxis("Vertical") * moveSpeed * sensitivity;
// would a positive rotation exceed the maxUp?
if(rotatedY + VerticalAxis > maxUp)
{
// then rotate only so much that you terminate exactly on maxUp
VerticalAxis = maxUp - rotatedY;
}
// would a negative rotation exceed the maxDown?
else if(rotatedY + VerticalAxis < maxDown)
{
// then you rotate only that much that you terminate exactly on maxDown
VerticalAxis = maxDown - rotatedY;
}
transform.RotateAround(target.position, Vector3.left, VerticalAxis);
transform.RotateAround(target.position, Vector3.up, HorizontalAxis);
// sum up how much you already rotated vertically
rotatedY += VerticalAxis;
}

How to make a curved flight path?

How to make a bullet fly in an arc when shooting and hit the player.
As in this picture . I tried to use formulas from physics, the body is thrown at an angle to the horizon, that's what came of it . But the bullet flies away into the void
velocity = Mathf.Round(Vector3.Distance(lastpos, transform.position) / Time.deltaTime);
lastpos = transform.position;
Vector3 direction = PlayeCar.position - Vector3.zero;
float angle = Mathf.Atan2(direction.y, direction.x); // радианы
float x = velocity * Mathf.Cos(angle) + gravity * (time* time) / 2;
float y = velocity * Mathf.Sin(angle);
transform.position = new Vector2(x, y)
;
Sample orientative method could be (The script would be attached to the gun that shots, so when the code referes to transform, refers to the gun's transfom):
public void LaunchTarget()
{
Vector3 initialSpeed = transform.forward; //shot direction, gun's forward
GameObject go = GameObject.Instantiate(m_bullet);//reference to bullet prefab
//in case you need to randomize the shot speed
initialSpeed = transform.forward * Random.Range(m_minLaunchSpeed, m_maxLaunchSpeed);
//set the initial position of the bullet in the gun
go.transform.position = transform.position;
// shoot (give speed to the bullets rigidbody)
go.GetComponent<Rigidbody>().velocity = initialSpeed;
//initially disabled soas to see the bullet when shot
go.SetActive(true);
}
Hope that helps
I did it !!!! at the time of the bullet’s flight, I turn it toward the player in an intermittent manner. And after a while I delete it
void Start()
{
rigidbodyBullet = GetComponent<Rigidbody2D>();
Player = GameObject.Find("carPlayer").GetComponent<Transform>();
_distance = Vector3.Distance(Player.position, transform.position);
Invoke("DestroyArcBullet", 1.5f);
limitDistance = _distance / 1.3f;
}
void Update()
{
transform.position += transform.up * Time.deltaTime * 5f;
_distance = Vector3.Distance(Player.position, transform.position);
if (_distance < limitDistance)
{
var turn = Quaternion.Lerp(transform.rotation,
Quaternion.LookRotation(Vector3.forward, Player.position - transform.position), Time.deltaTime * 2);
rigidbodyBullet.MoveRotation(turn.eulerAngles.z);
}
if (this.transform.position.y + this.transform.position.y <= -10 || this.transform.position.y + this.transform.position.y >= 10
|| this.transform.position.x + this.transform.position.x <= -10 || this.transform.position.x + this.transform.position.x >= 10)
{
Destroy(gameObject);
}
}

Dash against slopes using physics in Unity 2D

I'm working on a 2D project in Unity.
The character controller is physics based, so I use rigidbody to move the player. Everything is working fine except when I try to apply a high speed movement to the character, like a dash.
This is how the code looks like.
I just check if the player is dashing, so I increase the Vector2 movement in a certain amount.
private void DashMovement() {
if (isDashing) {
movement.x *= dashFactor;
}
}
I'm also calculating the ground angle, so I set the movement vector to follow the ground inclination.
private void OnSlopeMovement() {
if (isGrounded && !isJumping) {
float moveDistance = Mathf.Abs(movement.x);
float horizontalOnSlope = Mathf.Cos(groundAngle * Mathf.Deg2Rad) * moveDistance * Mathf.Sign(movement.x);
float verticalOnSlope = Mathf.Sin(groundAngle * Mathf.Deg2Rad) * moveDistance;
if (horizontalOnSlope != 0)
movement.x = horizontalOnSlope;
if (isGrounded && verticalOnSlope != 0)
movement.y = verticalOnSlope;
}
SetMaxFallVelocity();
}
So I set the rigidbody velocity for making it move.
private void Move() {
movement.x *= Time.fixedDeltaTime;
if(isGrounded && !isJumping) movement.y *= Time.fixedDeltaTime;
Vector3 targetVelocity = new Vector2(movement.x, movement.y);
PlayerController.rb2d.velocity = Vector3.SmoothDamp(PlayerController.rb2d.velocity, targetVelocity, ref velocity, movementSmoothing);
}
The problem appears when I apply a speed high enough. I understand this issue is because of physics.
I think the ray that checks the ground and is used to calculate the groundAngle doesn't work fast enough to keep track of that movement, so I can not keep the player fixed on the ground.
I would like to find a solution without making the player kinematic, or stopping the dash on slopes.
This is how it looks ingame.
And this is how the rigidbody movement remain right over the ground, following the slopes angle.
EDIT:
This is how I get the ground angle:
private void GroundAngle() {
Vector2 rayOrigin = feetCollider.bounds.center;
rayOrigin.y += 0.1f;
Vector2 rayDirection = (Input.GetAxisRaw("Horizontal") == 0) ? Vector2.right : new Vector2(Input.GetAxisRaw("Horizontal"), 0);
int groundCollisions = Physics2D.RaycastNonAlloc(rayOrigin, Vector2.down, groundResults, Mathf.Infinity, groundMask);
if (groundCollisions > 0) {
groundAngle = Vector2.Angle(groundResults[0].normal, rayDirection) - 90f;
//Debug.DrawRay(rayOrigin, Vector2.down, Color.green);
if (groundAngle > 0 && !isDashing) {
rayOrigin.x += Input.GetAxisRaw("Horizontal") * .125f;
Physics2D.RaycastNonAlloc(rayOrigin, Vector2.down, groundResults, Mathf.Infinity, groundMask);
groundAngle = Vector2.Angle(groundResults[0].normal, rayDirection) - 90f;
//Debug.DrawRay(rayOrigin, Vector2.down, Color.blue);
}
}
}
Thanks to #Ruzhim for the help. I just post a first "solution" for the problem.
According to Ruzhim advises, I've used him code this way.
private void SetPositionAfterTick() {
if (isDashMovement) {
Vector2 currentPosition = new Vector2(transform.position.x, transform.position.y);
currentPosition.y = feetCollider.bounds.min.y;
Vector2 feetPosAfterTick = currentPosition + PlayerController.rb2d.velocity * Time.deltaTime;
float maxFloorCheckDist = .1f;
RaycastHit2D groundCheckAfterTick = Physics2D.Raycast(feetPosAfterTick + Vector2.up * maxFloorCheckDist, Vector2.down, maxFloorCheckDist * 5f);
if (groundCheckAfterTick) {
Vector2 wantedFeetPosAfterTick = groundCheckAfterTick.point;
if (wantedFeetPosAfterTick != feetPosAfterTick) {
//PlayerController.rb2d.transform.position = (wantedFeetPosAfterTick + new Vector2(0f, feetCollider.bounds.min.y - PlayerController.rb2d.position.y));
PlayerController.rb2d.velocity = Vector2.zero;
}
}
}
}
This is how it looks like.
This is good enough to continue polishing that mechanic. I still need to set the position in some way. The rigidbody's position calculation is not working as it
is raised right now, as the condition (wantedFeetPosAfterTick != feetPosAfterTick) is always true, so the character goes throw the floor and fall.
As you can see, I also need to control the down slopes movement, as it uses the slopes movement sometimes, and dash straight forward others.
This is how asker Rubzero implemented the below code to work for them:
private void SetPositionAfterTick() {
if (isDashMovement) {
Vector2 currentPosition = new Vector2(transform.position.x, transform.position.y);
currentPosition.y = feetCollider.bounds.min.y;
Vector2 feetPosAfterTick = currentPosition + PlayerController.rb2d.velocity * Time.deltaTime;
float maxFloorCheckDist = .1f;
RaycastHit2D groundCheckAfterTick = Physics2D.Raycast(feetPosAfterTick + Vector2.up * maxFloorCheckDist,
Vector2.down, maxFloorCheckDist * 5f);
if (groundCheckAfterTick) {
Vector2 wantedFeetPosAfterTick = groundCheckAfterTick.point;
if (wantedFeetPosAfterTick != feetPosAfterTick) {
//PlayerController.rb2d.transform.position = (wantedFeetPosAfterTick + new Vector2(0f, feetCollider.bounds.min.y -
PlayerController.rb2d.position.y));
PlayerController.rb2d.velocity = Vector2.zero;
}
}
}
}
This is how it looks like.
This is good enough to continue polishing that mechanic. I still need
to set the position in some way. The rigidbody's position calculation
is not working as it is raised right now, as the condition
(wantedFeetPosAfterTick != feetPosAfterTick) is always true, so the
character goes throw the floor and fall.
As you can see, I need to control the down slopes movement, as it uses
the slopes movement sometimes, and dash straight forward others.
I agree with AresCaelum; using physics to do slope movement is pretty much the opposite of what you want to be doing if you don't want to preserve momentum when you're done going up/down the slope. Specifically, your problem is here:
float moveDistance = Mathf.Abs(movement.x);
float horizontalOnSlope = Mathf.Cos(groundAngle * Mathf.Deg2Rad) * moveDistance * Mathf.Sign(movement.x);
float verticalOnSlope = Mathf.Sin(groundAngle * Mathf.Deg2Rad) * moveDistance;
This is a problem because the more the player moves horizontally in a frame, the more they will move vertically based on the slope of the ramp they are on. However, this assumption doesn't hold if they should only be traveling up the ramp during only part of the movement during the frame. So, you need a way to handle that situation.
One solution is to use a raycast from where the player would be then if it's above the floor, alter the vertical velocity so that it would place them at that floor's position instead.
First, determine if slope movement has occurred in a physics frame...
private bool slopeMovementOccurred = false;
void FixedUpdate() {
slopeMovementOccurred = false;
// ...
}
private void OnSlopeMovement() {
if (isGrounded && !isJumping) {
slopeMovementOccurred = true;
// ...
}
SetMaxFallVelocity();
}
... and if it has, determine where the player is going to be after the physics update. Then do a physics2d raycast from above that position (by some amount) downward (double the previous amount) to find where the player's position should be, and then change the rb2d.velocity such that it will place the player exactly at the height they should be at.
Assuming you can calculate some kind of Vector2 feetOffset that has the local position of the player's feet:
void FixedUpdate() {
// ...
StickToSlopeLanding();
}
void StickToSlopeLanding() {
if (slopeMovementOccurred) {
Vector2 curVelocity = PlayerController.rb2d.velocity;
Vector2 feetPosAfterTick = PlayerController.transform.position
+ PlayerController.feetOffset
+ curVelocity * Time.deltaTime;
float maxFloorCheckDist = 1.0f;
// determine where the player should "land" after this frame
RaycastHit2D groundCheckAfterTick = Physics2D.Raycast(
feetPosAfterTick + Vector2.up * maxFloorCheckDist,
-Vector2.up, maxFloorCheckDist * 2f);
if (groundCheckAfterTick.collider != null) {
Vector2 wantedFeetPosAfterTick = groundCheckAfterTick.point;
// if basic physics won't take them to landing position
if (wantedFeetPosAfterTick != feetPosAfterTick) {
Vector2 wantedVelocity = curVelocity
+ Vector2.up
* ((wantedFeetPosAfterTick.y - feetPosAfterTick.y)
/ Time.deltaTime);
// adjust velocity so that physics will take them to landing position
PlayerController.rb2d.velocity = wantedVelocity;
// optionally, set a flag so that next frame
// it knows the player should be grounded
}
}
}
}
Hopefully this gets you towards a solution that will work.
Note: you may need to also move the rigidbody so that it doesn't try to clip through the corner at the top of the ramp, and you can determine where to put the rigidbody using another raycast, setting the velocity from that point to be horizontal:
void StickToSlopeLanding() {
if (slopeMovementOccurred) {
Vector2 curVelocity = PlayerController.rb2d.velocity;
Vector2 feetPosAfterTick = PlayerController.transform.position
+ PlayerController.feetOffset
+ curVelocity * Time.deltaTime;
float maxFloorCheckDist = 1.0f;
// determine where the player should "land" after this frame
RaycastHit2D groundCheckAfterTick = Physics2D.Raycast(
feetPosAfterTick + Vector2.up * maxFloorCheckDist,
-Vector2.up, maxFloorCheckDist * 2f);
if (groundCheckAfterTick.collider != null) {
Vector2 wantedFeetPosAfterTick = groundCheckAfterTick.point;
// if basic physics won't take them to landing position
if (wantedFeetPosAfterTick != feetPosAfterTick) {
// look for corner of ramp+landing.
// Offsets ensure we don't raycast from inside/above it
float floorCheckOffsetHeight = 0.01f;
float floorCheckOffsetWidth = 0.5f;
RaycastHit2D rampCornerCheck = Physics2D.Raycast(
wantedFeetPosAfterTick
- floorCheckOffsetHeight * Vector2.up
- floorCheckOffsetWidth * Mathf.Sign(movement.x) * Vector2.right,
Mathf.Sign(movement.x) * Vector2.right);
if (rampCornerCheck.collider != null) {
// put feet at x=corner position
Vector2 cornerPos = Vector2(rampCornerCheck.point.x,
wantedFeetPosAfterTick.y);
PlayerController.rb2d.position = cornerPos
- PlayerController.feetOffset;
// adjust velocity so that physics will take them from corner
// to landing position
Vector2 wantedVelocity = (wantedFeetPosAfterTick - cornerPos)
/ Time.deltaTime;
PlayerController.rb2d.velocity = wantedVelocity;
// optionally, set a flag so that next frame
// it knows the player should be grounded
}
}
}
}
}

Use Lerp Position and Slerp Rotation together (Unity)

This is what I try to do, When I click on a UI Element, the camera smoothly rotate (to look at the target) and simultaneously move on top of the target.
To perform that I use a two Coroutine one for the Lerp Position and the other one for the Slerp Rotation.
The issue is that the rotation doesn't work correctly, normally the camera should look down to see the top of the target but instead of doing this it look like the Camera first look at the target and after that move to his position.
I hope this is understandable ;)
Here is the code c#
Vector3 LocationProjectForPos = new Vector3(Loc_X, 100, Loc_Z);
Vector3 LocationProjectForRot = new Vector3(Loc_X, Loc_Y, Loc_Z);
Vector3 MainCameraPos = MainCamera.transform.position;
if(!IsCameraMoving & LocationProjectForPos != MainCameraPos)
{
StartCoroutine (CoroutineMovePositionCamera(LocationProjectForPos));
StartCoroutine (CoroutineMoveRotationCamera(LocationProjectForRot));
}
}
Moving the position of the Camera with Lerp
public IEnumerator CoroutineMovePositionCamera(Vector3 LocationProject)
{
float lerpTime = 5f;
float currentLerpTime = 0f;
IsCameraMoving = true;
Vector3 startPos = MainCamera.transform.localPosition;
Vector3 endPos = LocationProject;
while (lerpTime > 0)
{
lerpTime -= Time.deltaTime;
currentLerpTime += Time.deltaTime;
if (currentLerpTime > lerpTime)
{
currentLerpTime = lerpTime;
}
float t = currentLerpTime / lerpTime;
t = t*t*t * (t * (6f*t - 15f) + 10f);
//t = t*t * (3f - 2f*t);
//t = 1f - Mathf.Cos(t * Mathf.PI * 0.5f);
MainCamera.transform.localPosition = Vector3.Lerp(startPos, endPos, t);
yield return null;
}
IsCameraMoving = false;
}
Rotate the Camera with Slerp
public IEnumerator CoroutineMoveRotationCamera(Vector3 LocationProject)
{
float lerpTime = 5f;
float currentLerpTime = 0f;
IsCameraMoving = true;
Vector3 relativePos = LocationProject - MainCamera.transform.localPosition;
Quaternion rotation = Quaternion.LookRotation(relativePos);
Quaternion current = MainCamera.transform.localRotation;
while (lerpTime > 0)
{
lerpTime -= Time.deltaTime;
currentLerpTime += Time.deltaTime;
if (currentLerpTime > lerpTime)
{
currentLerpTime = lerpTime;
}
float t = currentLerpTime / lerpTime;
t = t*t*t * (t * (6f*t - 15f) + 10f);
//t = t*t * (3f - 2f*t);
//t = 1f - Mathf.Cos(t * Mathf.PI * 0.5f);
MainCamera.transform.localRotation = Quaternion.Slerp(current, rotation, t);
yield return null;
}
IsCameraMoving = false;
}
Thanks for your help.
In CoroutineMoveRotationCamera, you need to update the relativePostion and rotation inside the while loop.
The relative position is changing while the camera is moving. Right now, your camera rotates based on the vector snapshot you took before the while loop started.
Add the following code after yield statement.
relativePos = LocationProject - Camera.main.transform.position;
rotation = Quaternion.LookRotation(relativePos);
before start coroutine, you should save the initial vars with member vars instead of function local vars

Unity2D Asteroids style game

I am trying to build an asteroids style game in Unity and could really use some help. I believe all my math is correct as far as the ship movement but I am having trouble getting it to work inside Unity. I am having a couple different problems.
The ship does not update with velocity ( if you start moving and then let go, it will stand still)
I am unsure in Unity how to set the ships rotation to my specific angle.
Any help would be greatly appreciated.
public class playerController : MonoBehaviour {
public static float timer;
public static bool timeStarted = false;
Vector2 accel;
Vector2 velocity;
float direction;
float angle;
float shotCooldown;
float speed;
const float pi = 3.141592f;
const float maxSpeed = 300;
const float maxAccel = 500;
void Start () {
timeStarted = true;
}
void Update () {
if (timeStarted == true) {
timer += Time.deltaTime;
}
shotCooldown -= (timer%60);
angle = direction * pi / 180;
if (Input.GetKey(KeyCode.W)) {
accel.y = -Mathf.Cos(angle) * maxAccel;
accel.x = Mathf.Sin(angle) * maxAccel;
velocity += accel * Time.deltaTime;
}
if (Input.GetKey(KeyCode.S)) {
accel.y = -Mathf.Cos(angle) * maxAccel;
accel.x = Mathf.Sin(angle) * maxAccel;
velocity -= accel * Time.deltaTime;
}
if (Input.GetKey(KeyCode.Space)) {
if (shotCooldown <= 0)
{
// Create new shot by instantiating a bullet with current position and angle
shotCooldown = .25f;
}
}
if (Input.GetKey(KeyCode.D)) {
direction += 360 * Time.deltaTime;
}
if (Input.GetKey(KeyCode.A)) {
direction -= 360 * Time.deltaTime;
}
/*
if (this.transform.position.x >= Screen.width && velocity.x > 0) {
this.transform.position.x = 0;
}*/
while (direction < 0) {
direction += 360;
}
while (direction > 360) {
direction -= 360;
}
speed = Mathf.Sqrt( (velocity.x * velocity.x) + (velocity.y * velocity.y));
if (speed > maxSpeed) {
Vector2 normalizedVector = velocity;
normalizedVector.x = normalizedVector.x / speed;
normalizedVector.y = normalizedVector.y / speed;
velocity = normalizedVector * maxSpeed;
}
this.transform.position = velocity * Time.deltaTime;
transform.rotation = Quaternion.AngleAxis(0, new Vector3(0,0,angle));
}
}
It's usually a bad idea to set the position the way you are, because you're not actually using any physics. The way you're doing it, velocity is a new position for the ship, not a speed. Once you let go of the keys, it stops calculating new positions, and thus stops moving.
There are a couple of alternatives which would make for a better result:
1) One way this can be done is by calling: transform.Translate(Vector3.forward * speed * Time.deltaTime) Vector3.forward should correspond to the direction you consider as "forward", but if not, you can change it to whichever works (eg Vector3.up). This means you only really need to calculate a speed and let unity hangle the rest.
2) If you're using a rigidbody on your ship, you could simply do:
rigidbody.AddForce(Vector3.forward * speed * Time.deltaTime) which will automatically accelerate the ship in the given direction by whatever speed you give it.
As for rotation, perhaps try something like this:
if (Input.GetKey(KeyCode.D))
{
Vector3 newRotation = transform.rotation.eulerAngles;
newRotation.z += 10;
transform.rotation = Quaternion.Euler (newRotation);
}
else if (Input.GetKey(KeyCode.A))
{
Vector3 newRotation = transform.rotation.eulerAngles;
newRotation.z -= 10;
transform.rotation = Quaternion.Euler (newRotation);
}

Categories