C# Vector2 How to move an object toward an angle - c#

I want to move an object to the given angle, But it moves only up, and down, only Y axis.
Vector2 unitV = new Vector2((float)Math.Sin(player.angle), (float)Math.Cos(player.angle));
unitV.Normalize();
player.model.Position += Vector2.Multiply(unitV,player.model.Speed) * (float)gameTime.ElapsedGameTime.TotalSeconds;

I just met this problem while practicing, but here is the solution i found. I hope this will work for you. Used XNA 4 C sharp.
Declaration:
Texture2D sprite;
Vector2 spritePosition = Vector2.Zero;
Vector2 spriteOriginalPos;
float spriterotation = 0;
float anglecorrection = (Math.PI * 90 / 180.0);
float speed = 1;
Note that the anglecorrection is needed to move the object toward its "up" angle.
Load:
//Load basic texture to make it recognizable :)
sprite= Content.Load<Texture2D>("spritetexture");
//Default position in middle
spritePosition = new Vector2(
(graphics.GraphicsDevice.Viewport.Width / 2) - (sprite.Width / 2),
(graphics.GraphicsDevice.Viewport.Height / 2) - (sprite.Height / 2));
//Sprite centering
spriteOriginalPos.X = sprite.Width / 2;
spriteOriginalPos.Y = sprite.Height / 2;
Update:
if (Keyboard.GetState(PlayerIndex.One).IsKeyDown(Keys.Up))
{
spritePosition.X += speed * (float)Math.Cos(spriterotation - anglecorrection);
spritePosition.Y += speed * (float)Math.Sin(spriterotation - anglecorrection);
}
Draw:
spriteBatch.Draw(sprite, spritePosition, null, Color.Black, spriterotation, spriteOriginalPos, 1.0f, SpriteEffects.None, 0f);

Related

C# OpenTK mouse picking incorrect?

This is my code of generate a ray
float x = (2.0f * e.X) / Width - 1f;
float y = (1.0f - (2.0f * e.Y) / Height);
float z = 1.0f;
Vector3 ray_nds = new Vector3(x, y, z);
Vector4 ray_clip = new Vector4(ray_nds.X, ray_nds.Y, -1.0f, 1.0f);
Vector4 ray_eye = Matrix4.Invert(Projection) * ray_clip;
ray_eye = new Vector4(ray_eye.X, ray_eye.Y, -1.0f, 0.0f);
Vector3 ray_wor = (Matrix4.Invert(View) * ray_eye).Xyz;
ray_wor = Vector3.Normalize(ray_wor);
ray.Origin = CameraPosition;
ray.Direction = ray_wor;
And I draw the ray into the scene.
When I look at -Z axis, it working perfect like this (I click plane center)
But when my camera front is not -Z axis or +Z axis
ray's direction was incorect like this (I click plane center)
I have no idea what's wrong with it for a week
Can anyone help me ?
If you need other info of my code, please tell me, thank you :)
Update 1:
This is my view :
public Matrix4 View { get => Matrix4.LookAt(CameraPosition, CameraPosition + CameraFront, CameraUp); }
and this is my rotate code :
(rotate the scene is change camera position and look to view center actually)
lookX += (lastMouseLoc.X - e.X) * RotateSensitive;
lookY += (e.Y - lastMouseLoc.Y) * RotateSensitive;
lookY = Math.Max(lookY, -MathHelper.DegreesToRadians(89));
lookY = Math.Min(lookY, MathHelper.DegreesToRadians(89));
Vector3 v = new Vector3((float)Math.Sin(lookX) * (float)Math.Cos(lookY), (float)Math.Sin(lookY), (float)Math.Cos(lookX) * (float)Math.Cos(lookY));
CameraPosition = ViewCenter + v * lastDistOfCenter;
CameraFront = Vector3.Normalize(ViewCenter - CameraPosition);
lastMouseLoc = e.Location;
You forgot the z-coordinate after converting from the normalized device space to the viewing space:
ray_eye = new Vector4(ray_eye.X, ray_eye.Y, -1.0f, 0.0f);
ray_eye = new Vector4(ray_eye.X, ray_eye.Y, ray_eye.Z, 0.0f);

