I'm trying to add knockback to my player, but he won't move. I know the function is correctly called and the if a statement is functional, as he will still take damage, but the player won't move at all.
Weirdly, if I put the addForce somewhere else (Like in the update() method), it will work, but not in this scenario.
Some help would be greatly appreciated
private void OnCollisionEnter2D(Collision2D collision)
{
if (collision.gameObject.tag == "Enemy")
{
TakeDamage(-20, 21);
theRB.AddForce((collision.transform.position - transform.position).normalized * 100, ForceMode2D.Impulse);
}
}
Here is what the Rigidbody looks like if it helps:
Hey I think the issue here is with your use of
(collision.transform.position - transform.position)
I would instead calculate the direction using the contact point of the collision and save that in a Vector. Then normalize that vector and multiply by -1 to launch the player in the opposite direction. Here's some sample code:
Vector2 dir = collision.contacts[0].point - transform.position;
// Flip the vector and normalize
dir = -dir.normalized;
// Apply Force
theRB.AddForce(dir * 100, ForceMode2D.Impulse);
Ok, so I figured out the answer. The problem lies in the way I managed movement in my Movement() function. To create movement, I used this line :
theRB.velocity = new Vector2(Input.GetAxisRaw("Horizontal"), Input.GetAxisRaw("Vertical")).normalized * playerSpeed;
Apparently, velocity doesn't really work well with AddForce, for reasons I am not capable of explaining, as my understanding of Unity is still limited. I'll need to figure out a better way to manage movement, and I'll edit this post once I figure it out in case someone made the same mistake as me.
EDIT : So, turns out I've been looking for weeks, and didn't find anything. My final solution was to use a LERP instead of Addforce(), and just forget about physics alltogether.
Related
[Using A-Star project] Hi. So the problem is in the title basically. I have a top-down game in which the enemy should face the direction they're going. I've tried:
To calculate Enemy's force of it's RigidBody in FixedUpdate
To calculate the vector from enemy to target.
In the first instance Enemy changes its animation states too quickly, every fixed frame there's a new force applied (especially annoying when the AI is close to target).
In the second Enemy always faces its target ignoring any obstacles. It's wallhacking, if you will.
To solve this bastard I decided to find AI's current waypoint and I do not know how to do that. I've found steeringTarget method in A-Star's documentation, but I couldn't figure out how to implement it.
I would REALLY appreciate any help. Thanks in advance!
(steeringTarget method)
https://arongranberg.com/astar/documentation/dev_4_1_0_9f8b6eb7/class_pathfinding_1_1_rich_a_i.php#a399e2bebfc8dfaf4fd291f051ca486e6
For questions related to A* Pathfinding Project it may be better to ask on the developer forum.
But here's my experience using it.
Usually you start with a seeker.
public Seeker seeker;
Since pathfinding calculations are asynchronous you must register for an event that tells us when the path is ready.
seeker.pathCallback += OnPathComplete;
Somewhere in your code you call to search for a path.
seeker.StartPath(start, end);
When the path is ready you will get a Path object. It contains all of the points and vectors.
List<GraphNode> path;
List<Vector3> vectorPath;
You can use the built-in PathInterpolator to smooth out the movement.
When you get the new path pass the vector path to the interpolator.
interpolator.SetPath(path.vectorPath);
On FixedUpdate you need to interpolate and apply the movement.
interpolator.MoveToCircleIntersection2D(transform.position, 0.1f, GraphTransform.identityTransform);
var moveDir = (interpolator.position - this.transform.position).normalized;
// Apply moveDir to Rigidbody, or whatever.
So thanks to the guy that tried to help, but that was not it. I solved my problem this way.
Vector2 direction = ((Vector2)path.vectorPath[currentWaypoint] - rb.position).normalized;
So this is the vector that's needed. From this game object to the end of the waypoint. Your code may vary.
Vector2 force = direction * speed * Time.deltaTime;
And this is the variable that is needed. So we set the animator with force.x and force.y and this should work.
I hope I made this at least somewhat clear. But if not - ask away.
I'm currently using this code:
public Transform Target;
public float speed = 20f;
public GameObject ME;
private void Update()
{
if (Vector3.Distance(ME.transform.position, Target.transform.position) < 5)
{
Vector3 direction = Target.position - transform.position;
Quaternion rotation = Quaternion.LookRotation(-direction);
transform.rotation = Quaternion.Lerp(transform.rotation, rotation, speed * Time.deltaTime);
}
}
Pretty much what it's doing is rotating an object based on where the target is. So if the target goes to the right the object is always facing it.
Now, I'm trying to achieve something like in this video, I'm trying to add edge fixed objects, where they rotate based on where the target is, but one of the edges is fixed to the wall, almost like a page in a book. I've found code to use another object, and use that as a pivot point, but I was hoping for a more straightforward solution that will allow me to use a boolean. For example, if the edge was on the right, rightFixed would be true, if left then leftFixed would be set to true. I figured moving the pivot point would be simplest solution, but now I am not exactly sure... how could I get that sort of functionality implemented?
Huge thanks for any help guy!
Question
This code works. ↓
private void FixedUpdate()
{
Vector3 newPosition = new Vector3(0, 1, 0);
GetComponent<Rigidbody>().MovePosition(newPosition);
}
This code doesn't work. ↓
private void FixedUpdate()
{
Vector3 newPosition = new Vector3(0, 1, 0);
Vector3 oldPosition = transform.position;
transform.position = newPosition;
transform.position = oldPosition;
GetComponent<Rigidbody>().MovePosition(newPosition);
}
I tested in Unity 2019.4 and 2020.3.
So, it seems Rigidbody.MovePosition() will not work if transform.position just changed.
Why does this happen?
2021.9.3 comment
I find it is relevant to Physics2D.SyncTransforms().
Physics.autoSyncTransforms, Physics.SyncTransforms
This code works. ↓
private void FixedUpdate()
{
Vector3 newPosition = new Vector3(0, 1, 0);
Vector3 oldPosition = transform.position;
transform.position = newPosition;
transform.position = oldPosition;
Physics2D.SyncTransforms(); //newly added
GetComponent<Rigidbody>().MovePosition(newPosition);
}
Another small problem
Another small problem and the reason for why I'm writing code above.
I didn't use much physics in my project. I changed position by setting transform.position.
I learn some physics, and think Kinematic and Rigidbody2D.MovePosition() is proper for me.
The old code is about several hundred lines. It would take some time to replace transform.position with Rigidbody2D.MovePosition().
So I think I can do the following to save time:
(1)save initial position,
(2)use old code to change position (transform.position),
(3)save new position,
(4)restore old position,
(5)and finally use Rigidbody2D.MovePosition(newPosition) to change position.
But it turns out I can't do this in Unity.
Any good idea?
Firstly, Rigidbody's MovePosition method should only be used if you're constantly checking for a collision/trigger whether if the rigid body attached to the game object has continuous/discrete collision detection. If you really are not using much physics in the project, avoid using it and move the object using its transform instead.
The reason why the object is not moving (at least I assume that is what you see on the screen) is that you are trying to set the object's transform's position and rigid body at the same FixedUpdate timestamp and updating transform on FixedUpdate is a lot far from any best practices out there. If you move the lines where you edit transform's position to Update method, it would probably move the object (depending on the framerate and timestamp of the FixedUpdate the game runs at).
What I would suggest is, either stop updating transform's positions on FixedUpdate and only use rb.MovePosition method, or remove FixedUpdate method and update the transform's positions on Update() method.
Also, make sure that you do not change the transform.position, rb.position or rb.velocity anywhere else inside that MonoBehaviour class for now, just to make sure that this piece of code works fine.
Physics2D.SyncTransforms(); this function Work for me...
I needed use a Transform.Translate of a game object and then use Rigibody.MovePosition for a child game object. How the child received the translation of the parend, the rb.MovePosition just doesn't work... the update of the physics was enought between the two funtions.
Physics2D.SyncTransforms() allow update the physics for the transform.translation.
I need the Player to follow the moving Target and stop exactly when it reaches the Target.
The Player has to reach the Target almost instantaneously in every frame, so i need a high speed way to do it.
I couldn't use Transform.translate because there's a lot of physics implementations in my game and using Transform.translate or movetowards made the physics buggy.
Is there any physics based way to follow the target? velocity, AddForce, anything? For a 2D game.
Any leads would be greatly appreciated! Thank You!
If you have a Rigidbody2D you want to follow another object, the Rigidbody2D.MovePosition is the proper way to move it.
Do the following:
1.Disable gravity by setting the "Gravity Scale" to 0.
2.Change the BodyType to Kinematic.
3.You can now move the Rigidbody object to follow another GameObject with the Rigidbody2D.MovePosition function. See code below. This should be done in the FixedUpdate function and with Time.fixedDeltaTime instead of Time.deltatime.
Finally, if you still get jerky movement, change Interpolate option from None to Interpolate or Extrapolate. I would also suggest reducing the speed variable below.
//Object to follow
public Transform target;
//Rigidbody to move
public Rigidbody2D rb2d;
public float speed = 7.0f;
//Distance to start moving
public float minDistance = 0.09f;
void FixedUpdate()
{
//Find direction
Vector3 dir = (target.transform.position - rb2d.transform.position).normalized;
//Check if we need to follow object then do so
if (Vector3.Distance(target.transform.position, rb2d.transform.position) > minDistance)
{
rb2d.MovePosition(rb2d.transform.position + dir * speed * Time.fixedDeltaTime);
}
}
Changing the velocity directly is always a bad practice and should be avoided. Instead always work with AddForce.
I would calculate the distance between the target and the body and add a force based on that distance.
var dif = target.transform.pos - body.transform.pos;
bodyRigid.AddForce(dif * multiplier * Time.deltatime);
The only problem that comes with that solution might be the fact that the body 'shakes' around the target once its to close.
You could avoid this by checking if the body is close to target and then freezing it.
var dif = target.transform.pos - body.transform.pos;
if(dif.magnitude > 1) {
bodyRigid.AddForce(dif * multiplier * Time.deltatime);
} else {
bodyRigid.velocity = Vector2.zero;
}
Although I said that setting the velocity directly is a bad habit, using it to just freeze the body should be fine. I have no idea whether that might break your other physics that you use in your game, duo the fact that that just strait up freezes your object.
You can also change the distance (1 in the if statement) that it needs in order to freeze, just play around with it a bit and find a value that fits the game
I'm trying to make a very simple race game with spheres, however, I face many problems.
First of all, I'm trying to make a very simple AI system for opponents.
The problem I have here is that I want opponents to detect obstacles and avoid them using Raycast but only a certain type of obstacle , a simple cube is detected.
I've created a simple sphere as opponent and wrote a script so it can move and detect obstacles
Here is update function:
void FixedUpdate()
{
transform.Translate(Vector3.forward * Time.deltaTime * speed);
if (Physics.Raycast(transform.position, transform.forward, 100.0f))
print("There is something in front of the object!");
}
The message is printed only when there is a cube forward and it does not detect any other obstacles. What can be so wrong? Also, is there any idea how to move left or right when opponent raycast an obstacle?
obstacle that is detected
hierarchy
cube01 that is child of obstacle2 that is not detected
Only collider components are detected using raycast, make sure you have an appropriate collider (size of the collider does not necesarily match size of the mesh that gets rendered). Normally also layers on which objects are are important but syntax you are using is not checking for layer mask anyway
Unity Physics Best Practices (As in https://unity3d.com/pt/learn/tutorials/topics/physics/physics-best-practices) recommends that we don't use Raycasts in FixedUpdate, as it is heavy to process and may not always work.
There is also some tips about Matrix Layers that will help you improve performance and avoid such bugs.
Good luck!
You can use Debug.DrawLine() or Debug.DrawLine() to debug the line and see if it cross the obstacles or not.
Here is the documentation for them
DrawRay
DrawLine
For moving right and left I think you can add something like this
void FixedUpdate()
{
Vector3 dir = Vector3.forward * Time.deltaTime * speed;
if (Physics.Raycast(transform.position, transform.forward, 100.0f))
{
print("There is something in front of the object!");
dir += Vector3.Right * horizontalSpeed * Time.deltaTime;
}
}
You might also consider ray casting two rays to detect the direction to lean to if it will be the left or the right.