Instantiate Object on Raycast2D hit and rotate Instance - c#

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).

Related

In Unity Calculate Points a Given Distance Perpendicular to a Line at Angles on a Circle

I crafted a model to illustrate what I am trying to calculate. Given a line (vector) between two anchor points, I want to place one or more game objects a certain distance tangential to the midpoint of that vector and at designated angles (radians?) along a circle that is perpendicular to the vector.
In this illustration, an imaginary circle is placed at midpoint and perpendicular to the line between Anchor 1 and Anchor 2. I want to calculate the Vector3 positions of three points (P1, P2, and P3). The intent is to place objects at each of those points. The entire assembly will a gameobject that can rotate in space. (There will be a single game object with each object a child.)
I have scoured StackOverflow and the Unity communities and cannot find examples that help me make those three placements.
Any ideas?
Instead of trig, consider vector math and quaternions. Use cross products to find the 0 angle offset and quaternions to rotate it according to the angle. See comments for explanation.
public void PlaceObjects(Transform anchor1, Transform anchor2, float r,
List<Transform> objs, List<float> angles)
{
// lists must be non-null and same size
Debug.Assert(objs != null);
Debug.Assert(angles != null);
Debug.Assert(objs.Count == angles.Count);
// Find midpoint and axis of rotation
Vector3 midpoint = 0.5f * (anchor1.position + anchor2.position);
Vector3 axis = (anchor2.position - anchor1.position).normalized;
// What direction should the the "zero" offset be based on?
// Base it on the local up of the "assembly parent" this script is attached to?
// or Vector3.up if "0 angle" should approximate world up?
Vector3 upDirection = transform.up;
// Of directions perpendicular to the axis find the closest to upDirection
// See https://stackoverflow.com/a/57698547/1092820 for more information
Vector3 axisRight = Vector3.Cross(upDirection, axis);
if (axisRight == Vector3.zero)
{
// upDirection & axis are colinear, no unique "up-ish" exists.
// Just give up and don't move anything.
return;
}
Vector3 zeroOffsetDir = Vector3.Cross(axis, axisRight);
for (int i = 0 ; i < objs.Count ; i++)
{
Transform obj = objs[i];
float angle = angles[i];
// Find a rotation that describes how to rotate a "0 angle" offset into the one
// the current object needs
Quaternion rot = Quaternion.AngleAxis(angle, axis);
// Find the offset by rotating the "zero" offset, then extending it by the radius
Vector3 offset = r * (rot * zeroOffsetDir);
// Set the object's position based on its offset and the location of the midpoint
obj.position = midpoint + offset;
// Optionally, set the object's rotation based on its current forward and the new up:
// obj.rotation = Quaternion.LookRotation(obj.forward, offset);
}
}
For those interested, here's my Component adaptation of #Ruzihm's solution. The PlaceObjectsOnCirclePerpendicularToVectorLine component is placed on an empty game object.
using System.Collections.Generic;
using UnityEngine;
public class PlaceObjectsOnCirclePerpendicularToVectorLine : MonoBehaviour
{
// Adapted from https://stackoverflow.com/a/63308834/13052746, by Ruzihm.
public Transform anchor1;
public Transform anchor2;
public float radius;
public List<Transform> objs;
public List<float> angles;
private Vector3 anchor1PriorPosition;
private Vector3 anchor2PriorPosition;
// Start is called before the first frame update
void Start()
{
PlaceObjects(
anchor1,
anchor2,
radius,
objs,
angles);
}
// Update is called once per frame
void Update()
{
PlaceObjects(
anchor1,
anchor2,
radius,
objs,
angles);
}
public void PlaceObjects(
Transform anchor1,
Transform anchor2,
float radius,
List<Transform> objs,
List<float> angles)
{
if (anchor1PriorPosition == anchor1.position &&
anchor2PriorPosition == anchor2.position)
{
// The anchors haven't moved.
return;
} else
{
anchor1PriorPosition = anchor1.position;
anchor2PriorPosition = anchor2.position;
}
// lists must be non-null and same size
Debug.Assert(objs != null);
Debug.Assert(angles != null);
Debug.Assert(objs.Count == angles.Count);
// Find midpoint and axis of rotation
Vector3 midpoint = 0.5f * (anchor1.position + anchor2.position);
Vector3 axis = (anchor2.position - anchor1.position).normalized;
// What direction should the the "zero" offset be based on?
// Base it on the local up of the "assembly parent" this script is attached to?
// or Vector3.up if "0 angle" should approximate world up?
Vector3 upDirection = transform.up;
// Of directions perpendicular to the axis find the closest to upDirection
// See https://stackoverflow.com/a/57698547/1092820 for more information
Vector3 axisRight = Vector3.Cross(upDirection, axis);
//if (axisRight == Vector3.zero)
//{
// // upDirection & axis are colinear, no unique "up-ish" exists.
// // Just give up and don't move anything.
// return;
//}
Vector3 zeroOffsetDir = Vector3.Cross(axis, axisRight);
for (int i = 0; i < objs.Count; i++)
{
Transform obj = objs[i];
float angle = angles[i];
// Find a rotation that describes how to rotate a "0 angle" offset into the one
// the current object needs
Quaternion rot = Quaternion.AngleAxis(angle, axis);
// Find the offset by rotating the "zero" offset, then extending it by the radius
Vector3 offset = radius * (rot * zeroOffsetDir);
// Set the object's position based on its offset and the location of the midpoint
obj.position = midpoint + offset;
}
}
}
Here's what it looks like in the Scene view:
And here's what the component looks like in the inspector:
Again, brilliant, #Ruzihm! Exactly what I wanted!

