My player ball is shaking when it changes position in Unity - c#

Hey guys my question is in the title. Basically when I press play everything is OK, the ball starts to go up without shaking, but when I start swiping to change position it starts shaking.
I already tried different things like changing to FixedUpdate() or resetting the player, but it doesn't change. Btw there is no animation on the ball. Can you help me?
Here is the script with the swipe parameters :
public class Swipe : MonoBehaviour
{
private const float DEADZONE = 100.0f;
public static Swipe Instance { set; get; }
private bool tap, swipeLeft, swipeRight, swipeUp, swipeDown;
private Vector2 startTouch, swipeDelta;
public bool Tap { get { return tap; } }
public Vector2 SwipeDelta { get { return swipeDelta; } }
public bool SwipeLeft { get { return swipeLeft; } }
public bool SwipeRight { get { return swipeRight; } }
public bool SwipeUp { get { return swipeUp; } }
public bool SwipeDown { get { return swipeDown; } }
private void Awake()
{
Instance = this;
}
private void Update()
{
// Reseting all the booleans
tap = swipeLeft = swipeRight = swipeDown = swipeUp = false;
#region Stadalone Inputs
if (Input.GetMouseButtonDown(0))
{
tap = true;
startTouch = Input.mousePosition;
}
else if (Input.GetMouseButtonUp(0))
{
startTouch = swipeDelta = Vector2.zero;
}
#endregion
#region Mobile Inputs
if (Input.touches.Length != 0)
{
if (Input.touches[0].phase == TouchPhase.Began)
{
tap = true;
startTouch = Input.mousePosition;
}
else if (Input.touches[0].phase == TouchPhase.Ended || Input.touches[0].phase == TouchPhase.Canceled)
{
startTouch = swipeDelta = Vector2.zero;
}
}
#endregion
// Calculate The Distance
swipeDelta = Vector2.zero;
if (startTouch != Vector2.zero)
{
if (Input.touches.Length != 0)
{
swipeDelta = Input.touches[0].position - startTouch;
}
else if (Input.GetMouseButton(0))
{
swipeDelta = (Vector2)Input.mousePosition - startTouch;
}
}
// Did we cross the deadzone ?
if (swipeDelta.magnitude > DEADZONE)
{
// Which direction ?
float x = swipeDelta.x;
float y = swipeDelta.y;
if (Mathf.Abs(x) > Mathf.Abs(y))
{
// Left or Right
if (x < 0)
swipeLeft = true;
else
swipeRight = true;
}
else
{
// Up or Down
if (y < 0)
swipeDown = true;
else
swipeUp = true;
}
startTouch = swipeDelta = Vector2.zero;
}
}
}
And this the part of the script in Update() or (FixedUpdate(), it doesn't change anything) used to make it move one side or the other on the player :
// Gather the inputs in which tube we should be
if (Swipe.Instance.SwipeLeft)
MoveTube(false);
if (Swipe.Instance.SwipeRight)
MoveTube(true);
// Calculate where we should be in the future
Vector3 targetPosition = transform.position.y * Vector3.up;
if (desiredTube == 0)
targetPosition += Vector3.left * TUBE_DISTANCE;
else if (desiredTube == 2)
targetPosition += Vector3.right * TUBE_DISTANCE;
// Let's calculate our move delta
Vector3 moveVector = Vector3.zero;
moveVector.x = (targetPosition - transform.position).normalized.x * speed;
moveVector.y = speed;
// Move the ball
controller.Move(moveVector * Time.deltaTime);
}
private void MoveTube(bool goingRight)
{
desiredTube += (goingRight) ? 1 : -1;
desiredTube = Mathf.Clamp(desiredTube, 0, 2);
}

