Character unable to dash NorthEast but can dash in other directions, including NorthWest - unity3d

I'm using the function below on a character controller to Dash in my 2d platformer. For some reason I can dash East, West, North, and NorthWest but not NorthEast, and I can't figure out the issue. I'm sure it's got to be an issue with my math equation used for DashDir but I'm not sure where I went wrong. Facing is simply an Enum holding -1 or 1. Any advice would be helpful - Ideally I'd actually like to be able to dash all 8 directions.
private IEnumerator Dash_Enter () {
dashCooldownTimer = DashCooldown;
Speed = Vector2.zero;
DashDir = Vector2.zero;
Vector2 value = new Vector2(moveX, moveY);
if (value == Vector2.zero) {
value = new Vector2 ((int)Facing, 0f);
} else if (value.x == 0 && value.y > 0 && onGround) {
value = new Vector2 ((int)Facing, value.y);
}
value.Normalize();
Vector2 vector = value * DashSpeed;
Speed = vector;
DashDir = value;
if (DashDir.x != 0f) {
Facing = (Facings)Mathf.Sign (DashDir.x);
}
if (DashDir.y < 0 && onGround) {
DashDir.y = 0;
DashDir.x = Mathf.Sign (DashDir.x);
Speed.y = 0f;
Speed.x *= 2f;
}
yield return new WaitForSeconds (DashTime);
// Wait one extra frame
yield return null;
if (DashDir.y >= 0f) {
Speed = DashDir * EndDashSpeed;
}
if (Speed.y > 0f) {
Speed.y = Speed.y * EndDashUpMult;
}
fsm.ChangeState (States.Normal, StateTransition.Overwrite);
yield break;
}

Related

Unity Game BreakOut ball loses speed and direction

I just finished a BreakOut style game but there is a bug where sometimes the ball gets stuck to the edges of the map with no direction or speed as shown in the screenshot
What I see is that it happens when the ball completely loses trajectory or speed, but could not solve the error
enter image description here
my code
public class Ball : MonoBehaviour
{
[SerializeField] Rigidbody2D rigidbody2D;
Vector2 moveDirection;
Vector2 currentVelocity;
float velocity=10;
//GameManager gameManager;
Transform paddle;
[SerializeField] AudioController audioController;
[SerializeField] AudioClip bounceSfx;
[SerializeField] AudioClip dieSfx;
public bool superBall;
[SerializeField] float superBallTime=10;
[SerializeField]float yMinSpeed = 10;
[SerializeField]TrailRenderer trailRenderer;
public bool SuperBall
{
get=> superBall;
set{
superBall=value;
if(superBall)
StartCoroutine(ResetSuperBall());
}
}
// Start is called before the first frame update
void Start()
{
//rigidbody2D = GetComponent<Rigidbody2D>();
//rigidbody2D.velocity = Vector2.up*velocity*Time.deltaTime;
GameManager.Instance = FindObjectOfType<GameManager>();
paddle = transform.parent;
}
// Update is called once per frame
void Update()
{
currentVelocity = rigidbody2D.velocity;
if (Mathf.Abs(currentVelocity.y) < 3 && Mathf.Abs(currentVelocity.y) < 3 && GameManager.Instance.ballOnGame)
{
velocity = 10;
rigidbody2D.velocity = Vector2.up * velocity ;
}
if (Mathf.Abs(currentVelocity.y) + Mathf.Abs(currentVelocity.y) < 10 && GameManager.Instance.ballOnGame)
{
velocity = 10;
rigidbody2D.velocity = Vector2.up * velocity ;
}
if (velocity <10 && GameManager.Instance.ballOnGame)
{
velocity = 10;
rigidbody2D.velocity = Vector2.up * velocity ;
}
if ((Input.GetKey(KeyCode.W) && GameManager.Instance.ballOnGame == false)||(Input.GetKey(KeyCode.Space) && GameManager.Instance.ballOnGame == false))
{
rigidbody2D.velocity = Vector2.up * velocity ;
transform.parent = null;
GameManager.Instance.ballOnGame = true;
rigidbody2D.isKinematic = false;
rigidbody2D.AddForce(new Vector3(velocity, velocity, 0));
if (!GameManager.Instance.GameStarted)
{
GameManager.Instance.GameStarted = true;
}
}
}
private void OnCollisionEnter2D(Collision2D collision)
{
if (collision.transform.CompareTag("Brick") && superBall)
{
rigidbody2D.velocity = currentVelocity;
return;
}
moveDirection=Vector2.Reflect(currentVelocity,collision.GetContact(0).normal);
if (Mathf.Abs(moveDirection.y) < yMinSpeed)
{
//permitir velocidad minima
moveDirection.y = yMinSpeed*Mathf.Sign(moveDirection.y);
}
rigidbody2D.velocity=moveDirection;
audioController.PlaySfx(bounceSfx);
if (collision.transform.CompareTag("BottomLimit"))
{
if(GameManager.Instance != null)
{
GameManager.Instance.PlayerLives--;
audioController.PlayDie(dieSfx);
if (GameManager.Instance.PlayerLives > 0)
{
rigidbody2D.velocity = Vector2.zero;
transform.SetParent(paddle);
transform.localPosition = new Vector2(0, 0.65f);
GameManager.Instance.ballOnGame = false;
}
}
}
}
IEnumerator ResetSuperBall()
{
trailRenderer.enabled = true;
yield return new WaitForSeconds(superBallTime);
trailRenderer.enabled = false;
GameManager.Instance.powerIsActive = false;
superBall = false;
}
}
This is a common issue with Rigidbodies at low velocities. The physics engine implements a Physics2D.velocityThreshold that is designed to dampen slow bounces and calm down a pile of Rigidbodies.
The default value for velocityThreshold is 1, meaning that the x or y component of the velocity that is slower will be floored to 0.
To resolve this issue you can simply lower the value to 0.001. You can do it in the Physcs2d tab located at Edit->ProjectSettings->Physics2d