2 rotations with transform.Rotate() and transform.localEulerAngles() doesn't work

I'm trying to make a simple car simulator, and when I use the transform.Rotate() to rotate the wheels foreword (x axis), and the transform.localEulerAngles() to rotate in the turning direction (y axis), only the localEulerAngles() works. when I use only one method, the wheel foreword rotation (x axis) works, but I can't manage to make them both work. Do you have any ideas how to make them work together?
float ro = 20f; // 20 degrees turn
//to preserve the x and z values of rotation
Vector3 rot = wheel.gameObject.transform.rotation.eulerAngles;
//rotates the wheels angle
wheel.gameObject.transform.localEulerAngles = new Vector3(rot.x, ro, rot.z);
float vel = wheel.rpm * 2 * Mathf.PI / 60 * Time.deltaTime * Mathf.Rad2Deg;
//rotates the wheels forward
wheel.gameObject.transform.Rotate(vel, 0, 0);
You should not be using localEulerAngles when you are having two different rotations, because when you have 2 movements if you use localEulerAngles you change the local angles with the movements you are providing themselves so you loose the reference of where the angular position of your axis is at.
You can indicate to the rotate method to rotate respect to the world, transform.rotate rotates the transform of your object relative to the world so you can handle simultaneus rotations together because world axis do not change.
Find below the code snippet that I tried, and the picture of my axis orientation which is not exactly the same as yours.
public class WheelTurning : MonoBehaviour
{
float rpm=10f;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
if (Input.GetKeyDown(KeyCode.A))
{
turn(direction.left);
}
if (Input.GetKeyDown(KeyCode.D))
{
turn(direction.right);
}
float vel = this.rpm * 2 * Mathf.PI / 60 * Time.deltaTime * Mathf.Rad2Deg;
rotate(vel);
}
enum direction
{
left,
right
}
void turn(direction dir)
{
Vector3 rot = this.gameObject.transform.rotation.eulerAngles;
//rotates the wheels angle
float rotation = dir == direction.left ? 20f : -20f;
gameObject.transform.Rotate(new Vector3(0, rotation, 0), Space.World);
}
void rotate (float speed)
{
gameObject.transform.Rotate(0, speed, 0);
}
}
However it is much more operative to use quaternions, try to check that out.
Hope that helps!
I do not get your point. If you want to turn a wheel it will alwiys be respect to its previous rotational postion. With that reference you can choose the value you like in the rotation vector Vector3(0, rotation, 0). If you want an absolute reference you can make a parent object and rotate this. Objects have the same world axis and when rotated or transformed, the children "suffer" the same transformation. You have to meke sure that the posistion in the childre is 0,0,0 as this is the distance respect to the parent position that will be the rotation pivot.
void setRotation()
{
Vector3 rot = this.gameObject.transform.rotation.eulerAngles;
GameObject wheelParent = gameObject.transform.parent.gameObject;
Vector3 rotationVector = new Vector3(0, 30, 0);//absolute turn set
Quaternion rotation = Quaternion.Euler(rotationVector);
wheelParent.transform.localRotation = rotation;
}
Hope that helps.

How to throw an object and have it rotate around a sphere as if it were orbiting

