Raycast from one object to side of the other object - c#

I have a ai (the red circle) which should shoot at my player (the blue circle).
Currently i'm using a normal Raycast:
Ray ray = new Ray(transform.position, transform.forward);
which gives me the purple Line.
Now, when there is a corner (like on the image), it doesn't hit the player, but it could if it would shoot a bit more to the side.
I've seen a solution for this by adding an angle to that raycast, but this doesn't work for me, because the angle is different if the player is near or far away from the ai.
What i need is:
That the ai shoots a raycast from itself to the side (left & right) of the player, but i don't know how to do that.

Your player certainly has some kind of radius, no?
Just using the distance between the player and the shooting AI, the player's radius and some nice trigonometry, you should be able to generate two rays to test both if the shooting AI sees the player's "right side", as well as his "left side".
Vector3 direction = player.transform.position - shootingAI.transform.position;
float distance = direction.magnitude;
float playerRadius = player.radius;// this is a variable you need to set
float angleToRotate = Mathf.Atan(radius/distance); // trigonometry: tan(angle)=oppositeSideLength/adjacentSideLength
Vector3 rayDirection1 = Quaternion.Euler(0f, -angleToRotate, 0f) * direction;
Vector3 rayDirection2 = Quaternion.Euler(0f, angleToRotate, 0f) * direction;
Using these two rays as directions you should be testing for the "right side", and the "left side"

You can find good answer HERE.
Or maybe use Sphere Raycast and use Contact Point and shot at this point.

Related

Problem with 3rd person camera rotation in unity

I'm trying to make the camera rotate around an object according to the movement of the mouse, and this is what I've come up with:
void Start()
{
direction = new Vector3(1f,0f,0);
direction.Normalize();
Debug.Log(direction);
mousePosCurr = Input.mousePosition;
}
void Update()
{
mousePosPrev = mousePosCurr;
mousePosCurr = Input.mousePosition;
mouseVector = (mousePosCurr - mousePosPrev);
mouseVector = mouseVector * sensitivity;
direction = Quaternion.Euler(mouseVector.y, mouseVector.x, 0) * direction;
direction.Normalize();
Debug.Log(direction);
this.transform.position = (target.position + tOffset + (direction * distance));
transform.LookAt(target.position + tOffset, Vector3.up);
}
Now, I'm sure that there are at least a million problems with this code, however the main one I'm facing right now is that the x rotation does not work correctly, unless the y rotation is in a specific direction.
What's happening is basically that the more I rotate in the y axis the more "inprecise" the x movement becomes. So for example, when the camera is south of the object I'm rotating it around, the x rotation works exactly as it should, you move the mouse up, and the camera points up and viceversa, but when it's west of it the movement of the mouse required for the vertical rotation is no longer vertical, but diagonal, and when it's north of the object the movement is inverted: moving the mouse up makes the camera point down and viceversa.
This seems most likely caused by the fact that regardless of the horizontal rotation of the direction vector, I'm still rotating along the x axis in the same direction, as if the camera was south of the object.
However, even having (hopefully) identified the problem, I'm still clueless as to how to solve it, so I'm asking for help here.
Note: I just noticed that I probably used the term "rotation" wrong in this post. When I write "rotation of the camera", I'm actually referring to the rotation of the "direction" vector.
alright so I am not the best in Unity so this might be completely useless but when I try to rotate my camera around an object I create an empty game Object and make the camera a child of it, like this
so that I can just just rotate the Game Object to rotate the camera around a fixed point maybe your code will work

How to tilt an object depending on the direction of the player on a spherical map

