AddRelativeForce() causes unwanted turning - c#

I've create a movement script that moves a character (ship) in a topdown view.
Gravity is disabled, but the rest of the settings i left mostly alone.
I'm applying a constant force in the forward or backward direction (local, so relative to the character NOT the world). This however causes some movement in other directions if the character is rotated for some reason.
Debug.Log(nameof(force) + force);
rigidBody2D.AddRelativeForce(force);
Lets me explain with pictures.
Starting point:
Moving forward somewhat (works okay):
Back to starting point (stopping game, starting anew)
And then i manually change the rotation to -90 in the inspector.
I then move forward somewhat.
As we can see since the rotation is -90, moving forward in relative to the character (AddRelativeForce(..)) causes it to move to the right on the screen.
The X position increments accordingly.
However, also the Y component changes, the character gets velocity in this direction, even though i apply no force in that direction - which we can see in the output.
How can I move my character with force without this issue?
Edit:
Here are the project files. Runs under the latest unity 2020.1.14f1. The logic mentioned here is located in MoveExecuteSystem. I use a small ECS framework: https://github.com/Leopotam/ecs
https://wetransfer.com/downloads/b86dfb27b4388b85ac4fef285d87b39520201124193329/00af66

Take into account that AddRealtiveForce adds the force in the local coords system. If the force vector has got always the same value, the outcome is going to be different depending on the rotational position of the entity.
To solve this, you need to apply the force such as: Vector3 force = myShip.forward * forceValue where force value can be an int or a float.
It can be myShip.up or myShip.right depending on what you want. My point is that with the .forward, .up or .right you always will apply the force according to the instant local coordinate system rotational position.
EDIT:
This question seems deeper than I thought, I made the trial in a project myself, and actually there are variations in the position when you apply force only when the object is rotated. Had a quick look and don't know why this is. Seem to be a precisión thinh regarding the rotations of the physics the rigidbody uses under the hood.
I tried to remove the friction which I thought might be also cause of the problem but seems not possible. +1 to this question and lookig forward to know the answer.
EDIT2:
Bounciness and friction can be set to 0 if a new physics material 2d is created, but the issue persists.
You can freeze position in determined axis as a solution, but this does not explain the position variation problem.

Related

Scaling Movement in unity VR with oculus headset

There seems to be an issue when i am using VR. The movement I make is not scaled correctly with the movement in the VR. I have to move much further in reality to go where I need to in VR. I am working on the reach with the OVRgrabbable script after finding something online that may help. I am having an issue with getting the X,Y axis to be recognized as objects. Everything else about the code seems to be ok as nothing else is underlined in red.
This image is the notif. i am getting. I am just referencing the x and y axis i think it should operate just fine
I have one suggestion, on the OVRCustomHand.prefab check the configurations on the script OVRCustomSkeleton.cs:
Make sure to check the checkboxes for Update Root Pose (only if your OVRHandPrefab is not parented to OVRCameraRig), Update Root Scale (makes the hand model size is scaled either up or down based on the user’s actual hand size), Apply Bone Translation.
This will make sure the Hand's position is referenced to your scene's global space instead of real tracking space.
Hope it works!

Interpolate where OnTriggerExit is called

In my code, I use OnTriggerExit to detect when an object leaves a previous cube's space, and then create another cube. However, because of delta time, the cube gets placed slightly late creating these varied size gaps:
How do I get rid of them, and position the cube properly?
I am pretty sure I need to interpolate, but I am not sure exactly what/how to do it. If needed, I have the last cube, last frame and current transforms, as well as current speed (in Vector3 form). Thanks!
When you leave, set this cube's position to lastCube.position + size_offset, where size_offset is however big your cubes are in the direction that they're moving.
You already have a reference to the previous cube (due to the OnTriggerExit supplying you with a reference to the other collider, from which you can get the needed Transform).
I don't think this is strictly deltatime,s fault. Physisc engine has its on timestep, and if the velocity is x, the object will travel x*dt per physics step. So, by the time the next round of triggers is fired, the object is already penetrating. You could either use a rigidbody (easier but may not give expected results), or check penetration depth with that collider and offset that

Unity Object moves when AddForceAtPosition is applied when it should only rotate

I have a game object in unity I'd like to thrust vector around with some forces. At the moment I'm trying to add some realistic rotation forces hence using AddForceAtPosition using an offset from the rigidbody center of mass. Yet when i run the game, the object starts moving slightly in addition to the rotation. No other forces are present and there is no drag.
rb.AddForceAtPosition(transform.TransformDirection(Vector3.up * 5), transform.position + transform.TransformDirection(mainThrustPt));
The Rigidbody.AddForceAtPosition function apply both torque and force on the object. this means that the Object will be rotated and moved at the-same time.
If you just want to apply a rotational force that doesn't move the Object, use the Rigidbody.AddTorque or Rigidbody.AddRelativeTorque which will only apply a rotational force to the Object.
You can also free the Rigidbody x,y,z position if you don't want it to move but the movement behavior of the object will be weird sometimes when this is done.
Yet when i run the game, the object starts moving slightly in addition
to the rotation.
If the Object is moving without adding force to it or without using AddForceAtPosition, then gravity is pulling it. Disable "Use Gravity" as I did in the image above.
Use AddTorque if you need rotation.
If you pushed the edge of a ball tied up with string, you would expect it to swing as well as spin. Try using this before applying the force:
rigidbody.constraints = RigidbodyConstraints.FreezeRotationX | RigidbodyConstraints.FreezeRotationY | RigidbodyConstraints.FreezeRotationZ;

