- Home /
Moving 2D Object To New Position With Angle and Distance
I have a player object with a charge ability. What I'm trying to do, is when I use my charge ability, I want to move to that new position in a straight line over time. Maybe this has already been answered, but every answer I found only provided and answer to basically "teleport" your player object to the new position. I don't want to move to my new position immediately, I want to travel over time like. Similiar to:
Barbarian in Diablo 3
Magnus in Dota 2
Here is how my charge ability works. I am tracking the position of the analog (from a controller) or mouse position to capture the current angles. When the ability button is pressed, it calls UseAbility. Then I start a Coroutine, and use an IEnumerator to iterate my position to the newPosition.
Here is my Charge ability
public override void UseAbility(GameObject player)
{
abilityCooldownTimer = new Stopwatch();
abilityCooldownTimer.Start();
StartCoroutine(ChargeUpdate(player));
}
public IEnumerator ChargeUpdate(GameObject player)
{
// Capture DirectionIndicator for proper angle
GameObject directionIndicator = GameObject.Find("DirectionIndicator");
float angle = directionIndicator.transform.eulerAngles.z;
// Calculate the distance we need to travel on x and y
Vector3 distanceToTravel = new Vector3(baseEffectDistance * Mathf.Cos(angle * Mathf.PI / 180), baseEffectDistance * Mathf.Sin(angle * Mathf.PI / 180), 0);
Vector3 newPosition = new Vector3(player.transform.localPosition.x + distanceToTravel.x, player.transform.localPosition.y + distanceToTravel.y, 0);
Vector2 input;
player.GetComponent<Player>().canMove = false;
isCharging = true;
collidedWithObject = false;
// Wait .4 second to "prepare" our charge ability
yield return new WaitForSeconds(baseEffectPreparation);
while (abilityCooldownTimer.IsRunning && newPosition != player.transform.localPosition && isCharging)
{
// TODO: fix this, for some reason our x and y position can't make it to the final points. We are always .1 or .2 off.
// Making a check to see if we are .5 off, if so then we will say our charge is complete
float safeCheckDistance = .5f;
if (collidedWithObject ||
((newPosition.x - player.transform.localPosition.x <= safeCheckDistance && newPosition.x - player.transform.localPosition.x >= -safeCheckDistance) &&
(newPosition.y - player.transform.localPosition.y <= safeCheckDistance && newPosition.y - player.transform.localPosition.y >= -safeCheckDistance)))
{
isCharging = false;
}
// Determine X Direction to Move
if (newPosition.x - player.transform.localPosition.x == 0 ||
(newPosition.x - player.transform.localPosition.x <= safeCheckDistance && newPosition.x - player.transform.localPosition.x >= -safeCheckDistance))
input.x = 0;
else if (newPosition.x - player.transform.localPosition.x > 0)
input.x = 1;
else
input.x = -1;
// Determine Y Direction to Move
if (newPosition.y - player.transform.localPosition.y == 0 ||
(newPosition.y - player.transform.localPosition.y <= safeCheckDistance && newPosition.y - player.transform.localPosition.y >= -safeCheckDistance))
input.y = 0;
else if (newPosition.y - player.transform.localPosition.y > 0)
input.y = 1;
else
input.y = -1;
player.GetComponent<Player>().UpdateMotor(input, baseEffectSpeed, baseEffectSpeed);
yield return null;
}
player.GetComponent<Player>().canMove = true;
abilityCooldownTimer.Stop();
abilityCooldownTimer.Reset();
yield return null;
}
And here is my UpdateMotor function
public virtual void UpdateMotor(Vector2 input, float motorXSpeed, float motorYSpeed)
{
// Reset MoveDelta
moveDelta = new Vector2(input.x * motorXSpeed, input.y * motorYSpeed);
// Move on y axis based on moveDelta
transform.Translate(0, moveDelta.y * Time.deltaTime, 0);
myAnimator.SetFloat("yspeed", moveDelta.y);
// Move on x axis based on moveDelta
transform.Translate(moveDelta.x * Time.deltaTime, 0, 0);
myAnimator.SetFloat("xspeed", moveDelta.x);
}
Two points to mention: 1. You'll notice the first thing in my while loop, I have a TODO. My UpdateMotor function for some reason doesn't move my character smoothly and accurately to the new position. I'm always .5 to 1.5-ish away from my final position. Meaning, when I call my UpdateMotor, and my final position is (3.5, 4.3), I'll get really close to 3.5 on the x axis, but will never get exactly (to the tenth decimal, obviously don't need to be float accurate). This is the same for the y-axis. 2. My UpdateMotor function works, and gets me to my location, but as you'll see in the image below, I travel to my x and y position at the same speeds. This is a problem, because when I have reached the x or y position I stop traveling on that axis. This gives an awkward movement to the player and looks funny.
With all of this, I'm trying to figure out: 1. Given an angle, how can I move my player object to the new position over time 2. Additionally, having the player move to the exact position (since I know my new x,y position)
Thank you all in advance for any help you can provide.
If i get it right you want to point a direction with a controller or sth and move your player to new position according to new direction and your baseEffectDistance in given time. So this is what you can do:
void Update () {
if (Input.Get$$anonymous$$eyDown($$anonymous$$eyCode.Space)) { //this is just for testing. You could modify it as your needs
StartCoroutine($$anonymous$$oveToPosition(1f));
}
}
public Vector3 GetDirection(Vector3 relative, Vector3 reference) {
var heading = relative - reference;
var direction = heading.normalized;
return direction;
}
public IEnumerator $$anonymous$$oveToPosition(float timeTo$$anonymous$$ove) {
//this is where you want to do your preparations
yield return new WaitForSeconds(baseEffectPreparation);
var t = 0f;
var target = GetDirection(relative.transform.position, transform.position);
var initialPos = transform.position;
while (t < 1) {
t += Time.deltaTime / timeTo$$anonymous$$ove;
transform.position = Vector3.Lerp(transform.position,
initialPos + target * baseEffectDistance, t);
yield return null;
}
//this line ensures that to get exactly the target position
transform.position = initialPos + target * baseEffectDistance;
}
Here is some walkthrough: In GetDirection method reference is the position you pointed to move your player and relative is your players positon. I tested script before posting and it works as expected (at least what i understood from your question). Hope this helps.
Thanks for answering.
I don't want to charge based on time (like what you have in your while). I want to charge until I reach my new position (which is based on the angle and the variable baseEffectDistance). This way I can reuse the charge ability, and the total distance to travel will be deter$$anonymous$$ed by baseEffectDistance.
Additionally, the speed it takes to travel to that distance will be based on the variable baseEffectSpeed. So this will either make us charge really quickly, or it might be a slower charge. But time itself is not a part of the movement.
Is there anyway I can charge, and move to my new position without time? $$anonymous$$y Update$$anonymous$$otor function is currently what I'm using to actually move my player using WASD on keyboard, and analog with controller. This works fine to move, but as I mentioned using my image, its not ideal because it will look weird.
Edit 1: I do have checks to see if I need to stop charging, which is why I have the variable isCharging. I have a few checks that say "if this happens, isCharging = false". All that works, I just want a better way to charge in a straight line to my new position.
Time can't be the only way to make this work, right?
Ofc not. But i cant say i got what you want to achieve completely. Is there a sample video, gif or sth. to visualize it?
Your answer
Follow this Question
Related Questions
Making a bubble level (not a game but work tool) 1 Answer
Multiple Cars not working 1 Answer
2D game with two point perspective and distortion? 1 Answer
Sprite will not roate when arrow keys are pressed 2 Answers
Distribute terrain in zones 3 Answers