I believe you may be having issue here:
// Gather the inputs in which tube we should be
if (Swipe.Instance.SwipeLeft)
MoveTube(false);
if (Swipe.Instance.SwipeRight)
MoveTube(true);
Since Update() is invoked once per frame, this means this will be checked several times per second. So it may be changing the position of the player several times per second, giving this shaking effect you mention.
What you could try is to restrict the times the player can swipe per second.
private float SwipeRate = 0.1f;
private float NextSwipe = 0.0f;
Update(){
if (Swipe.Instance.SwipeLeft && Time.time > NextSwipe)
{
NextSwipe = Time.time+SwipeRate;
MoveTube(false);
}
if (Swipe.Instance.SwipeRight && Time.time > NextSwipe)
{
NextSwipe = Time.time+SwipeRate;
MoveTube(true);
}
}
Edit:
private void MoveTube(bool goingRight)
{
desiredTube += (goingRight) ? 1 : -1;
desiredTube = Mathf.Clamp(desiredTube, 0, 2);
// Calculate where we should be in the future
Vector3 targetPosition = transform.position.y * Vector3.up;
if (desiredTube == 0)
targetPosition += Vector3.left * TUBE_DISTANCE;
else if (desiredTube == 2)
targetPosition += Vector3.right * TUBE_DISTANCE;
// Let's calculate our move delta
Vector3 moveVector = Vector3.zero;
moveVector.x = (targetPosition - transform.position).normalized.x * speed;
moveVector.y = speed;
// Move the ball
controller.Move(moveVector * Time.deltaTime);
}

I found how to solve the problem. So basically I was using the same speed variable to move my ball on the x and y axis and it seems that it created some “switch problem” for unity. So I just created 2 different variables for the speed and I solved the bug like this.

Related

Passing List to another GameObject script, it becomes empty after first operation

I am trying to move a GameObject along a path by stages. Conceptually a first script, connected to the controller, defines the path via a List of Vector3 and a second one connected to the object moves it. To move it first rotates to face the destination and then it simply moves by incrementing transform.position by small steps.
The problem is that once the first part of the path has been completed the rest seems to cancel out (the Count became 0) and the robot stops.
This only happens by giving the list from a second script, trying it with a pre-defined list in the same script works fine.
This is the motion code:
public List<Vector3> pathRover;
[SerializeField] private float roverSpeed;
[SerializeField] private float roverRotateSpeed;
private float dotto;
private bool isRotating = false;
private bool isLerping = false;
private Vector3 startPosition;
private Vector3 targetPosition;
private void FixedUpdate()
{
if (isRotating)
{
//To determine whether the robot faces the direction of movement
dotto = Vector3.Dot(transform.TransformDirection(Vector3.forward), (new Vector3(targetPosition.x, 0, targetPosition.z) - new Vector3(startPosition.x, 0, startPosition.z)).normalized);
if (dotto < 0.98f) // rotate until reached then move
{
transform.Rotate(0, Time.deltaTime * roverRotateSpeed, 0);
Debug.Log(dotto);
}
else
{
isLerping = true;
isRotating = false;
}
}
else if (isLerping)
{
var step = roverSpeed * Time.deltaTime;
transform.position = Vector3.MoveTowards(transform.position, targetPosition, step);
if (Vector3.Distance(transform.position, targetPosition) <= 1f)
{
NextStep();
}
}
}
public void StartMoving(List<Vector3> pathReceived)
{
if (pathReceived.Count > 1)
{
pathRover.Clear();
for (int i = 1; i < pathReceived.Count; i++)
{
pathRover.Add(pathReceived[i]);
}
startPosition = transform.position;
targetPosition = new Vector3(pathRover[0].x, pathRover[0].y + 0.7f, pathRover[0].z); //0.7f for the height of the rover from the ground
isRotating = true;
}
else
{
StopMoving();
}
}
public void StopMoving()
{
isRotating = false;
isLerping = false;
pathRover.Clear();
}
public void NextStep()
{
isLerping = false;
StartMoving(pathRover);
}
From the other script:
roverMover.StartMoving(percorsoList);
No error appears in the debug console, I don't know where I am wrong.
I guess the problem is you are starting the move right at the Start of the script but you call StartMoving after a while. You have to move only when StartMove is called.
public List<Vector3> pathRover;
[SerializeField] private float roverSpeed;
[SerializeField] private float roverRotateSpeed;
private float dotto;
private bool isRotating = false;
private bool isLerping = false;
private Vector3 startPosition;
private Vector3 targetPosition;
boolean startMove = false;
private void FixedUpdate()
{
if(startMove)
Move();
}
public void Move(){
if (isRotating)
{
//To determine whether the robot faces the direction of movement
dotto = Vector3.Dot(transform.TransformDirection(Vector3.forward), (new Vector3(targetPosition.x, 0, targetPosition.z) - new Vector3(startPosition.x, 0, startPosition.z)).normalized);
if (dotto < 0.98f) // rotate until reached then move
{
transform.Rotate(0, Time.deltaTime * roverRotateSpeed, 0);
Debug.Log(dotto);
}
else
{
isLerping = true;
isRotating = false;
}
}
else if (isLerping)
{
var step = roverSpeed * Time.deltaTime;
transform.position = Vector3.MoveTowards(transform.position, targetPosition, step);
if (Vector3.Distance(transform.position, targetPosition) <= 1f)
{
NextStep();
}
}
}
public void StartMoving(List<Vector3> pathReceived)
{
startMove= true;
if (pathReceived.Count > 1)
{
pathRover.Clear();
for (int i = 1; i < pathReceived.Count; i++)
{
pathRover.Add(pathReceived[i]);
}
startPosition = transform.position;
targetPosition = new Vector3(pathRover[0].x, pathRover[0].y + 0.7f, pathRover[0].z); //0.7f for the height of the rover from the ground
isRotating = true;
}
else
{
StopMoving();
}
}
public void StopMoving()
{
isRotating = false;
isLerping = false;
pathRover.Clear();
}
public void NextStep()
{
isLerping = false;
StartMoving(pathRover);
}