Instantiate in circle objects look to center

A little bit confused - math is really not my strong point, so I'm not sure how to achieve.
Currently the objects instantiate, but I have no control over the distance from center or the rotation of each spawned object
public void instantiateInCircle()
{
for (int i = 0; i < amount; i++)
{
float radius = spawnDistance;
float angle = i * Mathf.PI * 2f / radius;
Vector3 newPos = transform.position + (new Vector3(Mathf.Cos(angle) * radius, spawnHeight, Mathf.Sin(angle) * radius ));
//Rotate objects to look at the center
GameObject instantiatedObject = Instantiate(itemToSpawn, newPos, Quaternion.Euler(0, 0, 0));
instantiatedObject.transform.LookAt(spawnAroundThis.transform);
//How to adjust the width of the radius, how far away from the center?
//Parent instantiated objects to disk
instantiatedObject.transform.parent = spawnAroundThis.transform;
instantiatedObject.transform.localScale = new Vector3(scale, scale, scale);
}
}
How to make the distance adjustable, move cubes in closer to center...?
Currently, you do not access the instantiated object, but the prefab instead. Cache the object and call the LookAt on them.
Since I do not know what type itemToSpawn is, I assumed it is a GameObject. You may want to use your type instead.
GameObject instantiatedObject = Instantiate(itemToSpawn, newPos, Quaternion.Euler(0, 0, 0));
instantiatedObject.transform.LookAt(spawnAroundThis.transform);
If you want to control the distance from center of the rotation:
for (int i = 0; i < amount; i++)
{
float radius = spawnDistance;
float angle = i * Mathf.PI * 2f / (float)amount; // divide by amount, NOT radius
// manipulate radius here as you want
Vector3 newPos = transform.position + (new Vector3(Mathf.Cos(angle) * radius, spawnHeight, Mathf.Sin(angle) * radius ));
...
}

Unity rigid object receives twice the force it is supposed to receive

