I'm trying to add a bounce effect to an element of a game I'm making using C#. I can't seem to find the correct easing equation for this. Here's what I'm using for the time being:
t.position += (destination-t.position)*0.05f;
if((destination-t.position).magnitude <= 0.01f)
{
t.position = destination;
}
Can anyone help me with changing it to a bouncing equation?
if(setUpEase)
{
// Set the destination of each boardspace
if(!oneTime)
{
beginning = new Vector3(t.position.x, t.position.y, t.position.z);
destination = new Vector3(t.position.x, t.position.y-10, t.position.z);
change = new Vector3(0, -10, 0);
setUpDuration = Random.Range (1.0f, 3.0f);
oneTime = true;
}
// BOUNCING
currentTime += Time.deltaTime;
float t2 = currentTime/setUpDuration;
if(currentTime < setUpDuration)
{
if (t2 < (1/2.75f))
{
t.position = change*(7.5625f*t2*t2) + beginning;
}
else if (t2 < (2/2.75f))
{
t.position = change*(7.5625f*(t2-=(1.5f/2.75f))*t2 + 0.75f) + beginning;
}
else if (t2 < (2.5f/2.75f))
{
t.position = change*(7.5625f*(t2-=(2.25f/2.75f))*t2 + 0.9375f) + beginning;
}
else
{
t.position = change*(7.5625f*(t2-=(2.625f/2.75f))*t2 + 0.984375f) + beginning;
}
}
else
{
t.position = destination;
if(boardId < 113 && boardId > 92)
pie.setUpEase2 = true;
setUpEase=false;
}
}
Related
The code is a snippet of code from the torso but if you press 'f' on the torso it fires a laser. If the characters arm moves in front of the laser while it is firing it will get cut off, is there a way to fix this? PS: I'm not that good at coding. :P
laser.enabled = true;
for (int i = 0; i < iterations; i++)
{
var end = Physics2D.Raycast(BarrelPosition, BarrelDirection, 10000, bounds);
var endPos = end.transform == null ? (Vector3)BarrelPosition + (Vector3)BarrelDirection * 10000 : (Vector3)end.point;
var victimCount = Physics2D.LinecastNonAlloc(BarrelPosition, endPos, victimBuffer, layers);
laser.SetPosition(1, components.transform.InverseTransformPoint(endPos));
for (int n = 0; n < victimCount; n++)
{
var victim = victimBuffer[n];
victim.transform.SendMessage("Slice", SendMessageOptions.DontRequireReceiver);
// phys.rigidbody.AddForceAtPosition(forward * DirectionalForce * phys.rigidbody.mass, hit.point, ForceMode2D.Impulse);
}
CameraShakeBehaviour.main.Shake(1, transform.position);
physicalBehaviour.rigidbody.AddRelativeForce(new Vector2(0f * transform.localScale.normalized.x, 0), ForceMode2D.Impulse);
yield return new WaitForSeconds(interval);
}
laser.enabled = false;
yield return new WaitForSeconds(2f);
}
public override Vector2 BarrelPosition { get { return transform.TransformPoint(barrelPosition); } }
public Vector2 BarrelDirection { get { return transform.TransformDirection(barrelDirection) * transform.localScale.x; } }
I need help with trajectory prediction on mobile.
I'm able to do that on PC using the mouse, but I'm not able to do that with touch functions on mobile.
I've the dot that I copy on the start, and while I'm dragging the ball I want to calculate my trajectory.
After touch will end I will destroy these dots.
As I said I'm able to do it using Input.GetMouseButton/Up/Down but I'm not able to do that using touch function.
Here is my code:
private void Update()
{
//if (Input.touchCount > 0)
//{
Touch touch = Input.GetTouch(0);
if (touch.phase == TouchPhase.Began)
{
startPosition = Input.GetTouch(0).position;
for (int i = 0; i < number; i++)
{
trajectoryDots[i] = Instantiate(trajectoryDot, gameObject.transform);
}
}
if (Input.touchCount > 0)
{
for (int i = 0; i < number; i++)
{
trajectoryDots[i].transform.position = calculatePosition(i * 0.1f);
}
}
if (touch.phase == TouchPhase.Ended)
{
for (int i = 0; i < number; i++)
{
Destroy(trajectoryDots[i]);
}
endPoisiton = Input.GetTouch(0).position;
force = startPosition - endPoisiton;
ballRigid.gravityScale = 1;
ballRigid.velocity = new Vector2(force.x * power, force.y * power);
}
//}
}
private Vector2 calculatePosition(float elapsedTime)
{
return new Vector2(endPoisiton.x, endPoisiton.y) +
new Vector2(force.x * power, force.y * power) * elapsedTime +
0.5f * Physics2D.gravity * elapsedTime * elapsedTime;
}
The code I used for mouse input
if (Input.GetMouseButtonDown(0))
{ //click
startPos = gameObject.transform.position;
for (int i = 0; i < number; i++)
{
trajectoryDots[i] = Instantiate(trajectoryDot, gameObject.transform);
}
}
if (Input.GetMouseButton(0))
{ //drag
endPos = Camera.main.ScreenToWorldPoint(Input.mousePosition) + new Vector3(0, 0, 10);
gameObject.transform.position = endPos;
forceAtPlayer = endPos - startPos;
for (int i = 0; i < number; i++)
{
trajectoryDots[i].transform.position = calculatePosition(i * 0.1f);
}
}
if (Input.GetMouseButtonUp(0))
{ //leave
rigidbody.gravityScale = 1;
rigidbody.velocity = new Vector2(-forceAtPlayer.x * forceFactor, -forceAtPlayer.y * forceFactor);
for (int i = 0; i < number; i++)
{
Destroy(trajectoryDots[i]);
}
}
So after little changes it's much better, I' am getting closer to what i want there are still some glitches i guess because of touch.moved so when I' am on display with my finger and do only little moves ball is jumping on the screen
Here is the code
private void Update()
{
if (Input.touchCount > 0)
{
var touch = Input.GetTouch(0);
switch (touch.phase)
{
case TouchPhase.Began:
initPosition = gameObject.transform.position;
startPosition = cam.ScreenToWorldPoint(touch.position) + new Vector3(0, 0, 10);
for (int i = 0; i < number; i++)
{
trajectoryDots[i] = Instantiate(trajectoryDot, gameObject.transform);
trajectoryDots[i].transform.position = calculatePosition(i * 0.1f);
}
break;
case TouchPhase.Moved:
endPosition = Camera.main.ScreenToWorldPoint(touch.position) + new Vector3(0, 0, 10);
gameObject.transform.position = initPosition;
force = startPosition - endPosition;
for (int i = 0; i < number; i++)
{
trajectoryDots[i].transform.position = calculatePosition(i * 0.1f);
}
break;
case TouchPhase.Ended:
ballRigid.gravityScale = 1;
ballRigid.velocity = new Vector2(force.x * power, force.y * power);
for (int i = 0; i < number; i++)
{
Destroy(trajectoryDots[i]);
}
break;
}
}
}
private Vector2 calculatePosition(float elapsedTime)
{
return new Vector2(initPosition.x, initPosition.y) +
new Vector2(force.x * power, force.y * power) * elapsedTime +
0.5f * Physics2D.gravity * elapsedTime * elapsedTime;
}
Ok i have final soution and it's working correctly
private void Update()
{
if (Input.touchCount > 0)
{
var touch = Input.GetTouch(0);
switch (touch.phase)
{
case TouchPhase.Began:
initPosition = gameObject.transform.position;
startPosition = cam.ScreenToWorldPoint(touch.position) + new Vector3(0, 0, 10);
for (int i = 0; i < number; i++)
{
trajectoryDots[i] = Instantiate(trajectoryDot, gameObject.transform);
trajectoryDots[i].transform.position = calculatePosition(i * 0.1f);
}
break;
case TouchPhase.Ended:
ballRigid.gravityScale = 1;
ballRigid.velocity = new Vector2(force.x * power, force.y * power);
for (int i = 0; i < number; i++)
{
Destroy(trajectoryDots[i]);
}
break;
}
endPosition = Camera.main.ScreenToWorldPoint(touch.position) + new Vector3(0, 0, 10);
gameObject.transform.position = initPosition;
force = startPosition - endPosition;
for (int i = 0; i < number; i++)
{
trajectoryDots[i].transform.position = calculatePosition(i * 0.1f);
}
}
}
private Vector2 calculatePosition(float elapsedTime)
{
return new Vector2(initPosition.x, initPosition.y) +
new Vector2(force.x * power, force.y * power) * elapsedTime +
0.5f * Physics2D.gravity * elapsedTime * elapsedTime;
}
So just taking your mouse code and convert it to touch code it might look like
if(Input.touchCount > 0)
{
var touch = Input.GetTouch(0);
switch(touch.phase)
{
case TouchPhase.Began:
// Note: to be more accurate you actually probably would
// rather also here use ScreenToWorldPoint on the touch.position
// same way as later. Otherwise you might allways get a force even if touch wasn't moved at all
//startPos = transform.position;
startPos = Camera.main.ScreenToWorldPoint(touch.position) + new Vector3(0, 0, 10);
for (int i = 0; i < number; i++)
{
trajectoryDots[i] = Instantiate(trajectoryDot, gameObject.transform);
trajectoryDots[i].transform.position = calculatePosition(i * 0.1f);
}
break;
case TouchPhase.Moved:
// These were missing in your touch version
// You did it only in the end so there were no preview trajectory
// And note that also touch is in pixel screenspace so if you
// want to use world positions you need to convert them just the same as for mouse input!
endPos = Camera.main.ScreenToWorldPoint(touch.position) + new Vector3(0, 0, 10);
transform.position = endPos;
force = endPos - startPos;
for (int i = 0; i < number; i++)
{
trajectoryDots[i].transform.position = calculatePosition(i * 0.1f);
}
break;
case TouchPhase.Ended:
rigidbody.gravityScale = 1;
// Not sure why but in your mouse code you used a negative force here
// but in this case your trajectory would have been wrong since there you didn't use negative values...
rigidbody.velocity = force * forceFactor;
for (int i = 0; i < number; i++)
{
Destroy(trajectoryDots[i]);
}
break;
}
}
Btw the calculate method gets better to read like
private Vector2 calculatePosition(float elapsedTime)
{
return endPoisiton
+ force * power * elapsedTime
+ Physics2D.gravity * 0.5f * elapsedTime * elapsedTime;
}
Note: Typed on smartphone but I hope the idea gets clear
So, I'm generating a Vector2 using Unity's Random.Range, this is basically the x and y value of the direction the mobile should be moving.
m_CurrentMovementInput = new Vector2
(Random.Range(-0.75f, 0.75f), Random.Range(-0.75f, 0.75f));
The problem is the mobiles are only moving in diagonal angles. Which makes it seem like when it produces the random it's producing like..
(-0.35f, -0.35f) or (0.35f, -0.35f) or (-0.35f, 0.35f)
Which makes little sense to me as I understand the random function.
I'm sure I can get the desired behaviour by only changing one at a time, but I'd still like to understand its current behavior.
Edit: I believe this is all the relevant code. Sorry it took so long had to go get it from the repo.
void ProcessMovement()
{
ModifyComputerMovement(m_CurrentMovementInput.x, m_CurrentMovementInput.x);
}
float ModifyMovementInput(float input)
{
return input * m_MovementSpeedBase;
}
void RandomizeMovementInput()
{
m_CurrentMovementInput = new Vector2
(Random.Range(-0.75f, 0.75f), Random.Range(-0.75f, 0.75f));
if(RandomBoolean)
{
m_CurrentMovementInput += new Vector2
(Random.Range(-0.05f, 0.05f), Random.Range(-0.05f, 0.05f));
}
}
void ModifyComputerMovement(float x, float y)
{
m_VerticalInput = x;
m_HorizontalInput = y;
if ((m_VerticalInput == 0 && m_HorizontalInput == 0))
{
m_IsMoving = false;
}
else { m_IsMoving = true; }
UpdateCpuLocation();
}
bool m_ShouldRun;
bool m_ShouldSprint;
void UpdateCpuLocation()
{
if (!IsMoving())
m_CurrentMoveType = MovementType.None;
else
m_CurrentMoveType = MovementType.Walk;
m_DeltaVector = new Vector3
(
ModifyMovementInput(m_VerticalInput),
m_IsJumping ? ComputeJumpVelocity() : ApplyGravity(),
ModifyMovementInput(m_HorizontalInput)
);
m_GammaVector =
transform.forward * m_DeltaVector.x + transform.right * m_DeltaVector.z;
m_DeltaVector = new Vector3
(m_GammaVector.x, m_DeltaVector.y, m_GammaVector.z);
if (m_ShouldRun && IsMoving())
{
if (m_Controller.isGrounded)
{
m_CurrentMoveType = MovementType.Run;
m_DeltaVector *= m_RunSprintFactor;
if (m_ShouldSprint && IsMoving())
{
m_CurrentMoveType = MovementType.Sprint;
m_DeltaVector *= m_RunSprintFactor;
}
}
}
m_VectorShift = !m_Controller.isGrounded ?
(m_DeltaVector * Time.deltaTime) * m_JumpModifier : (m_DeltaVector * Time.deltaTime);
if (m_Controller.isGrounded)
m_VectorShift *= (m_PlayerState.GetCurrentEnergyLevelRatio());
m_VectorShift = new Vector3
(
m_VectorShift.x,
m_VectorShift.y,
m_VectorShift.z
);
#region Debug
//Debug.Log("Vector Shift: " + m_VectorShift);
//Debug.Log("Vector Shift Breakdown:");
/*Debug.Log
(String.Format
("VectorShift (X): {0} | VectorShift (Y): {1} | VectorShift (Z): {2}",
(double)m_VectorShift.x, (double)m_VectorShift.y, (double)m_VectorShift.z));*/
#endregion
if (m_PlayerState.GetCurrentEnergyLevelRatio() < m_MinimumEnergyThreshold)
m_VectorShift *= m_LowStamMoveModulus;
//m_MoveEventArg =
//new PlayerMoveActionEventArgs(m_VectorShift, GetCurrentMovementType);
if (m_IsMoving)
{
//EventDispatcher.InvokeMoveAction(m_MoveEventArg);
}
m_VectorShift = m_VectorShift * (Time.deltaTime * m_TimeWarpModifier);
m_Controller.Move(m_VectorShift);
}
Edit, Part II
So, the only thing that is really different is this:
void QueryPlayerInput()
{
m_VerticalInput = Input.GetAxis("Vertical");
m_HorizontalInput = Input.GetAxis("Horizontal");
if ((m_VerticalInput == 0 && m_HorizontalInput == 0))
{
m_IsMoving = false;
}
else { m_IsMoving = true; }
UpdatePlayerLocation();
}
I can't see a problem in code but in game if there is mirror anywhere in front of the beam it ignores all other objects
Please can anyone help me, why this is happening.
I can't ahre this because "It's all code and stuff".
public class LaserBeam : MonoBehaviour {
LineRenderer lr;
public bool isOpen = true;
Vector3 s;
void Start () {
lr = GetComponent<LineRenderer>();
}
void Update () {
s = new Vector3(transform.position.x, transform.position.y + (2 / 5f), transform.position.z);
lr.SetPosition(0, s);
lr.SetWidth(0.3f, 0.3f);
if (isOpen)
{
RaycastHit[] Hit = Physics.RaycastAll(s, transform.forward, 100.0F);
//Debug.Log("isOpen W");
if (Hit.Length > 0)
{
for (int x = 0; x < Hit.Length; x++)
{
Debug.Log(Hit[x].collider.tag + " ID: " + x);
if (Hit[x].collider.tag == "Mirror" || !Hit[x].collider.isTrigger)
{
Debug.DrawLine(s, Hit[x].point, Color.blue);
lr.SetPosition(1, Hit[x].point);
// Debug.Log("loop W" + x);
if (Hit[x].collider.tag == "Mirror") Reflect(s, Hit[x], 0);
else lr.SetVertexCount(2);
break;
}
else if (x == Hit.Length - 1)
{
lr.SetVertexCount(2);
Debug.DrawLine(s, transform.forward * Int16.MaxValue, Color.blue);
lr.SetPosition(1, transform.forward * Int16.MaxValue);
break;
}
}
}
else
{
lr.SetVertexCount(2);
Debug.DrawLine(s, transform.forward * Int16.MaxValue, Color.blue);
lr.SetPosition(1, transform.forward * Int16.MaxValue);
}
}
else
{
lr.SetVertexCount(2);
lr.SetPosition(1, s);
}
}
public void Reflect(Vector3 start, RaycastHit hit, int id)
{
lr.SetVertexCount(id + 3);
Vector3 p = Vector3.Reflect(hit.point - start, hit.normal);
Debug.DrawRay(hit.point, hit.normal * 3);
Debug.DrawLine(hit.point, p + hit.point, Color.blue);
RaycastHit[] Hit1 = Physics.RaycastAll(hit.point, p, 100.0F);
if (Hit1.Length > 0)
{
for (int x = 0; x < Hit1.Length; x++)
{
if (Hit1[x].collider.tag == "Mirror" || !Hit1[x].collider.isTrigger)
{
Debug.DrawLine(hit.point, Hit1[x].point, Color.blue);
//Debug.DrawLine(hit.point, Hit[x].point, Color.blue);
//lr.SetPosition(id + 1,(hit.point + start) / 2);
//lr.SetPosition(id + 2, hit.point);
lr.SetPosition(id + 2, Hit1[x].point);
if (Hit1[x].collider.tag == "Mirror")
{
Reflect(hit.point, Hit1[x], (id + 1));
return;
}
else lr.SetVertexCount(id + 3);
return;
}
else if (x == Hit1.Length - 1)
{
lr.SetVertexCount(id + 3);
Debug.DrawLine(hit.point, Vector3.Normalize(p) * Int16.MaxValue, Color.blue);
//lr.SetPosition(id + 1, (hit.point + start) / 2);
//lr.SetPosition(id + 2, hit.point);
lr.SetPosition(id + 2, Vector3.Normalize(p) * Int16.MaxValue);
return;
}
return;
}
}
else
{
lr.SetVertexCount(id + 3);
Debug.DrawLine(hit.point, Vector3.Normalize(p) * Int16.MaxValue, Color.blue);
//lr.SetPosition(id + 1, (hit.point + start) / 2);
//lr.SetPosition(id + 2, hit.point);
lr.SetPosition(id + 2, Vector3.Normalize(p) * Int16.MaxValue);
return;
}
// Debug.Log(id);
}
}
I can't see a problem in code but in game if there is mirror anywhere in front of the beam it ignores all other objects
Please can anyone help me, why this is happening.
I can't ahre this because "It's all code and stuff".
I don't think you can get away with layers in this case, but you DO NEED to know how to use them, anyways, this should work:
if (Hit.Length > 0)
{
float firstHitDistance = 100000f; //or something ridiculously high
RaycastHit firstHit;
for (int x = 0; x < Hit.Length; x++)
{
if(Hit[x].distance < firstHitDistance){
firstHitDistance = Hit[x].distance;
firstHit = Hit[x];
}
}
if (firstHit.collider.tag == "Mirror" || !firstHit.collider.isTrigger)
{
Debug.DrawLine(s, firstHit.point, Color.blue);
lr.SetPosition(1, firstHit.point);
// Debug.Log("loop W" + x);
if (firstHit.collider.tag == "Mirror") Reflect(s, , 0);
else lr.SetVertexCount(2);
break;
}
}
sorry for bad formatting, I'm on windows :/
I've been having some trouble applying correct velocity changes to my ball when it hits bricks in my Breakout clone. In a previous question, I was advised to use continuous collision detection, as well as other methods such as finding the intersection between the ball and the brick when it hits a corner to determine which direction the ball should reflect. I've applied this to my code below, but there are still occasions when the ball will just completely plow through a collection of bricks. This is more noticeable when it hits moving bricks.
In Level.cs Update method:
Bricks.ForEach(brick => Balls.ForEach(ball => ball.Collide(brick)));
In Ball.cs:
public bool Touching(Brick brick)
{
var position = Position + (Velocity * Speed);
return position.Y + Size.Y >= brick.Position.Y &&
position.Y <= brick.Position.Y + brick.Size.Y &&
position.X + Size.X >= brick.Position.X &&
position.X <= brick.Position.X + brick.Size.X && brick.Health > 0 && brick.Lifespan == 1F;
}
public void Collide(Brick brick)
{
if (!Touching(brick)) return;
var position = Position + (Velocity * Speed);
var bounds = new Rectangle((int)position.X, (int)position.Y, Texture.Width, Texture.Height);
var nonCCDBounds = new Rectangle((int)Position.X, (int)Position.Y, Texture.Width, Texture.Height);
if (bounds.Intersects(brick.Top) || bounds.Intersects(brick.Bottom))
{
var change = new Vector2(Velocity.X, -Velocity.Y);
if (bounds.Intersects(brick.Left) || bounds.Intersects(brick.Right))
{
var intersection = Rectangle.Intersect(bounds, brick.Texture.Bounds);
var nonCCDIntersection = Rectangle.Intersect(nonCCDBounds, brick.Texture.Bounds);
if (intersection.Width < intersection.Height || nonCCDIntersection.Width < nonCCDIntersection.Height){
change = new Vector2(-Velocity.X, Velocity.Y);
}
}
if (bounds.Intersects(brick.Top))
{
if (level.GetBrick(new Vector2(brick.GridPosition.X, brick.GridPosition.Y - 1)) != null)
change = new Vector2(-Velocity.X, Velocity.Y);
else if ((Position - Velocity).Y > brick.Position.Y)
change = new Vector2(-Velocity.X, Velocity.Y);
}
if (bounds.Intersects(brick.Bottom))
{
if (level.GetBrick(new Vector2(brick.GridPosition.X, brick.GridPosition.Y + 1)) != null)
change = new Vector2(-Velocity.X, Velocity.Y);
else if ((Position - Velocity).Y < brick.Position.Y + brick.Texture.Bounds.Height)
change = new Vector2(-Velocity.X, Velocity.Y);
}
ReflectBall(brick, change);
return;
}
if (bounds.Intersects(brick.Left) || bounds.Intersects(brick.Right))
{
var change = new Vector2(-Velocity.X, Velocity.Y);
if (bounds.Intersects(brick.Top) || bounds.Intersects(brick.Bottom))
{
var intersection = Rectangle.Intersect(bounds, brick.Texture.Bounds);
var nonCCDIntersection = Rectangle.Intersect(nonCCDBounds, brick.Texture.Bounds);
if (intersection.Width > intersection.Height || nonCCDIntersection.Width > nonCCDIntersection.Height)
{
change = new Vector2(Velocity.X, -Velocity.Y);
}
}
if (bounds.Intersects(brick.Left))
{
if (level.GetBrick(new Vector2(brick.GridPosition.X - 1, brick.GridPosition.Y)) != null)
change = new Vector2(Velocity.X, -Velocity.Y);
else if ((Position - Velocity).X > brick.Position.X)
change = new Vector2(Velocity.X, -Velocity.Y);
}
if (bounds.Intersects(brick.Right))
{
if (level.GetBrick(new Vector2(brick.GridPosition.X + 1, brick.GridPosition.Y)) != null)
change = new Vector2(Velocity.X, -Velocity.Y);
else if ((Position - Velocity).X < brick.Position.X + brick.Texture.Bounds.Width)
change = new Vector2(Velocity.X, -Velocity.Y);
}
ReflectBall(brick, change);
}
}
public void ReflectBall(Brick brick, Vector2 reflection)
{
Position = Position - Velocity;
Velocity = reflection;
if (brick.Health < 9)
{
brick.Health--;
brick.Life --;
}
if (brick.Health > 0 && brick.Life > 0)
{
brick.Texture = Assets.GetBrick(brick.TextureName, brick.Health);
}
}
It's a bit of a mess but it's the closest I've got to having decent collision. It would be much easier if there was a fast way of finding out collision points and applying correct velocity changes.