I am trying to draw a line from one object to a target object. I have managed to do this however the lines are drawn from the centers
What I would like to do is draw the lines from the edge of a plane to the edge of a plane on the target
In this image the white lines are the currently drawn connection and the red lines are how I would like the lines to be drawn
This is how the lines are drawn right now
foreach (GameObject planet in LinkedPlanets)
{
GameObject PlanetLine = new GameObject();
PlanetLine.transform.position = this.transform.position;
PlanetLine.name = this.transform.name + " To " + planet.transform.name;
PlanetLine.transform.parent = this.transform;
PlanetLine.AddComponent<LineRenderer>();
LineRenderer lr = PlanetLine.GetComponent<LineRenderer>();
lr.material = new Material(Shader.Find("Particles/Additive"));
lr.SetWidth(3f, 3f);
lr.SetPosition(0, this.transform.position);
lr.SetPosition(1, planet.transform.position);
lr.GetComponent<Renderer>().material.SetColor("_TintColor", new Color(1, 1, 1, 0.2f));
}
This code is not tested, so may be wrong.
EDIT:
I see that you want to connect from edges of plane, so all change is instead of having direction vector from one planet to other, is to have direction based on longer axis of this vector. If the "x" is longer then "z" use Vector3.right multiplied by unary operator which depends on if the direction vector was below zero or not.
END OF EDIT
You need to know the radius of each circle. Let's say that in this example you know it, and it is 5f and 4f. Then you need to calculate the "meeting" points. You can do it like this:
foreach (GameObject planet in LinkedPlanets)
{
float radiusA = 5f;
float radiusB = 4f;
GameObject PlanetLine = new GameObject();
PlanetLine.transform.position = this.transform.position;
PlanetLine.name = this.transform.name + " To " + planet.transform.name;
PlanetLine.transform.parent = this.transform;
PlanetLine.AddComponent<LineRenderer>();
LineRenderer lr = PlanetLine.GetComponent<LineRenderer>();
lr.material = new Material(Shader.Find("Particles/Additive"));
lr.SetWidth(3f, 3f);
Vector3 pointA = Vector3.ClampMagnitude (planet.transform.position - this.transform.position, radiusA);
Vector3 pointB = Vector3.ClampMagnitude (this.transform.position -planet.transform.position, radiusB);
lr.SetPosition(0, this.transform.position + pointA);
lr.SetPosition(1, planet.transform.position + pointB);
lr.GetComponent<Renderer>().material.SetColor("_TintColor", new Color(1, 1, 1, 0.2f));
}
So let's explain.
First you need to get the direction vector like:
planet.transform.position - this.transform.position
then clamp its length to end on radius length:
Vector3 pointA = Vector3.ClampMagnitude (planet.transform.position - this.transform.position, radiusA);
And finally add this vector to the actuall position:
this.transform.position + pointA
Related
I'm trying to get an angle from two Vector2 positions.
The points are found by the following raycast code:
RaycastHit2D hit = Physics2D.Raycast(groundedPos.transform.position, Vector3.down, 1, lmask); // lmask is only the blocks
Vector2 firstPos = hit.point;
RaycastHit2D hit2 = Physics2D.Raycast(groundedPos.transform.position + new Vector3(5f, 0, 0), Vector3.down, 1, lmask);
Vector2 secondPos = hit2.point;
How would I get an angle from these two Vector3 points?
I would then need to change the rotation of my object after this.
Edit:
Flat ground:
Not flat:
As you can see in the images, the red raycasts are where the raycast codes hit and they are displayed, the black square with the circle colliders is the player, and the two blocks is the thing I'm trying to change the rotation of. It is fine on flat, as you can see. But non flat it is messed up.
First a general issue with your code is the maxDistance. You are passing in 1 as the maximum distance for both your raycasts but your image shows that this might not hit the ground if it isn't flat
=> one of the positions might be "invalid" since the raycast doesn't hit the ground and therefore the value would just be a default (0, 0) which will mess up the rotation.
you either want to wrap this properly and do e.g.
var hit = Physics2D.Raycast(groundedPos.transform.position, Vector2.down, 1, lmask);
var hit2 = Physics2D.Raycast(groundedPos.transform.position + new Vector3(5f, 0, 0), Vector2.down, 1, lmask);
if(hit.collider && hit2.collider)
{
var firstPos = hit.point;
var secondPos = hit2.point;
...
}
or rather use float.PositiveInfinity as maximum distance for the rays so they will always hit something.
var hit = Physics2D.Raycast(groundedPos.transform.position, Vector2.down, float.PositiveInfinity, lmask);
var hit2 = Physics2D.Raycast(groundedPos.transform.position + new Vector3(5f, 0, 0), Vector2.down, float.PositiveInfinity, lmask);
var firstPos = hit.point;
var secondPos = hit2.point;
...
Then alternativ to this you can also use
var direction = secondPos - firstPos;
transform.rotation = Quaternion.Euler(0, 0, Mathf.Atan2(direction.y, direction.x) * Mathf.Rad2Deg);
which might be slightly more efficient.
Or simply set
transform.right = direction;
Or in case this is about a Rigidbody2D you would rather go through
rigidbody2D.MoveRotation(Mathf.Atan2(direction.y, direction.x) * Mathf.Rad2Deg);
Once you've got the two positions, find out the angle from the starting point to the second point, then apply the Euler rotation, rotating around the z-axis ..
transform.rotation = Quaternion.Euler ( 0, 0, Vector2.SignedAngle ( Vector2.right, secondaPos - firstPos ) );
Note - if you are trying to rotate a child of a GameObject, you might be "double" rotating the object, which is what it looks like in the images you updated your post with. If the colliders are attached to a child object, do you need to rotate that object as well?
after a good amount of searching I haven't been able to find out how to change the rotation of my overlap boxes set up and the gizmo used to visualize them.
//draw a hitbox in front of the character to see which objects it collides with
Vector3 boxPosition = transform.position + (Vector3.up * lastAttack.collHeight)
+ Vector3.right * lastAttack.collDistance;
Vector3 boxSize = new Vector3 (lastAttack.CollSize/2, lastAttack.CollSize/2, hitZRange/2);
Collider[] hitColliders = Physics.OverlapBox(boxPosition, boxSize, Quaternion.identity,
HitLayerMask);
I'm using it for damage calculation. I want the OverlapBox to take the same rotation of the player and always be in front of the player.
void OnDrawGizmos(){
if (lastAttack != null && (Time.time - lastAttackTime) < lastAttack.duration) {
Gizmos.color = Color.red;
Vector3 boxPosition = transform.position + (Vector3.up * lastAttack.collHeight)
+ Vector3.right * ((int)lastAttackDirection * lastAttack.collDistance);
Vector3 boxSize = new Vector3 (lastAttack.CollSize, lastAttack.CollSize, hitZRange);
Gizmos.DrawWireCube (boxPosition, boxSize);
}
}
Draw the Box Overlap as a gizmo to show where it currently is testing
To have the overlap box inherit the transform's rotation, you can use transform.rotation instead of Quaternion.identity for the overlap box's rotation.
For the gizmo, it's a little more complex. One way to fix this is to change the Gizmo matrix to be the local transform matrix with Gizmos.matrix = transform.localToWorldMatrix, which will make the gizmo inherit the player's rotation. But, it will also make the gizmo's position be relative to the player's local position. So, you'll need to convert the world position boxPosition to local position before you draw the gizmo. You can use transform.InverseTransformPoint to do this.
You may want to restore the gizmo settings to what they were previously or it could result in unexpected behaviour in other places where Gizmos is used.
Altogether:
//draw a hitbox in front of the character to see which objects it collides with
Vector3 boxPosition = transform.position + (Vector3.up * lastAttack.collHeight)
+ Vector3.right * lastAttack.collDistance;
Vector3 boxSize = new Vector3 (lastAttack.CollSize/2, lastAttack.CollSize/2, hitZRange/2);
Collider[] hitColliders = Physics.OverlapBox(boxPosition, boxSize,
transform.rotation, HitLayerMask);
...
void OnDrawGizmos(){
if (lastAttack != null && (Time.time - lastAttackTime) < lastAttack.duration) {
// cache previous Gizmos settings
Color prevColor = Gizmos.color;
Matrix4x4 prevMatrix = Gismos.matrix;
Gizmos.color = Color.red;
Gizmos.matrix = transform.localToWorldMatrix;
Vector3 boxPosition = transform.position + (Vector3.up * lastAttack.collHeight)
+ Vector3.right * ((int)lastAttackDirection * lastAttack.collDistance);
// convert from world position to local position
boxPosition = transform.InverseTransformPoint(boxPosition);
Vector3 boxSize = new Vector3 (lastAttack.CollSize, lastAttack.CollSize, hitZRange);
Gizmos.DrawWireCube (boxPosition, boxSize);
// restore previous Gizmos settings
Gizmos.color = prevColor;
Gizmos.matrix = prevMatrix;
}
}
I want to move an instance of a gameObject along the outline of another gameobject. Its a 2D Project in Unity.
My current Code:
Vector3 mousePosition = m_camera.ScreenToWorldPoint(Input.mousePosition);
RaycastHit2D hit = Physics2D.Raycast(new Vector2(mousePosition.x, mousePosition.y), new Vector2(player.transform.position.x, player.transform.position.y));
if (hit.collider != null && hit.collider.gameObject.tag == "Player") {
if (!pointerInstance) {
pointerInstance = Instantiate(ghostPointer, new Vector3(hit.point.x, hit.point.y, -1.1f), Quaternion.identity);
} else if(pointerInstance) {
pointerInstance.gameObject.transform.position = new Vector3(hit.point.x, hit.point.y, -1.1f);
pointerInstance.gameObject.transform.eulerAngles = new Vector3(0f, 0f, hit.normal.x);
}
}
Unfortunately, the gameObject doesn't rotate towards the mouse and the position on the left side of the playerObject is also sometimes off. I tried to use Instantiate() with Quaternion.LookRotation(hit.normal), but no luck either.
Here a rough sketch of what I want to achieve:
Any help is appreciated. Thanks!
it's better to use Mathematical way instead of physical way(Raycasting),because in raycasting you have to throw ray several time for checking hit point and rotate your object,it makes lag in your game.
Attach this script to your instantiated object:
using UnityEngine;
using System.Collections;
public class Example : MonoBehaviour
{
public Transform Player;
void Update()
{
//Rotating Around Circle(circular movement depend on mouse position)
Vector3 targetScreenPos = Camera.main.WorldToScreenPoint(Player.position);
targetScreenPos.z = 0;//filtering target axis
Vector3 targetToMouseDir = Input.mousePosition - targetScreenPos;
Vector3 targetToMe = transform.position - Player.position;
targetToMe.z = 0;//filtering targetToMe axis
Vector3 newTargetToMe = Vector3.RotateTowards(targetToMe, targetToMouseDir, /* max radians to turn this frame */ 2, 0);
transform.position = Player.position + /*distance from target center to stay at*/newTargetToMe.normalized;
//Look At Mouse position
var objectPos = Camera.main.WorldToScreenPoint(transform.position);
var dir = Input.mousePosition - objectPos;
transform.rotation = Quaternion.Euler(0, 0, Mathf.Atan2(dir.y, dir.x) * Mathf.Rad2Deg);
}
}
Useful explanations
Atan2:
atan2(y,x) gives you the angle between the x-axis and the vector (x,y), usually in radians and signed such that for positive y you get an angle between 0 and π, and for negative y the result is between −π and 0.
https://math.stackexchange.com/questions/67026/how-to-use-atan2
Returns the angle in radians whose Tan is y/x.
Return value is the angle between the x-axis and a 2D vector starting at zero and terminating at (x,y).
https://docs.unity3d.com/ScriptReference/Mathf.Atan2.html
Mathf.Rad2Deg:
Radians-to-degrees conversion constant (Read Only).
This is equal to 360 / (PI * 2).
I'm provide LineRenderer to draw the shape of Room in 2D and store the LineRenderer position values in DrawLine.storeLineRenderers list.(List2>)
My plan to create 3D room using 2D Shape , i.e LineRenderer's.
Following code gives convert to 3d, but not accurate
for(int i=1;i<=noOfLines;i++)
{
LineRenderer line =GameObject.Find("line" + i).GetComponent<LineRenderer>();
if(line!=null)
{
Vector3[] ss= DrawLine.storeLineRenderers[i - 1];
print(ss[0]); //Position Element 0 value (Vector3)
print(ss[1]); //Position Element 1 value (Vector3)
//generate 3d box (wall) here
GameObject cube = GameObject.CreatePrimitive(PrimitiveType.Cube);
cube.name = "wall" + i;
cube.transform.localPosition =new Vector3(ss[0].x,ss[0].y,ss[0].z);
cube.transform.localScale = new Vector3(ss[1].x - ss[0].x, ss[1].y - ss[0].y,ss[1].z - ss[0].z);
}
}
Output
How to solve this?? Is there any formula to create properly??
thanks in advance...
try this out.
What you have to be aware of is that the cube's pivot is in its center, meaning you have to add half its size to its position to make it "start" at ss[0] and span all the way to ss[1].
Also, the wall need to be rotated to look at ss[1].
const float thickness = .1f; // how thick will the wall be
const float height = 1f; // how high will the wall be
Vector3 dist = ss[1] - ss[0];
float length = dist.magnitude; // make wall long enough to span ss[0] to ss[1]
Vector3 cubeSize = new Vector3(thickness, height, length);
Vector3 cubePos = ss[0] + (cubeSize * 0.5f); // cube pivot is in its center
Quaternion cubeOrientation = Quaternion.LookRotation(dist, Vector3.up); // rotate to look at ss[1]
GameObject cube = GameObject.CreatePrimitive(PrimitiveType.Cube);
cube.transform.localPosition = cubePos;
cube.transform.localScale = cubeSize;
cube.transform.localRotation = cubeOrientation;
I want to get a Collide Vector of a Mesh using a Up-Vector.
I have a position and a Up Vector.. with these both I calculate the far vector
public Vector3 SetPlayerToGround(Matrix Object, Matrix Player, Mesh GroundObject)
{
Vector3 IntersectVector = new Vector3(0, 0, 0);
if (GroundObject != null)
{
Vector3 Player_UP = new Vector3(Player.M12, Player.M22, Player.M32);
Vector3 PlayerPos = new Vector3(Player.M14, Player.M24, Player.M34);
Vector3 PlayerPos_Far = PlayerPos - Player_UP ;
gameengine.m_Device.Transform.World = Object;
IntersectInformation closestIntersection;
if (GroundObject.Intersect(PlayerPos, PlayerPos_Far, out closestIntersection))
{
IntersectVector = Player_UP + (PlayerPos_Far * closestIntersection.Dist);
}
}
return IntersectVector;
}
Well if I do
Vector3 PlayerPos_Far = PlayerPos + Player_UP;
It will always intersect with nothing...
But the Object which I want to intersect is always under the "position - UpVector"
so I think
Vector3 PlayerPos_Far = PlayerPos - Player_UP ;
is right
why I cant intersect?
Here is a better Description:
Here is the Player and he is into a Ship. the Player is always at 0,0,0 because I move the world around the player. if I Move the Player forward I Chance the playerposition vector which chance only the positions of all other objects.
But I think the player has nothing to do with the Intersect.. but the ship itself.
I use the Position 0,0,0 and the upvector as direction to get the intersectvector of the ground from the ship. the Matrix of the Ship is (Matrix Object):
Vector3 com = ship.position - gamemanager.player.position;
Matrix world;
world = Matrix.Identity * Matrix.Scaling(0.001f, 0.001f, 0.001f) * Matrix.Translation(com);
m_Device.Transform.World = world;
I tried something and I think he wont use my translated Matrix of the ship...
You have to provide a ray defined by a position and a direction. You do not have to specify two points. So pass -PLAYER_UP instead of PlayerPos_Far.
Furthermore, the Intersect method will not care about transformations. You have to pretransform the ray. Transform both the ray position and the direction with the inverse world matrix (transform from world space to model's space) and you should be fine.
Vector3 rayStart = PlayerPos;
Vector3 rayDir = -PLAYER_UP;
Matrix world; //the ship's world matrix
world = Matrix.Invert(matrix);
rayStart = Vector3.TransformCoordinate(rayStart, world); //you may need to add an out parameter
rayDir = Vector3.TransformNormal(rayDir, world);
GroundObject.Intersect(rayStart, rayDir, ...