I'm trying to calculate what angle to hit a pool ball and predict where ball will go to..
I thought target ball should move within a normal direction.. but it moves
on totally different direction
RaycastHit2D hit = Physics2D.CircleCast(cue.position, _radius, dir, 100f, ~(ignoreLayer));
if (hit.collider != null)
{
Debug.DrawRay(hit.collider.transform.position, -1f * hit.normal,
Color.green, Time.fixedDeltaTime);
}
Here is result:
Set velocity
rb.velocity = dir * force;
Result:
How to find exact move direction, Thanks
Edit:
I have tried Double Radius Casting this works only half way.. only when ray inside inner circle
I suppose this is just a limitation of the physics engine, which is optimized for speed and use in games, and is not so exact.
Trying this myself in a simple 2D scene, I found that if I set the friction to 0.01 and the bounciness to 1.0, it works the way I would expect. (in Unity 2020.1)
In the small sample scene I added, there is a ball aiming at another so that the resulting angle should be 45 degrees. And after setting the phyics-mat to the properties with friction 0.01 and bounciness 1.0, the resulting angle is as expected.
With the default-mat I get the same behaviour you described.
Did you forget to assign the physics materials?
Have you single-stepped to the point of contact and checked if the aiming is correct?
my sample project trying this
Related
I want to make a game in Unity where a person can pick a surface and walk along all of its sides. I've gotten the movement working, but when I rotate my character around certain angles of corner the character flips 180 degrees in some direction (it's different depending on the corner) and when I want them to move forward the game freaks out as they keep going across the corner over and over again, turning, and going forward across the border again. I'd strongly prefer to keep my character from doing these 180-degree spins and I think it's just due to a flaw in the formula I use to calculate the angle they stand at (which is based around making sure their transform.up is aligned with the point they are meant to stand on). Any ideas on how I fix this rotation formula in Update?
Current formula:
angle = Vector3.Angle(closestPoint, transform.position);
var t = transform;
var angles = t.eulerAngles;
t.LookAt(GravityWellPoint.transform.position);
t.RotateAround(transform.position, -transform.right, 90);
transform.rotation = Quaternion.Lerp(transform.rotation, t.rotation, Time.deltaTime * 5.0f);
Got this solution from a different forum and it worked:
So this is actually not a trivial problem to solve. If you try doing it by calculating angles etc you almost always end up with a similar spinning/flipping issue in certain positions. You can solve it by doing the maths, but its a pain. I usually like to use Quaternion.LookRotation to solve this kind of problem. you can feed in the desired forward and upward directions. So you can calculate the desired upward direction like so:
Vector3 targetUpDirection = transform.position - GravityWellPoint.transform.position;
Then you would do the following:
transform.rotation = Quaternion.LookRotation(transform.forward,targetUpDirection);
but this doesnt quite work. LookRotation will ensure that your forward direction is exactly the one you specify, and then chooses the upward direction that's the closest possible to the one you specify. So you will find that we don't actually manage to point our object upwards in the way we intended. However, there is an unintuitive solution we can apply instead.
Calculate the upward direction in the same way, then use LookRotation to rotate our object to point its forward face in exactly our desired upwards direction, and its upward face towards the current forward direction:
Vector3 targetUpDirection = transform.position - GravityWellPoint.transform.position;
transform.rotation = Quaternion.LookRotation(targetUpDirection, transform.forward);
Now our object is aligned perfectly, but is the wrong way up. We can use LookRotation again, to swap the upwards and forwards directions:
transform.rotation = Quaternion.LookRotation(transform.up, transform.forward);
For clarity/TLDR here is the complete code for my solution:
//find the desired up direction:
Vector3 targetUpDirection = transform.position - other.position;
//face forward/upward via black magic
transform.rotation = Quaternion.LookRotation(targetUpDirection, transform.forward);
transform.rotation = Quaternion.LookRotation(transform.up, transform.forward);
I started some programming in Unity just for fun a couple days ago.
So far my game (pretty much top-down shooter) consists of player flying in an asteroid field, in which lurk enemy ships. Player can shoot down asteroids and enemies, and enemy ships have missile turrets that "track" player.
Everything works fine until I decided that enemy ships shouldn't be able to rotate their turrets all the 360-way. Think of it as real-world battleship being unable to turn it's front turret (No.1) 180 degrees behind because turret No.2 is in the way.
Currently code for turret rotation is like this (this is not about making "gradual rotation", setting "rotation speed" or something, so please don't look at that!):
playerTarget = GameObject.FindGameObjectWithTag("Player");
chaseDirection = Quaternion.LookRotation(playerTarget.transform.position - transform.position);
newYaw = Mathf.Clamp(chaseDirection.eulerAngles.y, minYaw, maxYaw);
transform.rotation = Quaternion.Euler(0, newYaw, 0);
That works okay, until player flies behind enemy ship. As soon as player gets into turret's "possible rotation angle", it just snaps past "dead zone" to new direction if I don't turn it gradually with fixed angle, or is still stuck trying to rotate "past limit" until target (player) flies all around enemy ship so the angle to target is small enough for rotation direction to be calculated through "enabled" rotation zone, not through "dead zone".
An important thing is I am not looking for answer "how to make gradual rotation". I am looking about calculating rotation direction!
I thought about coding enemy to start rotating turret in counter-direction as soon as player passes "directly behind" the turret "forward facing" position. But the concept of how to do that eludes me.
Because as soon as turret rotates just a bit from limit, it's able to turn "towards" player again, and gets stuck at limit again.
Edited with the clarification in mind.
You need a function that will tell you if you should rotate clockwise or counter-clockwise, based on the enemy location.
First find the mid point, this will be:
var mid = (minYaw + maxYaw) / 2
In your example this will be 3 o'clock, straight right.
Now, if your current rotation is lower than mid, and the target is higher than mid, than you must rotate clockwise even if it's not the shortest rotation to get there.
If the target rotation is higher than mid, and the target is lower than mid, you must rotate counter-clockwise for the same reason. You may need to adjust for negative degrees.
Please note that this will create a secondary effect, where once the ship passes the half point of the dead zone (say moving from 10 o'clock to 8 o'clock in your example), the turret will start moving as if anticipating the flank. You may want to disable this movement in a special case.
I'll keep the second part of my answer as-is, for future references.
If you want it to move gradually, you need to use deltaTime or fixedDeltaTime in case of a fixed update. You can define how fast it will move by adding a speed property. Try something like this:
void update () {
var playerTarget = GameObject.FindGameObjectWithTag("Player");
var chaseDirection = Quaternion.LookRotation(playerTarget.transform.position - transform.position);
var newYaw = Mathf.Clamp(chaseDirection.eulerAngles.y, minYaw, maxYaw);
var currentRotation = transform.eulerAngles;
var desiredRotation= currentRotation;
var desiredRotation.y = newYaw;
transform.eulerAngles = Vector3.RotateTowards(currentRotation, desiredRotation, Time.deltaTime * RotationSpeed, 0.0f);
}
I'm making a game with unity3D that ball is rolling on the ground.
When I set single large ground block, and using Rigidbody.AddForce() in Unity3D. ball is rolling fine.
But if I set multiple small ground blocks, ball is jumping unexpectly on boundary of blocks. Even block size, positions and intervals are exactly matched.
Can I solve this problem?
(I can't freeze position Y of ball. because ball needs gravity.)
-edited-
Here is my code to move ball by AddForce(). when I clicked.
private void MoveBall(Vector3 pos)
{
Ray HookRay = Camera.main.ScreenPointToRay(pos);
int layerMask = LayerMask.GetMask("Block");
RaycastHit objectHit;
float distance = Mathf.Infinity;
if (Physics.Raycast(HookRay, out objectHit, distance, layerMask))
{
moveTo = objectHit.point;
Vector3 forceValue = moveTo - transform.position;
forceValue.y = 0f;
rb.AddForce( forceValue * charSpeed, ForceMode.Impulse);
}
}
And here is screenshot of Unity3D
I placed 3x1x3 cube blocks and arranged all positions Y to 0.
There are no cracks or gaps on it.
This likely comes from inaccuracies in the physics engine. They are there because the engine tries to cut corners to speed up processing. You can make it cut less counters (at the cost of speed) by following a few steps. First thing to try is to make the rigidbody do collision detection continuous. You can also try turning on interpolation. There are also more advanced ways where you will do physics updates more often than your frame rate. But I would try the simpler options first. They’re often enough.
Go to Edit -> Project Settings -> Physics and play with default contact offset, maybe make it much smaller like 0.00001 and try it. Another way you can freeze the y and then when some condition happens you can unfreeze it again.
I'm trying to create a game where a ball is launched off from a circle, much like a cannon, but it can be launched into any direction, 360º because the circle which the ball is attached to can rotate. So, I was thinking of using Rigidbody2D.AddForce() but I'm not sure how to define the direction I want the force to be applied. I want it to be the direction perpendicular to the ball/player's movement but I don't know how to define that. Thanks for any help! :)
If you get the direction that the ball is travelling (as say degrees) you can add a certain angle to that and use the angle to determine the force that needs to be applied.
I'm assuming that the ball/player has no ridged body, if it does then you can just grab the direction directly. Also since your using circle to describe the spawned shape i'm going to assume your working in 2D.
Vector3 lastPosition;
void Update()
{
//launch the ball before updating the last position
lastPosition = transform.position;
}
Vector3 launchDirection()
{
Vector3 ballDirection = transform.position - lastPosition;
float angle = Mathf.Atan2(ballDirection.x, ballDirection.y) * Mathf.Rad2Deg;
//the direction should be perpendicular to direction of movement
float angle += 90;
return new Vector2(Mathf.Cos(angle), Mathf.Sin(angle));
}
I haven't ran the code in unity but it looks like it should work. Basically to get the direction you store the last position and compare it to the current direction to work out the delta (if your using a ridged body to move around then grab the direction from that instead) then use atan2 to get the angle. To make the launch direction perpendicular to the ball I added 90 degrees (you might want -90 depending on what side you need the circle to launch from). Now that we have the angle that you want the ball to shoot out from, use that with Sin and Cos to get the XY of the angle.
There you have it that will get you the direction perpendicular to movement, you your using 3 dimensions it's basically the same maths just with a few numbers thrown in to pad the return value.
Oh if your object always faces the direction of movement transform.right also works :P
I am a beginner and trying to make penalty shooter Game in unity.. I have just setup the scene and just trying to shoot the ball towards the goal post.
When i shoot the ball it goes toward the goal but does not come down, because i am shooting it through the script and its gravity is off and kinematic is on.
Currently i have the following script:
void Start () {
startTime = Time.time;
rb.GetComponent<Rigidbody>();
}
void Update () {
transform.position -= fakevel * Time.deltaTime;
transform.position += fakeGravity * Time.deltaTime;
fakevel *= 0.999f ;
}
void OnTriggerEnter( Collider other ) {
fakevel = new Vector3(0.01f, 0, 0) * 2000f;
fakeGravity = new Vector3 (0 ,0.01f, 0)* 200f;
y = -45.68312f;
}
}
I have tried enabling the gravity and disabling the kinematic at some specific position but i does so the gravity just pull it down at that position and it does not look realistic. Some screen shoots are attached.
Please help me in setting trajectory of the ball and stopping it when it collides with the goalpost,
I would suggest you use a non-kinematic rigidbody on your ball and add a force to it when you shoot it: GetComponent<Rigidbody>().AddForce(forceVector3, ForceMode.Impulse) (this is just an example, you should avoid calling GetComponent on a frequent basis, you are better off calling it for the rigidbody component once on Start and store it in a private variable)
This way Unity's physics engine can handle gravity and the balls' velocity over time. To modify the trajectory you can play around with the properties of the balls' rigidbody component.
If you want to have more control over the velocity, you can also set the rigidbody's velocity directly in the FixedUpdate() (which is called right before each physics update). When doing so, you have to consider that velocity is measured in m/s and the physics engine handles sub-steps for you (I am assuming that FixedUpdate() is called more than once per second), meaning you do not have to multiply your velocity with some delta time (but I am not 100% sure about this right now).
Seeing how it does work, just doesn't give the effect you want, you can either spend several hours fine tuning it, or like xyLe_ stated, use the built in physics. Using the built-in physics isn't a bad thing, you just gotta be smart with it. You can add a bouncy physics material also, which will help give the ball a well, ball feel.