(Unity) Issue with rotation when transform.up is aligning to a direction

I am testing out some ideas in Unity where a player can walk around a circle while staying on it (so the circle has its own gravity) and also being oriented properly. This game is currently being done in 2D, so all objects are sprites.
I do hope I can explain myself properly. Please ask if you need any further clarification...
It appeared that I succeeded with my idea until I noticed something odd.
So as expected, the player moves around the circle without falling off (custom gravity worked just fine) and its Z rotation is affected as it aligns itself with a direction:
// Align code:
// We reverse the direction so the object is standing up the right way.
private void Update()
{
transform.up = -(planet.position - transform.position);
}
It works... mostly. However, when the player object's rotation Z naturally reaches 180, it appears to flip horizontally (like a mirror effect) and then it returns to normal as rotation Z leaves 180. The visual flip happens because for some reason the object's Y becomes 180 at the same time too. At no other point does X or Y change in regards to rotation. Only Z. So the moment Z hits 180, Y is affected and the moment we leave Z 180, Y returns to 0.
I'm happy to provide a quick video of it happening in-game if anybody needs some visual understanding of what's going on.
The visibility of this bug tends to rely on how fast you're moving around the circle. If you're moving fast enough, you can probably skip over 180 and not see it happen at all, however if you move slow enough there's no denying it's there. It's also problematic for the fact that I simply make the camera a child of the player so when the player flips, so does the camera causing the entire scene to flip which can look extremely glitchy for a player to see.
I really have no idea how to tackle this issue as I have no clue why it would do such a thing. At every other rotation value it behaves just fine. It's only at Z = 180 (so the object is exactly upside down) does it decide to rotate in the wrong ways.
EDIT: Changed tag to Unity3D
It's probably because of converting quaternions (which is what's actually used internally for rotations) to euler angles for display. Can you try to use Quaternion.Slerp to rotate?

2D Platformer AABB collision problems

I have a problem with AABB collision resolution.
I resolve AABB intersection by resolving the X axis first, then the Y axis.
This is done to prevent this bug: http://i.stack.imgur.com/NLg4j.png
The current method works fine when an object moves into the player and the player has to be pushed horizontally. As you can see in the .gif, the horizontal spikes push the player correctly.
When the vertical spikes move into the player, however, the X axis is still resolved first. This makes "using the spikes as a lift" impossible.
When the player moves into the vertical spikes (affected by gravity, falls into them), he's pushed on the Y axis, because there was no overlap on the X axis to begin with.
Something I tried was the method described in the first answer of this link.
However the spikes and moving objects move by having their position changed, not velocity, and I don't calculate their next predicted position until their Update() method is called.
Needless to say this solution didn't work either. :(
I need to solve AABB collision in a way that both of the cases described above work as intended.
This is my current collision source code: http://pastebin.com/MiCi3nA1
I'd be really grateful if someone could look into this, since this bug has been present in the engine all the way back from the beginning, and I've been struggling to find a good solution, without any success. This is seriously making me spend nights looking at the collision code and preventing me from getting to the "fun part" and coding the game logic :(
I tried implementing the same collision system as in the XNA AppHub platformer demo (by copy-pasting most of the stuff). However the "jumping" bug occurs in my game, while it doesn't occur in the AppHub demo.
[ jumping bug: http://i.stack.imgur.com/NLg4j.png ]
To jump I check if the player is "onGround", then add -5 to Velocity.Y.
Since the player's Velocity.X is higher than Velocity.Y (refer to the fourth panel in the diagram), onGround is set to true when it shouldn't be, and thus lets the player jump in mid-air.
I believe this doesn't happen in the AppHub demo because the player's Velocity.X will never be higher than Velocity.Y, but I may be mistaken.
I solved this before by resolving on the X axis first, then on the Y axis. But that screws up the collision with the spikes as I stated above.
Why not resolve on the Y-axis first for vertical spikes, and on the X-axis first for horizontal spikes?
Nice graphic, by the way.
As I understand it, you're handling movement and collision something like this:
Move all objects.
For each object O, test for intersection between the player and O, and if necessary, eject the player horizontally or vertically so that it is no longer intersecting with O.
If the player is still intersecting with some object, then (something).
This means that when you come to step (2), you have forgotten which way the object O was moving, so you can't tell if it is trying to push the player upwards or sideways.
Solution: in step (1), store for each object the direction it is moving. When you find the player intersecting with an object, you can look to see whether the object is moving up, down, left or right, and that will tell you which way to perform the ejection.
As Gareth Rees already said, the issue is after a collision is detected, you need more information (both current location and either direction came from or last position) to perform the collision response.
It gets quite complicated if both objects are moving. Instead, choose one object to be the frame of reference and subtract its velocity from everything else.
A straight forward solution might be to create line segments for the movement/delta of the non-frame-of-reference object. Then intersect those segments with the 4 AABB edges. This gives the time of intersection and the normal at the point of intersection. Then you can apply the same response you have now.
One possible solution I found is sorting the objects before resolving based on the velocity of the player.

Categories