Power of trajectory prediction Gold2d

I would like to add a force to my ball in my golf game, so if the player clicks the ball and holds a left mouse button, the power of the shot is growing, so is the trajectory. When the power reaches a maximum value the ball is shot immediately. I have a huge problem with it, and I'm stuck on it for a few days now. Maybe someone can help me? Code below:
internal Rigidbody2D ballRB;
internal Vector3 startPos = Vector3.zero;
int dotCount;
internal bool isClicked = false;
bool trajectoryVisible = false;
bool paraboleReachedEndOfScreen = true;
GameObject trajectoryDots;
GameObject ballClick;
//TrajectoryDots
List<Transform> dots = new List<Transform>();
//shot velocity
Vector2 shotForce = Vector2.zero;
public float startValShootingPower = 3f;
public float shootingPower = 3f;
float minBallPointerDist = 0.5f;
float dotSeparation = 10f;
float dotShift = 5f;
Transform lastDotTransform;
void Start()
{
startPos = transform.position;
startValShootingPower = shootingPower;
ballRB = GetComponent<Rigidbody2D>();
trajectoryDots = GameObject.Find("Trajectory Dots");
ballClick = transform.Find("Ball Click Area").gameObject;
dotCount = trajectoryDots.transform.childCount;
foreach (var dot in trajectoryDots.GetComponentsInChildren<Transform>())
{
dots.Add(dot);
}
dots.Remove(trajectoryDots.transform);
}
void Update()
{
foreach (var dot in dots)
{
if (dot.GetComponent<SpriteRenderer>().enabled)
{
lastDotTransform = dot;
}
}
paraboleReachedEndOfScreen = lastDotTransform.position.x <= -UsefulReferences.CameraViewFrustum.x / 2 || lastDotTransform.position.x >= UsefulReferences.CameraViewFrustum.x / 2;
ballClick.SetActive(!isClicked);
RaycastHit2D hit = Physics2D.Raycast(Camera.main.ScreenToWorldPoint(Input.mousePosition), Vector2.zero);
if (Input.GetButtonDown("Fire1"))
{
if (hit.collider != null)
{
//check if the mouse is hovering ball click area
if (hit.collider.transform.root.name == name)
{
trajectoryVisible = true;
}
}
}
if ((Input.GetButtonUp("Fire1") || (paraboleReachedEndOfScreen && Input.GetButton("Fire1"))) && !isClicked && trajectoryVisible) //player released the mouse button or the parabole reached the end of the screen
{
trajectoryVisible = false;
isClicked = true;
UsefulReferences.ballScript.ballRB.constraints = RigidbodyConstraints2D.FreezeRotation;
ballRB.velocity = shotForce;
foreach (var dot in dots)
dot.transform.position = Vector3.zero;
Invoke("GroundCheckAfterShot", 0.1f);
}
if (trajectoryVisible && !isClicked)
{
shotForce = (transform.position - Camera.main.ScreenToWorldPoint(Input.mousePosition)) * shootingPower;
for (int i = 0; i < dotCount; i++)
{
dots[i].gameObject.SetActive(true);
dots[i].transform.position = new Vector2(transform.position.x + shotForce.x * Time.fixedDeltaTime * (dotSeparation * i + dotShift),
transform.position.y + shotForce.y * Time.fixedDeltaTime * (dotSeparation * i + dotShift) - (-Physics2D.gravity.y / 2f * Time.fixedDeltaTime * Time.fixedDeltaTime * (dotSeparation * i + dotShift) * (dotSeparation * i + dotShift)));
}
}
else
{
foreach (var dot in dots)
{
dot.gameObject.SetActive(false);
}
}
//if the ball tried to fly out of the screen
if (transform.position.y > UsefulReferences.CameraViewFrustum.y / 2 || transform.position.x > UsefulReferences.CameraViewFrustum.x / 2 || transform.position.x < -UsefulReferences.CameraViewFrustum.x / 2)
{
OnCollisionEnter2D(null);
}
if (isClicked && UsefulReferences.ballScript.ballRB.constraints == RigidbodyConstraints2D.FreezeAll)
{
UsefulReferences.gcsScript.gameOver = true;
}
}
void OnTriggerEnter2D(Collider2D collision)
{
if (collision.tag == "Hole")
{
UsefulReferences.gcsScript.Score();
ballRB.constraints = RigidbodyConstraints2D.FreezeAll;
}
}
void OnCollisionEnter2D(Collision2D collision)
{
ballRB.constraints = RigidbodyConstraints2D.FreezeAll;
}
void GroundCheckAfterShot()
{
if (transform.position.y - startPos.y < 0.05f)
ballRB.constraints = RigidbodyConstraints2D.FreezeAll;
}
}