I am making a game where bullets can start orbiting a player. The orbits are circular, and not elliptical. Bullets have a drag factor of 0.
At first, I simply calculated the next position in the orbit, and divided the delta position by fixedDeltaTime to obtain its new velocity.
Unfortunately, it meant that fast bullets instead follow polygonal paths, and often miss a target.
I wanted to improve the precision by giving them an inward force, and a velocity nearly tangential to the orbit, so that they follow parabola segments around the player instead of straight lines.
The parabola segments are defined by their start and end point, and their vertices, which must lay on the orbit arc, with a velocity equal to the velocity I was previous using ((endpos - startpos) / fixedDeltaTime).
To calculate the parabola, I calculate the midway points on the arc and segment, and their difference is proportional to the force applied.
so we use the following names
fdt = fixedDeltaTime
t = fdt / 2
f = the force applied during the incoming physics frame
v0 = the velocity at the start of the frame
v1 = the velocity at the middle of the frame (at the vertex of the parabola)
dp1 = the relative position at the middle of the frame (midpos - startpos) and vertex of the parabola
dp2 = the relative position at the end of the frame (endpos - startpos)
The force is defined by these two equations:
// at vertex, only the "lateral" velocity remains
v1 = dp2 / fdt
// the difference between dp2 / 2 and dp1 is what the force can apply over half a frame
dp2 / 2 - dp1 = f * 0.5tt
therefore
(dp2 / 2 - dp1) / (0.5 * t * t) = f
(dp2 / 2 - dp1) / (0.5 * fdt/2 * fdt/2) = f
(dp2 - dp1 * 2) * 4 / (fdt * fdt) = f
//v0 is then easily calculated
v0 = v1 - t * force
v0 = (dp2 / fdt) - force * (fdt / 2)
We then get this working code:
Vector3 startPos = _rigidbody.position;
if (firstFrame == false && Vector3.Distance(predictedNextFramePos, startPos) > 0.01f)
Debug.Log("WTF");
Vector3 nextPosition;
GetLocalOrbitPos(nextTime, out nextPosition);
nextPosition += _parent.GetPosition();
float fdt = Time.fixedDeltaTime;
float halfTime = (time + nextTime) / 2f;
Vector3 halfPosition;
GetLocalOrbitPos(halfTime, out halfPosition);
halfPosition += _parent.GetPosition();
Vector3 dp2 = nextPosition - startPos;
Vector3 dp1 = halfPosition - startPos;
Vector3 force = (dp2 - 2 * dp1) * 4 / (fdt * fdt);
Vector3 v0 = (dp2 / fdt) - (force * fdt / 2f);
Vector3 deltaPosPredicted = PhysicsTools.GetMovement(v0, force, fdt);
if (Vector3.Distance(deltaPosPredicted, dp2) > 0.001f)
Debug.Log("position prediction error: " + Vector3.Distance(deltaPosPredicted, dp2));
predictedNextFramePos = deltaPosPredicted + startPos;
Vector3 deltaHPosPredicted = PhysicsTools.GetMovement(v0, force, fdt / 2f);
if (Vector3.Distance(deltaHPosPredicted, dp1) > 0.001f)
Debug.Log("position prediction error: " + Vector3.Distance(deltaHPosPredicted, dp1));
//drawing the startpos, midpos, endpos triangle
Debug.DrawLine(startPos, startPos + dp2, Color.magenta, Time.fixedDeltaTime * 2);
Debug.DrawLine(startPos, startPos + dp1, Color.red, Time.fixedDeltaTime * 2);
Debug.DrawLine(startPos + dp2, startPos + dp1, Color.red, Time.fixedDeltaTime * 2);
//drawing v0 and force
Debug.DrawLine(startPos, startPos + force, Color.gray, Time.fixedDeltaTime * 2);
Debug.DrawLine(startPos, startPos + v0, Color.blue, Time.fixedDeltaTime * 2);
//drawing the parabola arc
{
Vector3 pos = startPos;
Vector3 vel = v0;
for (int i = 0; i < 10; i++)
{
Vector3 offset = PhysicsTools.GetMovementUpdateVelocity(ref vel, force, Time.fixedDeltaTime / 10f);
Debug.DrawLine(pos, pos + offset, Color.green, Time.fixedDeltaTime * 2);
pos += offset;
}
}
// Old version
// Vector3 deltaPosition = nextPosition - _rigidbody.position;
// Vector3 velocity = deltaPosition / t;
// SetPhysicsState(_rigidbody.position, velocity, time);
//Applying results
SetPhysicsState(startPos, v0, time);
_rigidbody.AddForce(force / 2f, ForceMode.Acceleration);
I am using my physics helper class
public static class PhysicsTools
{
public static Vector3 GetMovement(Vector3 velocity, Vector3 force, float time)
{
return (velocity * time) + 0.5f * force * (time * time);
}
public static Vector3 GetMovementUpdateVelocity(ref Vector3 velocity, Vector3 force, float time)
{
Vector3 ret = (velocity * time) + 0.5f * force * (time * time);
velocity += force * time;
return ret;
}
}
Everything works fine, but if, and only if, I divide the force by two when applying it. My own simulation using PhysicsTools does not require such tampering.
Here's a picture of one of my tests, with the force factor applied to both the physics engine and the PhysicsTools simulation. You can see that the simulated lines go off into the distance, but not the actual projectile, which stays in its weird pentagram, as it should.
Here we can see it working as intended (still with the applied force reduced)
My question, why would I need to divide that damned force by two?
Well here folks is what happen when you make assumptions.
I assumed that ForceMode.Continuous meant that the force would be applied continuously through the frame. That is not the case.
The unity physics engine is incapable of any kind of continuous acceleration or parabola casting. Any object moves in straight lines, and AddForce simply modifies the velocity right then and there.
It turns out that simply dividing the force by two was enough to reset the starting velocity to my previous linear solution to the problem, and that the only reason that objects seemed to react outside of the polygon was that my bullet collider was much wider than I thought it was.
Please read this post for more information: https://answers.unity.com/questions/696068/difference-between-forcemodeforceaccelerationimpul.html
The only solution to the problem is to increase the physics framerate, or to use your own raycasting solution, which comes with a slew of other problems.

Player is not moving toward target without unity built in functions