How do I correctly calculate the rotation angle so that the object dodges the player? It means that whichever side the player comes from, the object must turn away from the player depending on its direction. I want the effect like in the video but without Joint, only rotation angle: https://www.youtube.com/watch?v=GJhiR3SOyXs
I have the answer from this post:
but right now I need it for a spherical map. It looks like this right now:
I have same trees and I got different results for them:
I have correctly result for this tree:
BUT not for this tree:
The coordinates of the correctly tree:
The coordinates of the incorrectly tree (number 1):
The coordinates of the incorrectly tree (number 2):
The coordinates of the incorrectly tree (number 3):
If you're on a sphere you need to use the normal of the ground as the up direction. Since you've probably initially rotated the tree the right way up, you could do the following:
[SerializeField] Transform player;
[SerializeField] float effectMaxDistance=1;
[SerializeField] float maxAngle=50;
Quaternion initialRotation;
Vector3 initialUp;
void Start(){
initialRotation = transfrom.rotation;
initialUp = transfrom.up;
}
void Update(){
Vector3 dir = player.position - transform.position;
Vector3 axis = Vector3.Cross(dir, initialUp);
float angle = (1-(Mathf.Clamp(dir.magnitude, 0, effectMaxDistance) / effectMaxDistance)) * maxAngle;
transform.rotation = initialRotation * Quaternion.AngleAxis(angle, axis);
}
put a rigidbody on each bush.
Set the mass of each bush to 0, so it doesn't move the player (if you want it to push the player, you can set it higher)
Add a spring joint to your bush, and a sphere collider.
sphere collider should mainly cover the bush, and should touch the ground.
Set the connected anchor to right below your bush. (this is in local space, relative to the bush, so maybe set it to (0, -1, 0) or something close)
Set spring and damper, so you can customize.
If you want there to be a max stretch distance (Try spring joint first), you could use a HingeJoint, and add spring onto it
If you notice any unexpected behavior, could you please describe it. thanks :).

How to make an object move straight from random directions in Unity