Snapped GO's Rotation not working properly

I'm currently trying to snap objects (cubes, pyramids, torus) together. I assigned each face of the objects bounding box a "snap allowed" variable and on collision try to find the closest two sides to each other. I then move the main object to the collision side and rotate it accordingly.
The code is as follows:
private static Vector3[] sides = {
Vector3.up,
Vector3.forward,
Vector3.right,
Vector3.down,
Vector3.back,
Vector3.left
};
private void Snap() {
if (!snappedObject)
return;
if (lastSnapping > LeftController.GetLastSnappingToggle()) {
//we dont calculate new sides, only use the old ones
//but we have to check whether we are now further away
float dis = Vector3.Distance(GetWorldPositionFace(this.gameObject, lastSelf),
GetWorldPositionFace(snappedObject, lastOther));
float max = Mathf.Max(Mathf.Abs(size.x), Mathf.Max(Mathf.Abs(size.y), Mathf.Abs(size.z)));
if (dis > max)
return;
ApplyToOther(lastSelf, lastOther, snappedObject);
} else {
//we need to find both new closest sides
MeshSnapping other = snappedObject.GetComponent<MeshSnapping>();
float otherDis = float.MaxValue;
int otherSide = -1;
//find the closest side from the other object
for (int i = 0; i < NUM_SIDES; i++) {
float dis = Vector3.Distance(transform.position, GetWorldPositionFace(snappedObject, i));
if (dis < otherDis && other.sidesAllowed[i]) {
otherDis = dis;
otherSide = i;
}
}
//find the closest side of our object
float selfDis = float.MaxValue;
int selfSide = 0;
for (int i = 0; i < NUM_SIDES; i++) {
float dis = Vector3.Distance(GetWorldPositionFace(this.gameObject, i),
GetWorldPositionFace(snappedObject, otherSide));
if (dis < selfDis && sidesAllowed[i]) {
selfDis = dis;
selfSide = i;
}
}
//are we to far away or at a prohibited side?
float max = Mathf.Max(Mathf.Abs(size.x), Mathf.Max(Mathf.Abs(size.y), Mathf.Abs(size.z)));
if (selfDis > max)
return;
ApplyToOther(selfSide, otherSide, snappedObject);
//save the sides for next iteration
lastSelf = selfSide;
lastOther = otherSide;
}
lastSnapping = Time.time;
}
private void OnCollisionEnter(Collision collision) {
snappedObject = collision.gameObject;
}
private void OnCollisionExit(Collision collision) {
snappedObject = null;
}
private Vector3 GetWorldPositionFace(GameObject other, int i) {
//get the side in local coordinates, scaled to size
Vector3 otherLocalSize = other.transform.localScale;
Vector3 otherSidePoint = new Vector3(otherLocalSize.x * sides[i].x, otherLocalSize.y * sides[i].y, otherLocalSize.z * sides[i].z) / 2f;
//rotate it according to world position
Vector3 dir = (other.transform.rotation * otherSidePoint);
//actually move it to world position
Vector3 center = other.transform.position + dir;
return center;
}
private void ApplyToOther(int selfI, int otherI, GameObject other) {
//first get the midpoint of face of other go
Vector3 edge = GetWorldPositionFace(other, otherI);
Vector3 dir = edge - other.transform.position;
RotateSides(selfI, otherI, dir);
selfI = (selfI + NUM_SIDES / 2) % NUM_SIDES;
//get midpoint of face of self go
edge += GetWorldPositionFace(this.gameObject, selfI) - transform.position;
//now move towards the combination
transform.position = edge;
}
private void RotateSides(int selfI, int otherI, Vector3 dir) {
//rotate self side towards this point
switch (selfI) {
case 0: transform.up = -dir; break;
case 1: transform.forward = -dir; break;
case 2: transform.right = -dir; break;
case 3: transform.up = dir; break;
case 4: transform.forward = dir; break;
case 5: transform.right = dir; break;
}
}
I can find every midpoint of the bounding box by transforming the direction vector, applying the objects current rotation and position to it (see GetWorldPositionFace() ). After finding the best combination, ApplyToOther() moves the objects to position and rotates it according to the selected face normals. So far so good, but the result is not aligned. As you can see, the front faces do not face in the same direction, i.e. I want to rotate the upper cube around the transform.up axis by this amount. This would be the result that I want.
But, if I add
float angle = Vector3.Angle(transform.forward, snappedObject.transform.forward);
transform.Rotate(transform.up, angle);
to the RotateSides() function, the result is this. The rotation axis is wrong.
Using
Quaternion.FromToRotation(transform.up, snappedObject.transform.up)
did not work either.
What did I miss? Thanks for your help!
I figured out my problem. By setting the transform.forward and the transform.up seperately (e.g. with transform.rotate around axis), only one of them was correct. Using Quaternion.LookRotation() solves this.