I am trying to move my target object towards my player using custom codes(without built-in function of unity like MoveTowards)
Vector3 displacment = target.transform.position - player.transform.position;
//you can also get magnitude directly through displacement.magnitude
float xMagnitude = displacment.x * displacment.x;
float yMagnitude = displacment.y * displacment.y;
float zMagnitude = displacment.z * displacment.z;
float customMagnitude =Mathf.Sqrt(xMagnitude + yMagnitude + zMagnitude);
directionToMove = new Vector3(displacment.x / customMagnitude, displacment.y / customMagnitude, displacment.z / customMagnitude);
//directionToMove = displacment.normalized;
Vector3 velocity = directionToMove * speed;
Vector3 moveAmount = velocity * Time.deltaTime;
target.transform.position += moveAmount;
I first got the displacement between two vectors than i get its direction and pass it to my position with speed. but its direction is not towards the player. what i am doing wrong?
If you want to move your target towards the player, the displacment must be :
displacment = player.transform.position - target.transform.position;
To generate a vector given the initial point : A (x1, y1, z1) and final point B (x2, y2, z2) the calculation is the following :
v = B - A = (x2 - x1, y2 - y1, z2 - z1);
So let me get this straight: You want to move the target towards the player, not the player towards the target. Is this correct?
If you want to move the target object towards the player, then the displacement should be player.transform.position - target.transform.position, not the other way around.
If you really don't want to use the Unity functions, then here's how I would do your code:
Vector3 displacment = player.transform.position - target.transform.position;
float xMagnitude = displacment.x * displacment.x;
float yMagnitude = displacment.y * displacment.y;
float zMagnitude = displacment.z * displacment.z;
float customMagnitude =Mathf.Sqrt(xMagnitude + yMagnitude + zMagnitude);
//multiplying vector by scalar works the same,
//and is more readable (possibly faster too)
directionToMove = displacement * 1f/customMagnitude;
Vector3 velocity = directionToMove * speed;
Vector3 moveAmount = velocity * Time.deltaTime;
target.transform.position += moveAmount;

Updating the Y position aswell as the X position of the 2D camera