Why does my script make my "dash" have a seemingly random duration and how can I fix it?

I am new to coding. I've been trying to Frankenstein basic tutorials into something of my own and it seems ive finally hit a wall. I'm really not sure what is causing this and would like some help to weed out the problem.
at the moment when I press the dash button (left shift) my character dashes in the direction he is facing but for a random duration. I would like it to be consistent and working properly.
Thanks in advance!
PS: Sorry for the long script, it contains everything to do with player movment.
using System.Collections;
using System.Collections.Generic;
using System.Security.Cryptography;
using UnityEngine;
public class CharacterController : MonoBehaviour
{
//Player Movement
public float speed;
public float jumpForce;
public Transform feetPos;
public float checkRadius;
public LayerMask whatIsGround;
public float dashSpeed;
public float startDashTime;
public float dashCooldownTime = 2;
private float nextFireTime = 0;
public Animator animator;
private Rigidbody2D rb;
private float moveInput;
private bool isGrounded;
private float jumpTimeCounter;
public float jumpTime;
private bool isJumping;
private float dashTime;
public int direction;
void Start()
{
animator.GetComponent<Animator>();
rb = GetComponent<Rigidbody2D>();
dashTime = startDashTime;
}
void FixedUpdate()
{
moveInput = Input.GetAxisRaw("Horizontal");
if (direction < 1 )
rb.velocity = new Vector2(moveInput * speed, rb.velocity.y);
}
void Update()
{
// Moving
isGrounded = Physics2D.OverlapCircle(feetPos.position, checkRadius, whatIsGround);
if (moveInput > 0)
{
transform.eulerAngles = new Vector3(0, 0, 0);
animator.SetBool("Moving", true);
}
else if (moveInput < 0)
{
transform.eulerAngles = new Vector3(0, 180, 0);
animator.SetBool("Moving", true);
}
else
{
animator.SetBool("Moving", false);
}
// Jumping
if (isGrounded == true && Input.GetKeyDown(KeyCode.Space))
{
animator.SetTrigger("IsJumping");
isJumping = true;
jumpTimeCounter = jumpTime;
rb.velocity = Vector2.up * jumpForce;
}
if (Input.GetKey(KeyCode.Space) && isJumping == true)
{
if (jumpTimeCounter > 0)
{
rb.velocity = Vector2.up * jumpForce;
jumpTimeCounter -= Time.deltaTime;
}
else
{
isJumping = false;
}
}
if (Input.GetKeyUp(KeyCode.Space))
{
isJumping = false;
}
if (isGrounded == false)
{
animator.SetBool("Grounded", false);
}
if (isGrounded == true)
{
animator.SetBool("Grounded", true);
}
// Dashing
if (Time.time > nextFireTime)
{
if (direction == 0)
{
if (Input.GetKeyDown(KeyCode.LeftShift))
{
UnityEngine.Debug.Log("beaners");
nextFireTime = Time.time + dashCooldownTime;
if ((transform.rotation.eulerAngles.y == 180))
{
Dashleft();
}
else
{
DashRight();
}
}
}
}
else
{
if(dashTime <= 0)
{
direction = 0;
dashTime = startDashTime;
}
else
{
dashTime -= Time.deltaTime;
}
}
}
void Dashleft()
{
direction = 1;
rb.velocity = Vector2.left * dashSpeed;
}
void DashRight()
{
direction = 1;
rb.velocity = Vector2.right * dashSpeed;
}
}
Random duration is because of the use of Rigidbody2D.
See in Unity Rigidbody2D is responsible for each and every single physical interaction. It mean forces from player like player movement and forces from your environment like friction and collision.
Here what is happening is that when your player is dashing there is also player movement force, which is also applied on your player's Rigidbody2d. And friction of ground on which your player is running/dashing on.
I've added a comment on parts that I've changed.
Updated part of your script:
private bool isDashing;
.
.
.
void Update()
{
//Added: putting a Condition to check if you player is not dashing, if it is then
//player won't be able to do anything, As I've scene and done in many games. if you
//don't want this remove it and see what happens, this is not tested so sorry if there
//is something that is not working as intended.
//dashing condition check
if(!isDashing)
{
// Moving
isGrounded = Physics2D.OverlapCircle(feetPos.position, checkRadius, whatIsGround);
if (moveInput > 0)
{
transform.eulerAngles = new Vector3(0, 0, 0);
animator.SetBool("Moving", true);
}
else if (moveInput < 0)
{
transform.eulerAngles = new Vector3(0, 180, 0);
animator.SetBool("Moving", true);
}
else
{
animator.SetBool("Moving", false);
}
// Jumping
if (isGrounded == true && Input.GetKeyDown(KeyCode.Space))
{
animator.SetTrigger("IsJumping");
isJumping = true;
jumpTimeCounter = jumpTime;
//Changed: use Add force method instead of changing the velocity.
rb.AddForce(Vector2.up * jumpForce, ForceMode2D.Impulse);
//rb.velocity = Vector2.up * jumpForce;
}
if (Input.GetKey(KeyCode.Space) && isJumping == true)
{
if (jumpTimeCounter > 0)
{
//Changed: Same this rb.AddForce...
rb.AddForce(Vector2.up * jumpForce, ForceMode2D.Impulse);
//rb.velocity = Vector2.up * jumpForce;
jumpTimeCounter -= Time.deltaTime;
}
else
{
isJumping = false;
}
}
if (Input.GetKeyUp(KeyCode.Space))
{
isJumping = false;
}
if (isGrounded == false)
{
animator.SetBool("Grounded", false);
}
if (isGrounded == true)
{
animator.SetBool("Grounded", true);
}
}
//dashing condition ends
// Dashing
if (Time.time > nextFireTime)
{
//Here your Dash timer ends.
isDashing = false;
if (direction == 0)
{
if (Input.GetKeyDown(KeyCode.LeftShift))
{
UnityEngine.Debug.Log("beaners");
nextFireTime = Time.time + dashCooldownTime;
//Here your Dash timer Starts.
isDashing = true;
if ((transform.rotation.eulerAngles.y == 180))
{
Dashleft();
}
else
{
DashRight();
}
}
}
}
else
{
if(dashTime <= 0)
{
direction = 0;
dashTime = startDashTime;
}
else
{
dashTime -= Time.deltaTime;
}
}
}
visit Unity - Scripting API: Rigidbody2D.AddForce hope it helps.
Happy Coding