I can pick up and throw an object by adding a force to it which throws it in the correct direction the player is facing. If this object was thrown and it's speed is greater than the speed Threshold it starts to RotateAround the planet which works fine.
Now what I'm trying to do is:
If I apply a force to the object whose speed is greater than the speed threshold upon throwing it, the object will go into orbit but not in the correct direction which would be the players forward direction.
Example Video demonstrating the problem when I throw the frisbee (object).
This is my code:
Vector3 planetDir = planet.transform.position - transform.position;
Vector3 axis = Vector3.Cross(Vector3.Normalize(planetDir), transform.forward);
if (rb.velocity.magnitude * 10 > speedThreshold)
{
rb.isKinematic = true;
isOrbiting = true;
}
if (isOrbiting == true)
{
transform.RotateAround(planet.transform.position, axis, rotationSpeed); //start orbiting
desiredAltitude = (transform.position - planet.transform.position).normalized * radius +
planet.transform.position; //set the altitude
transform.position = desiredAltitude; //move this gameobject to desired altitude
}
This seemed to work added a negative sign in front of the transform.forward, So this
Vector3 axis = Vector3.Cross(Vector3.Normalize(planetDir),
transform.forward);
To This
Vector3 axis = Vector3.Cross(Vector3.Normalize(planetDir), -
transform.forward);

Unity 5.1 player control of secondary object relative to player object

I've done a lot of searching but can't find a sollution to this problem.
What I want is to control a game object that rotates around the player object at a fixed distance based on right analogue stick input, indepentant of player movement. I also want the object to face outwards as it moves around the player.
I have left analogue stick set to player movement and working and have right analogue stick set up and tested so I know the input is working.
I've tried transform.rotate, RotateAround, .position and quaternions etc but can't figure it out or find anything that might help. I am fairly new to this so there's probably a simple sollution, I just can't see it!
Appreciate any help you might be able to give :) Thanks a mil
EDIT 2: The second attempt
so I've got this so far now:
public class ShieldMovement : MonoBehaviour {
public Transform target; //player shield is attaced to
float distance = 0.8f; // distance from player so it doesn't clip
Vector3 direction = Vector3.up;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
float angle = Mathf.Atan2 (Input.GetAxisRaw("rightH"), Input.GetAxisRaw("rightV"))* Mathf.Rad2Deg;
if(Input.GetAxis("rightH") != 0f || Input.GetAxis("rightV") != 0f)
{
direction = new Vector3(Input.GetAxis("rightH"),Input.GetAxis("rightV"), 0.0f ) ;
}
Ray ray = new Ray(target.position, direction);
transform.position = ray.GetPoint(distance);
if(Input.GetAxis("rightH") != 0f || Input.GetAxis("rightV") != 0f)
{
transform.rotation = Quaternion.AngleAxis(angle,Vector3.forward*-1);
}
}
}
I'd like it to be a smooth rotation of the shield around the player going to a new location instead of teleporting there. I've tried some lerps and some slerps, so far all I've been able to so is interpolate from one point on the circumference in a direct line to the new point. Can't think of a way to get it to rotate around the player as it does if you just rotate the stick. Hope that makes sense!
Any ideas you wonderful folk you?
Heres two ways of accomplishing what you want
Please note: this has not been tested
With a custom normalized procession (0f is exactly Vector3.forward, 1f brings you back to Vector3.forward)
using UnityEngine;
using System.Collections;
public class Follower : MonoBehaviour {
float distance = 10f;
Vector3 direction = Vector3.forward;
float procession = 0f; // exactly at world forward 0
Transform target;
void Update() {
float circumference = 2 * Mathf.PI * distance;
angle = (procession % 1f) * circumference;
direction *= Quaternion.AngleAxis(Mathf.Rad2Deg * angle, Vector3.up);
Ray ray = new Ray(target.position, direction);
transform.position = ray.GetPoint(distance);
transform.LookAt(target);
}
}
With Input.GetAxis
using UnityEngine;
using System.Collections;
public class Follower : MonoBehaviour {
float distance = 10f;
Vector3 direction = Vector3.forward;
float speed = .01f;
Transform target;
void Update() {
direction *= Quaternion.AngleAxis(Input.GetAxis("Horizontal") * speed * Time.deltaTime, Vector3.up);
Ray ray = new Ray(target.position, direction);
transform.position = ray.GetPoint(distance);
transform.LookAt(target);
}
}

C# Direct X 9.0c - Mesh Intersect

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, ...

Categories

Resources