I'm trying to make a 2D camera that follows my player around both vertically and horizontally. The camera is only following my player horizontally atm. Ive been told to update the Y part aswell as the X part in my ScrollCamera() method, but I couldnt figure out how to do it (ended up making a big mess).
Heres the code:
private void ScrollCamera(Viewport viewport)
{
#if ZUNE
const float ViewMargin = 0.45f;
#else
const float ViewMargin = 0.5f;
#endif
// Calculate the edges of the screen.
float marginWidth = viewport.Width * ViewMargin;
float marginLeft = cameraPosition + marginWidth;
float marginRight = cameraPosition + viewport.Width - marginWidth;
// Calculate how far to scroll when the player is near the edges of the screen.
float cameraMovement = 0.0f;
if (Player.Position.X < marginLeft)
cameraMovement = Player.Position.X - marginLeft;
else if (Player.Position.X > marginRight)
cameraMovement = Player.Position.X - marginRight;
// Update the camera position, but prevent scrolling off the ends of the level.
float maxCameraPositionWidth = Tile.Width * Width - viewport.Width;
cameraPosition = MathHelper.Clamp(cameraPosition + cameraMovement, 0.0f, maxCameraPositionWidth);
}
This is the draw method in my level class:
public void Draw(GameTime gameTime, SpriteBatch spriteBatch)
{
spriteBatch.Begin();
for (int i = 0; i <= EntityLayer; ++i)
layers[i].Draw(spriteBatch, cameraPosition);
spriteBatch.End();
ScrollCamera(spriteBatch.GraphicsDevice.Viewport);
Matrix cameraTransform = Matrix.CreateTranslation(-cameraPosition, 0.0f, 0.0f);
spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend, SamplerState.LinearClamp, DepthStencilState.Default,
RasterizerState.CullCounterClockwise, null, cameraTransform);
DrawTiles(spriteBatch);
Player.Draw(gameTime, spriteBatch);
foreach (Enemy enemy in enemies)
enemy.Draw(gameTime, spriteBatch);
spriteBatch.End();
spriteBatch.Begin();
for (int i = EntityLayer + 1; i < layers.Length; ++i)
layers[i].Draw(spriteBatch, cameraPosition);
spriteBatch.End();
}
I'm pretty new to Xna and C# and Im doing this just for fun, but it would be great if someone could tell me how to do it :)
I have tried:
private void ScrollCamera(Viewport viewport)
{
#if ZUNE
const float ViewMargin = 0.45f;
#else
const float ViewMargin = 0.5f;
const float ViewHeight = 0.3f;
#endif
// Calculate the edges of the screen.
float marginHeight = viewport.Height * ViewHeight;
float marginTop = cameraPosition + marginHeight;
float marginBottom = cameraPosition + marginHeight;
float marginWidth = viewport.Width * ViewMargin;
float marginLeft = cameraPosition + marginWidth;
float marginRight = cameraPosition + viewport.Width - marginWidth;
// Calculate how far to scroll when the player is near the edges of the screen.
float cameraMovement = 0.0f;
if (Player.Position.X < marginLeft)
cameraMovement = Player.Position.X - marginLeft;
else if (Player.Position.X > marginRight)
cameraMovement = Player.Position.X - marginRight;
if (Player.Position.Y < marginTop)
cameraMovement = Player.Position.Y - marginTop;
else if (Player.Position.Y > marginBottom)
cameraMovement = Player.Position.X - marginBottom;
// Update the camera position, but prevent scrolling off the ends of the level.
float maxCameraPositionWidth = Tile.Width * Width - viewport.Width;
cameraPosition = MathHelper.Clamp(cameraPosition + cameraMovement, 0.0f, maxCameraPositionWidth);
}
Which was not right at all.
From the code you provided I conclude 'cameraPosition' is a float with which you only keep track of the X position. I would recommend using a Vector2 for this. This is technically two floats in one; one for the X position and one for Y. If you do this, you will have to repeat your calculation for the Y value. If you prefer not to use a Vector2, you could make a second variable for the Y position instead.
I am unable to see what you do with the cameraPosition, so I cannot help you with that part for Y.
Edit
The draw function you have made is not right, because you have only one variable for the camera position. You will need a variable for the X position, and a second one for the Y position. As I stated above, the typical way to do this in XNA, is via the Vector2 structure. If you are not familiar with structures(or classes), I recommend reading up about it as soon as possible, because they are very important in object oriented programming. A link to the microsoft Vector2 documentation: http://msdn.microsoft.com/en-us/library/microsoft.xna.framework.vector2.aspx
What you would basically do is take the calculation you had at first.
float cameraMovement = 0.0f;
if (Player.Position.X < marginLeft)
cameraMovement = Player.Position.X - marginLeft;
else if (Player.Position.X > marginRight)
cameraMovement = Player.Position.X - marginRight;
// Update the camera position, but prevent scrolling off the ends of the level.
float maxCameraPositionWidth = Tile.Width * Width - viewport.Width;
cameraPosition = MathHelper.Clamp(cameraPosition + cameraMovement, 0.0f, maxCameraPositionWidth);
This is the calculation for the X position of your camera. Your code using Vector2 would be:
// Declare a Vector2 cameraPosition where you are now declaring a float cameraPosition right now.
Vector2 cameraMovement = new Vector2(0,0);
if (Player.Position.X < marginLeft)
cameraMovement.X = Player.Position.X - marginLeft;
else if (Player.Position.X > marginRight)
cameraMovement.X = Player.Position.X - marginRight;
float maxCameraPositionWidth = Tile.Width * Width - viewport.Width;
cameraPosition.X = MathHelper.Clamp(cameraPosition.X + cameraMovement.X, 0.0f, maxCameraPositionWidth);
You will have to do similar calculations for cameraMovement.Y and cameraPosition.Y.
When you have these, the only thing you will have to change in your draw function is the Y translation. Currently you have:
Matrix cameraTransform = Matrix.CreateTranslation(-cameraPosition, 0.0f, 0.0f);
As you see, you are only translating in the X axis. After adding the Y axis it looks like this:
Matrix cameraTransform = Matrix.CreateTranslation(-cameraPosition.X, -cameraPosition.Y, 0.0f);
I hope you figure it out now. Good luck!

Categories