How to prevent any player Input if the object is moving

I am creating a clone of Billiards and I cannot work out how to stop the player from interacting with and launching the ball while it is still moving; below is my attempt. I have placed an if statement that checks whether the ball is moving on both the mouseDrag and mouseUp functions. I have also tried using isSleeping() but this caused the ball to not move at all.
If possible I would like to apply this method to all of the balls and not just the cue ball; so that all balls have to have stopped before any actions may happen. This is currently in my "player" script, if I should move it a GameManager script please let me know.
private void Update()
{
speed = rb.velocity.magnitude;
if (speed < 0.5)
{
rb.velocity = new Vector3(0, 0, 0);
}
}
void OnMouseDrag()
{
if (speed == 0)
{
mousePointB.GetComponent<SpriteRenderer>().enabled = true;
currDistance = Vector3.Distance(mousePointA.transform.position, transform.position);
if (currDistance <= 3f)
{
spaceLimit = currDistance;
}
else
{
spaceLimit = maxDistance;
}
shootPower = Mathf.Abs(spaceLimit) * shootPowervar;
Vector3 dimxy = mousePointA.transform.position - transform.position;
float difference = dimxy.magnitude;
mousePointB.transform.position = transform.position + ((dimxy / difference) * currDistance * -1);
mousePointB.transform.position = new Vector3(mousePointB.transform.position.x, mousePointB.transform.position.y, -0.8f);
shootDirection = Vector3.Normalize(mousePointA.transform.position - transform.position);
}
else
{
}
}
void OnMouseUp()
{
if (speed == 0)
{
mousePointB.GetComponent<SpriteRenderer>().enabled = false;
arrow.GetComponent<SpriteRenderer>().enabled = false;
circle.GetComponent<SpriteRenderer>().enabled = false;
Vector3 push = shootDirection * shootPower * -1;
GetComponent<Rigidbody2D>().AddForce(push, ForceMode2D.Impulse);
}
else
{
}
}
if your test speed == 0 is not functional, you could record the last position of the ball, and set a boolean isMoving = true, if actual position of ball is different thant the last, then record the lastposition and so on
Vector3 LastPosition;
bool isMoving;
void Update()
{
isMoving = BallPosition == LastPosition;
:
:
}
void OnMOuseDrag()
{
if(!isMoving) return;
}
void OnMOuseUp()
{
if(!isMoving) return;
}