I have a ball object in Unity 2D, this ball spawns at random positions on the screen and I want it to move in a 'straight-line depending on its direction e.g. if it's from the left it goes to the right or if it's from the top it goes to the bottom. I'm not sure if I should use transform.position/addforce/velocity to accomplish this and what direction I should use.
The following are what I have tried so far (I've tried using all directions)
ballRigidBody.AddForce(transform.up * speed);
ballRigidBody.velocity = Vector2.up * speed;
transform.position+=Vector2.up;
In Unity3D transform.forward is the go to variable when you want to move forward.
In Unity2D transform.right is the standard.
You can move your ball to its right with this code:
void Update()
{
GetComponent<Rigidbody2D>().velocity = transform.right * speed;
}
If you run this code the ball will always move into the direction of the red arrow.
You can see the arrows by selecting the move tool on the top left and then clicking on your ball inside the editor.
If you want to have your ball to always follow the green arrow you have to use transform.up.
transform.right and transform.up are both used relative to your object.
That means by changing the z rotation of your object you can modify the direction it should go in.
You can try out the following code to see your ball move to its right and rotate slowly on its z axis. This will cause the ball to move in a circle since it is still following the red arrow.
void Update()
{
GetComponent<Rigidbody2D>().velocity = transform.right * speed;
float speedRotate = 100;
transform.Rotate(Vector3.forward * speedRotate * Time.deltaTime);
}
When you always want to move an object to the right, no matter the rotation, you use Vector3.right instead of transform.right.
From your other comments I understand that you want your ball to always face into the direction in the middle of the screen. You can just rotate it to the middle of the screen when it spawns by using this code:
void Start()
{
transform.right = new Vector3(0, 0, 0) - transform.position;
}
This will get the ball to face the 0,0,0 position inside of your world. If 0,0,0 is in the middle of your screen it will face that direction. Otherwise you have to find out which coordinate your middle of your screen has.
I'm not sure what you're asking, but you can do ballRigidbody.velocity = transform.foward*speed, to make it go in the current direction it is facing.
If you want a ball you spawn on the left side of the screen to move to the right only, then set velocity like rb.velocity = Vector3.right * speed, and so on with each direction.
In this case, you should first check which position the ball spawned at (Top, Bottom, Left, Right), then from that decide the movement direction. If the ball spawns at the bottom, the direction to go up should be Vector3.up for example.
After you get the force, you can use rigidBody.AddForce(direction * speed); to move the ball.

How to rotate around a corner when the distance is unknown

I feel like this is a solvable problem but I am just to stupid to solve it.
I want to able to move a player around a cube in third person in a 3D game. Before I worry about the corners where 3 edges of the cube meet I would first like to be able to move around two edges. If I use the LookAt method while jumping around a corner some problems occur with the vertical rotation of the player. So if he enters the trigger of the edge he turns around 180 degree somehow. That is why I am searching for a different solution.
(Green rectangle is the player. The dotted area is a trigger.)
So what I am given on the entry of the trigger is the edge position P2 and obviously the player position P3. The player should be able to stop the velocity while being mid air, so he could just fall down to the edge thanks to the gravity. That means that I can not just lerp it from the entry point to some exit point. The entry and exit points are dynamic.
What I already calculated is the distance from the player to the edge. Therefore I could tell if the player is closer to the right surface or the left surface judging by whether X or Y is higher.
But if the player enter on a higher position the numbers are also higher.
I am very confused about how to solve this. I need to lerp rotate the player around the corner P2 as long as he is within the two dotted lines.
Here's something to get you started. This will rotate your player so that their down is pointing at the edge, and their forward vector tries to remain unchanged as much as possible. This will mean that moving in playerTransform.forward will move them where they are facing but will rotate them so that as they move around the edge, they will rotate around it.
transform playerTransform;
Vector3 edgeWorldDirection;
Vector3 edgeWorldPosition;
Vector3 playerWorldPosition;
// Determine up direction
Vector3 player2Edge = edgeWorldPosition - playerWorldPosition;
Vector3 playerUpDirection = (
Vector3.Dot(player2Edge, edgeWorldDirection) * edgeWorldDirection
- player2Edge).normalized;
// rotate player to align local up with playerUpDirection and forward with
// previous forward as much as possible.
Vector3 playerRightDirection = Vector3.Cross(playerUpDirection, playerTransform.forward);
// handle player looking "up"
if (playerRightDirection == Vector3.zero) playerRightDirection = player.Transform.right;
Vector3 playerForwardDirection = Vector3.Cross(playerRightDirection, playerUpDirection);
playerTransform.rotation = Quaternion.LookRotation(playerForwardDirection, playerUpDirection);
For corners it's actually easier because your up is based on the location of the corner, you don't have to calculate the closest point on a line.
transform playerTransform;
Vector3 cornerWorldPosition;
Vector3 playerWorldPosition;
// Determine up direction
Vector3 playerUpDirection = (playerWorldPosition - cornerWorldPosition).normalized;
// rotate player to align local up with playerUpDirection and forward with
// previous forward as much as possible. Same logic here as previously.
Vector3 playerRightDirection = Vector3.Cross(playerUpDirection, playerTransform.forward);
// handle player looking "up"
if (playerRightDirection == Vector3.zero) playerRightDirection = player.Transform.right;
Vector3 playerForwardDirection = Vector3.Cross(playerRightDirection, playerUpDirection);
playerTransform.rotation = Quaternion.LookRotation(playerForwardDirection, playerUpDirection);
Depending on how you're handling movement & player orientation, you may not actually want to rotate the player's transform, but with the results of Quaternion.LookRotation(...) you can multiply the local direction the player tries to go by that rotation to get the world direction that would correspond to.:
Vector3 localDesiredMove;
Quaternion boxOrientationQuat = Quaternion.LookRotation(
playerForwardDirection,
playerUpDirection);
Vector3 worldBoxOrientedMove = boxOrientationQuat * localDesiredMove;

Unity3D - Move an object to the opposite direction by clicking on it

I'm new in Unity and I'm working on a simple project but I'm stuck.
So my idea is when the player touches the bottom side of a ball it goes the opposite direction. Pretty much like in real life, if you kick a ball on the bottom side it will go up, but in 2D version.
I tried finding the opposite point of where the player touched the ball and making a vector by subtracting the original point and the opposite point, and then applying force to move the ball but it doesn't work.
void MoveBall()
{
x = mouseClickPosition.x;
y = mouseClickPosition.y;
oppositeClickPosition.x = -x;
oppositeClickPosition.y = -y;
Vector2 direction = oppositeClickPosition - mouseClickPosition;
rb.AddForce(direction * force, ForceMode.Impulse);
}
You have to subtract the mousePosition and the center of the ball.
Vector3 clickedPosition = Camera.main.ScreenToWorldPoint (Input.mousePosition);
Vector3 ballCenter = ballTransform.position;
// If this goes the opposite direction just swap the values.
Vector3 forceDirection = (ballCenter - clickedPosition).normalized;
ballRigidbody.AddForce (forceDirection * strength, ForceMode.Impulse);
This way you find the direction and add the force you want, you can not use the normalized Vector3 if you want to use the distance as a factor too.
And you can catch that event properly on OnMouseDown if the ball has a collider
https://docs.unity3d.com/ScriptReference/MonoBehaviour.OnMouseDown.html
This may be helpful:
https://answers.unity.com/questions/681698/vector-between-two-objects.html
It Explains how to do it in 3D but the idea applies to both.
In your case, instead of oppositeClickPosition you should use the position of the ball:
Vector2 direction = transform.position - mouseClickPosition;
(replace transform.position with the position of the ball if this script is not attatched to the ball)
Hope that helps!

Categories