Unity3D bird flying back and forth

I'm trying to create a bird moving across screen along x axis.
bird.transform.position = Vector3.Lerp (pos1, pos2, (Mathf.Abs(speed * Time.time) + 1.0f) / 2.0f);
Using this in Update() the bird flies only once. I want that after it flies to the right, it should wait 2-3 seconds and then fly back with a different sprite.
transform.translate doesn't work like this. Any help will be appreciated.
you would need to put in another LERP for going the other direction and have a variable for which way the bird is flying so roughly:
bool goleft;
if(goleft)
{
if(transform.position != pos2)
{
transform.position = Vector3.Lerp (pos1, pos2, (Mathf.Abs(speed * Time.time) + 1.0f) / 2.0f);
}
else
{
goleft = false;
//change the direction the bird is facing here
}
}
else
{
if(transform.position != pos1)
{
transform.position = Vector3.Lerp (pos2, pos1, (Mathf.Abs(speed * Time.time) + 1.0f) / 2.0f);
}
else
{
goleft = true;
//change the direction the bird is facing here
}
}
Hope that helps
Not tested but i would start here:
Vector3[] posts;
int current = 0;
float speed = 5.0f;
float threshold = Single.Epsilon;
float delay = 2.0f;
public void Update() {
if(!waiting && posts.Length > 0)
{
if(!Mathf.Approximately((posts[current].position - transform.position).sqrMagnitude, threshold)
{
float step = speed * Time.deltaTime;
transform.position = Vector3.MoveTowards(transform.position, posts[current].position, step);
}
else StartCoroutine("Next");
}
}
IEnumerator Next() {
waiting = true;
yield return new WaitForSeconds(delay);
current = (current + 1) % posts.Length;
waiting = false;
}
This will also allow you to have as many posts as you want to have, and all your movement dynamics can be handled in Next(), whereas, if you want him to go from post 0...1...2...3...0...1.. or 0...1...2...3...2...1...
If you want the latter you just change current = (current + 1) % posts.Length; to Mathf.PingPong(current + 1, posts.Length);
I'd go a bit like this:
float flipCooldown
float defaultFlipCooldown = 2.0f;
bool isGoingRight;
Vector2 pos1;
Vector2 pos2;
void Start() {
flipCooldown = defaultFlipCooldown;
isGoingRight = true;
pos1 = new Vector2(0, 0);
pos2 = new Vector2(5, 0); // whatever floats your boat
}
void Update()
{
Vector2 initialPosition = null;
Vector2 finalPosition = null;
if (flipCooldown <= 0) {
isGoingRight = !isGoingRight
flipCooldown = defaultFlipCooldown;
ChangeSprite();
}
if (isGoingRight) {
initialPos = pos1;
finalPos = pos2;
} else {
initialPos = pos2;
finalPos = pos1;
}
bird.transform.position = Vector3.Lerp (initialPos, finalPos, (Mathf.Abs(speed * Time.time) + 1.0f) / 2.0f);
flipCooldown -= Time.deltaTime;
}
What you want to get is that the Time.deltaTime is decreasing the cooldown for the bird to turn. You can easily change the cooldown in the defaultFlipCooldown variable. When it's done going one way, it'll just flip the position and the Lerp function will do the rest of the work. The ChangeSprite function will be just a GetComponent<SpriteRenderer>().sprite change.
If you don't want fix positions, you can calculate how much it'll fly, define the final position and just change the pos1 and pos2.
It's also important to note that WaitForSeconds will just work with Coroutines that is a concept for working with threads, never in a method like Update. You can learn more about Coroutines in Unity's manual: http://docs.unity3d.com/Manual/Coroutines.html

In Unity Physics.gravity for x & z directions are not working in one script

I have one Sphere and I wanted to change gravity(in X & Z) according to Tilt(Input.acceleration). But its not working. For changing the gravity I am using the following code:
if((Input.acceleration.x) > 0)
{
Physics.gravity = new Vector3(9.81f, 0, 0);
}
if((Input.acceleration.x) < 0)
{
Physics.gravity = new Vector3(-9.81f, 0, 0);
}
and for Z:if((Input.acceleration.y) > 0)
{
Physics.gravity = new Vector3(0, 0, 9.81f);
}
if((Input.acceleration.y) < 0)
{
Physics.gravity = new Vector3(0, 0, -9.81f);
}
I m writting these code in FixedUpdate function.
Can anyone tell me where I m making mistake? I m new to unity as well.
If I understood correctly from the comments, your problem is that gravity is working, but only on one axis (x or z) at a time. In order to get gravity working simultaneously for more than one axis at a time, try the code bellow:
Vector3 newGravity = Physics.gravity;
if((Input.acceleration.x) > 0)
{
newGravity.x = 9.81f;
}
else if((Input.acceleration.x) < 0)
{
newGravity.x = -9.81f;
}
else
{
newGravity.x = 0;
}
if((Input.acceleration.y) > 0)
{
newGravity.y = 9.81f;
}
else if((Input.acceleration.y) < 0)
{
newGravity.y = -9.81f;
}
else
{
newGravity.y = 0;
}
if((Input.acceleration.z) > 0)
{
newGravity.z = 9.81f;
}
else if((Input.acceleration.z) < 0)
{
newGravity.z = -9.81f;
}
else
{
newGravity.z = 0;
}
Physics.gravity = newGravity;
However this will give the maximum gravity even for a small tilt. If you want the gravity to gradually grow depending on the angle of the tilt, you'll need to multiply 9.81f with a variable.
I take zero credit for this, in turn it was pulled from Unity iOS Example (linked in the forum post I linked) that does not appear to be up anymore:
public float force = 9.8f;
void FixedUpdate ()
{
Vector3 dir = new Vector3(Input.acceleration.x,0.0f,Input.acceleration.y);
Physics.gravity = dir * force;
}