Vector3.MoveTowards() is not working with TouchInputs

I am trying make a functionality to my game so that the object with containerTransform can move 720f left or right depending upon the touch inputs. I have used Vector3.MoveTowards() but, it shows a **glitchy back and forth movement whenever I swipe right or left, instead of proper transition 720f right or left. I am not sure where my logic went wrong. Here are the complete codes. I am seeking your help. Thank you
private Vector2 startPosition;
private Vector2 endPosition;
public Transform containerTransform;
public float speed;
public float SoftZone = 20f;
//soft zone is the distance upto which the swipe wont work, so swipe length less than it wont trigger the function;
private bool SwipeLeft;
private bool SwipeRight;
private bool boolean;
private Vector3 currentLocation;
private Vector3 endLocation;
void Start()
{
currentLocation = containerTransform.position;
endLocation = containerTransform.position;
}
void Update()
{
if(SwipeLeft) {
containerTransform.position = Vector3.MoveTowards(
currentLocation,
endLocation,
Time.deltaTime * speed
);
if(containerTransform.position == endLocation) {
SwipeLeft = false;
currentLocation = endLocation;
print("swipeleft ends");
}
}
if(SwipeRight) {
containerTransform.position = Vector3.MoveTowards(
currentLocation,
endLocation,
Time.deltaTime * speed
);
if(containerTransform.position == endLocation) {
SwipeRight = false;
currentLocation = endLocation;
print("swiperight ends");
}
}
SwipeCheck ();
}
void SwipeCheck () {
/*if (!SwipeConfirmed){*/
foreach (Touch touch in Input.touches)
{
if(touch.phase == TouchPhase.Began)
{
startPosition = touch.position;
endPosition = touch.position;
boolean = true;
}
if (touch.phase == TouchPhase.Moved)
{
endPosition = touch.position;
}
if (touch.phase == TouchPhase.Ended ||
touch.phase == TouchPhase.Canceled &&
boolean == true)
{
if (startPosition.x - endPosition.x >= SoftZone)
{
SwipeLeft = true;
print("left");
endLocation += new Vector3(
endLocation.x - 720f,
endLocation.y,
endLocation.z
);
}
else if(startPosition.x - endPosition.x <= -SoftZone)
{
SwipeRight = true;
print("right");
endLocation += new Vector3(
endLocation.x + 720f,
endLocation.y,
endLocation.z
);
boolean = false;
}
}
}
}
First of all, Touch.position gives you
The position of the touch in pixel coordinates.
In order to use them for transform.position, you have to convert them to world space 3D coordinates using Camera.ScreenToWorldPoint like
var worldPosition = Camera.main.ScreenToWorldPoint(new Vector3(touch.position.x, touch.position.y, distanceToCamera);
Where distanceToCamera is a value you have to define/calculate to determine how far the point should be in front of the camera.
Note
If you use this often as in Update, you should store the Camera and reuse the reference like this:
private Camera cam;
private void Awake ()
{
cam = Camera.main;
}
//...
var worldPosition = cam.ScreenToWorldPoint( ... );
The main issue
You are using
Vector3.MoveTowards(currentLocation, endLocation, speed * Time.deltaTime);
This will always start a new movement from currentLocation so you never move more than one step/frame away from the currentLocation.
Instead, use the actual current position of the object
containerTransform.position = Vector3.MoveTowards(containerTransform.position, endPosition, speed * Time.deltaTime);
Your code, SwipeLeft and SwipeRight actually do the same thing, so you could just remove one of the blocks.
if (Swipe)
{
containerTransform.position = Vector3.MoveTowards(containerTransform.position, endPosition, speed * Time.deltaTime);
if (containerTransform.position == endLocation)
{
Swipe = false;
currentLocation = endLocation;
print("swipe ends");
}
}
and only set Swipe = true;
However, I would recommend using Coroutines instead of doing stuff in Update since they are better to control using StartCoroutine and StopCoroutine and passing the value you in you don't need the local variables currentLocation and endLocation.
It could look like
// Makes sure only one scrolling process is running at a time
private bool isScrolling;
private IEnumerator MoveTo(Vector3 targetPosition)
{
if (isScrolling) yield break;
isScrolling = true;
while (containerTransform.position != targetPosition)
{
containerTransform.position = Vector3.MoveTowards(containerTransform.position, endPosition, speed * Time.deltaTime);
yield return null;
}
isScrolling = false;
print("Swipe ends");
}
If you rather would like to swipe within a certain time regardless how far the distance is you could use Vector3.Lerp instead
public float swipeDuration;
private IEnumerator MoveTo(Vector3 targetPosition)
{
if (isScrolling) yield break;
isScrolling = true;
var currentPosition = containerTransform.position;
var timePassed = 0.0f;
while (timePassed < swipeDuration)
{
var lerpFactor = timePassed / swipeDuration;
containerTransform.position = Vector3.Lerp(currentPosition, endPosition, lerpFactor);
yield return null;
}
// To be sure set a fixed end position
containerTransform.position = endPosition;
isScrolling = false;
print("Swipe ends");
}
Adobt your code in SwipeCheck() to use the new coroutine.
StartCoroutine (MoveTo(endLocationWorldPoint));

Movement Bug stopping movement

Here is a video of the problem:
https://pbs.twimg.com/tweet_video/CPmbdpMWIAAUesX.mp4
The issue is whenever the ship flies in the direction of its shield, it seems to stop at regular intervals.
Here's the code for the ship and the shield:
public class MoveOnAxis : MonoBehaviour {
public float speed = 1.0f;
public float defaultDrag = 0.0f;
public float maxDrag = 3.0f;
public float maxAngularDrag = 3.0f;
public float maxTumble = 720;
public Transform shield;
private float distance;
private float hAxis;
private float deadzone = 0.15f;
private float aVel;
private Rigidbody2D rb;
// Use this for initialization
void Start ()
{
rb = GetComponent<Rigidbody2D>();
}
// Update is called once per frame
void Update ()
{
hAxis = Input.GetAxis("Horizontal");
aVel = rb.angularVelocity;
if(Mathf.Abs(hAxis) > 0.15f) //Controlls ship rotation
{
if(aVel > 10.0f) //if spinning out after a crash clockwise
{
if(aVel <= maxTumble && hAxis > deadzone)
{
rb.angularVelocity -= hAxis*speed*2;
}
else if(aVel < maxTumble && hAxis < -deadzone)
{
rb.angularVelocity -= hAxis*speed*2;
}
else if(aVel > maxTumble && hAxis < -deadzone)
{
rb.angularVelocity = maxTumble;
}
}
else if (aVel < -10.0f) //if spinning out of a crash anti-clockwise
{
if(aVel >= -maxTumble && hAxis < -deadzone)
{
rb.angularVelocity -= hAxis*speed*2;
}
else if(aVel > -maxTumble && hAxis > deadzone)
{
rb.angularVelocity -= hAxis*speed*2;
}
else if(aVel < -maxTumble && hAxis > deadzone)
{
rb.angularVelocity = -maxTumble;
}
}
else //if no physics angular momentum go back to using transform for rotation
{
rb.angularVelocity = 0;
transform.Rotate(0.0f, 0.0f, hAxis*-speed);
}
}
if(Input.GetAxis("triggerAxis") > 0.1f) //Controlls ship accelleration and decelleration
{
//distance = Mathf.Abs((transform.position - shield.position).magnitude);
//if (distance <= 1.0f && distance >= 0.6f)
//{
rb.AddForce(transform.up * speed * Input.GetAxis("triggerAxis"));
//}
//else if (distance < 0.6f || distance > 1.0f)
//{
// rb.velocity = new Vector2(0f,0f);
//}
}
if(Input.GetAxis("triggerAxis") < -0.1f)
{
rb.drag = maxDrag*-Input.GetAxis("triggerAxis");
rb.angularDrag = maxAngularDrag*-Input.GetAxis("triggerAxis");
}
else
{
rb.drag = defaultDrag;
rb.angularDrag = defaultDrag;
}
}
}
and
public class ShieldMovement : MonoBehaviour {
public Transform target; //player shield is attaced to
public float circSpeed = 0.1f; // Speed Shield moves around ship
private Vector3 direction = Vector3.up;
private float distance = 0.8f; // distance from player so it doesn't clip
private float deadzone = 0.15f;
private float separation;
private bool canMove = true;
private Rigidbody2D tRB;
private Rigidbody2D rb;
// Use this for initialization
void Start ()
{
tRB = target.GetComponent<Rigidbody2D>();
rb = GetComponent<Rigidbody2D>();
}
void OnCollisionEnter2D (Collision2D other)
{
canMove = false;
}
void OnCollisionStay2d(Collision2D other)
{
canMove = false;
}
void OnCollisionExit2D (Collision2D other)
{
canMove = true;
}
// Update is called once per frame
void Update () {
float rh = Input.GetAxisRaw("rightH");
float rv = Input.GetAxisRaw("rightV");
separation = Mathf.Abs((transform.position - target.position).magnitude);
if(Mathf.Abs(rh) > deadzone || Mathf.Abs(rv) > deadzone)
{
Vector3 targetDir = new Vector3(rh, rv, 0.0f);
direction = Vector3.Slerp(transform.position-target.position, targetDir, circSpeed);
}
Ray ray = new Ray(target.position, direction); // cast ray in direction of point on circle shield is to go
if(canMove)
{
transform.position = ray.GetPoint(distance); //move shield to the ray as far as the distance
}
else if(!canMove)
{
tRB.velocity = new Vector2(0.0f, 0.0f);
//rb.velocity = new Vector2(0.0f, 0.0f);
transform.position = transform.position;
}
if(separation != distance) //If the shield get torn away from the ship
{
transform.position = ray.GetPoint(distance); //move shield to the ray as far as the distance
}
float angleY = transform.position.y - target.position.y;
float angleX = -(transform.position.x - target.position.x);
float angle = Mathf.Atan2 (angleY, angleX) * Mathf.Rad2Deg-90; //Get angle
if(Mathf.Abs(rh) > deadzone || Mathf.Abs(rv) > deadzone)
{
transform.rotation = Quaternion.AngleAxis(angle,Vector3.forward*-1); // keep shield facing outwards in respect to player
}
}
}
I've tried taking out the stuff that stops moving the ship like tRB.velocity = new Vector2(0.0f, 0.0f); but it didn't make any difference at all. Any ideas on what I need to do here?
Edit
Removing the collider from the shield fixes the problem so it seems like somehow the shield is colliding with the ship even though it doesn't look like it and the raycast should keep it far enough away from the ship. Not sure where to go from here.
For physics system updates, it's best practice to put them in FixedUpdate() instead of Update(). The former can be used to change the velocity or add forces, and the latter can be used for getting the input from the user.
To prevent the ship and shield from colliding, use a different tag on each one, then compare the other.collider.tag to ignore those collisions.
// e.g. in ShieldMovement
void OnCollisionEnter2D (Collision2D other)
{
if (other.collider.tag != "Ship") {
canMove = false;
}
}
It seems the shield was colliding with the ship somehow, once I put them on separate non interacting layers the problem went away :D

Categories

Resources