Drawing a sprite on Raycast collision point - c#

I am trying to emit a raycast from the player object and project a crosshair texture onto the world position the crosshair is aimed at. The crosshair should not overlap with the player and it should also only be emited in front of the Player gameObject.
I have tried this so far:
private float range = 100f;
public Texture crosshair;
private Rect crosshairPos;
void Update()
{
if (Input.GetKeyDown(KeyCode.Space))
{
Shoot();
}
Ray ray = new Ray(transform.position, transform.forward);
crosshairPos.x = ray.GetPoint(100f).x;
crosshairPos.y = ray.GetPoint(100f).y;
Graphics.DrawTexture(crosshairPos, crosshair);
Edit: After some testing, I am currently on the following snippet of code:
void Update()
{
if (Input.GetKeyDown(KeyCode.Space))
{
Shoot();
}
Ray ray = new Ray(transform.position, transform.forward);
crosshairPos.x = ray.GetPoint(5f).x;
crosshairPos.y = ray.GetPoint(5f).y;
crosshairPos = Camera.main.WorldToScreenPoint(crosshairPos);
Vector2 crosshairPosSize = new Vector2(crosshair.width, crosshair.height);
Graphics.DrawTexture(new Rect((Vector2)crosshairPos, crosshairPosSize), crosshair);
}
I am however still unable to see a projected crosshair.

When you use a Ray from a GameObject you get a Vector in the world coordinate system. (The game world where your player is).
Graphics.DrawTexture() uses screen coordinates to draw the texture on screen.
Consider using Camera.Main.WorldToScreenPoint to change the world points that you get from Ray into points you can display on screen.
Here's an example of that
Vectors crosshairPos = new Vector3();
void Update()
{
if (Input.GetKeyDown(KeyCode.Space))
{
Shoot();
}
Ray ray = new Ray(transform.position, transform.forward);
crosshairPos.x = ray.GetPoint(100f).x;
crosshairPos.y = ray.GetPoint(100f).y;
crosshairPos = Camera.Main.WorldToScreenPoint(crosshairPos);
Graphics.DrawTexture((Vector2)crosshairPos, crosshair);
}

Related

How can I detect transparent areas in a sprite in Unity

I have a 1024x1024 pixel sprite with some transparent areas in it. I am rendering it on a game scene using Sprite Renderer. Is there any way check whether the pixel at mouse position is transparent or not when the mouse is hovered over it.
We could cast ray and get the world position of our hit point, Here I am assuming your SpriteRenderer has a collider.
private RaycastHit CastRay()
{
RaycastHit hit;
Ray ray = _camera.ScreenPointToRay(Input.mousePosition);
Physics.Raycast(ray, out hit);
return hit;
}
Then we need a method to convert that world space into texture coordinates
public Vector2 TextureSpaceCoord(Vector3 worldPos) {
float ppu = _sprite.pixelsPerUnit;
Vector2 localPos = transform.InverseTransformPoint(worldPos) * ppu;
var texSpacePivot = new Vector2(_sprite.rect.x, _sprite.rect.y) + _sprite.pivot;
Vector2 texSpaceCoord = texSpacePivot + localPos;
return texSpaceCoord;
}
Once we get the texture coordinates we could just use GetPixel() of Texture2D to get the color
private void PickColor()
{
RaycastHit hit = CastRay();
if (hit.collider != null)
{
Vector2 coord = TextureSpaceCoord(hit.point);
Color selectedColor = _sprite.texture.GetPixel((int) coord.x, (int) coord.y);
// Here you can check if color is transparent
if(selectedColor == Color.clear){
// do stuff
}
}
}
You could call the PickColor() in Update(), _camera would be Camera.main and _sprite would be the Sprite of your SpriteRenderer

Raycasting from the camera center doesn't work

I'm using the following code to raycast from the center of the camera.
using UnityEngine;
using System.Collections;
[RequireComponent(typeof(Camera))]
public class CameraPointer : MonoBehaviour {
private GameObject hitObject = null;
private Vector3 reticlePosition = Vector3.zero;
public Camera mcamera;
public float Distance = 10f;
void Update () {
reticlePosition = mcamera.transform.position;
Ray ray = mcamera.ScreenPointToRay(reticlePosition);
RaycastHit hit;
if (Physics.Raycast(ray, out hit, Distance)) {
if (hitObject != hit.transform.gameObject) {
if (hitObject != null) {
hitObject.SendMessage("OnReticleExit", SendMessageOptions.DontRequireReceiver);
}
hitObject = hit.transform.gameObject;
hitObject.SendMessage("OnReticleEnter", SendMessageOptions.DontRequireReceiver);
} else {
hitObject.SendMessage("OnReticleHover", SendMessageOptions.DontRequireReceiver);
}
} else {
if (hitObject != null) {
hitObject.SendMessage("OnReticleExit", SendMessageOptions.DontRequireReceiver);
}
hitObject = null;
}
}
}
Unfortunately, it doesn't work at all. It is not hitting any object at all. How can I sort this out?
Ray ray = mcamera.ScreenPointToRay(reticlePosition);
this function is the wrong approach.
vector3 parameter in screenpoint should be the GameScreen Position(ex:coordinate at screen 1920x1080)
So, you have to use function mcamera.ViewportPointToRay(new Vector3(0.5f,0.5f));
or you can use
if (Physics.Raycast(reticlePosition, transform.forward,out hit Distance))...
The reason why this may note be working as you intended is that you're projecting a ray from screen space to world space when you call:
Ray ray = mcamera.ScreenPointToRay(reticlePosition);
See the docs here
So if mcamera is located at the origin, you're Raycasting from the bottom left corner of the screen.
If you want to just cast a ray from the center of the camera's viewport, then something like this would work:
Ray ray = new Ray(mcamera.transform.position, mcamera.transform.forward);
This basically casts a ray along the forward vector of the camera starting at the camera's current position.

How to make the tank look to the side of the mouse and shoot where the player clicks?

I have a tank in a 3rd person 3D game so my camera is looking at the tank from above and a bit from the side. I need the turret of my tank to rotate on the y-axis so that it always looks at the mouse and shoot where the player clicks. The problem is that my game is 3D and all I get is that it actually looks at the mouse (like upwards to the sky).
This is the code I have now:
private Vector3 target;
private Camera cam;
private void Start()
{
cam = Camera.main;
}
void Update()
{
Vector2 mousePos = new Vector2();
mousePos.x = Input.mousePosition.x;
mousePos.y = Input.mousePosition.y;
target = cam.WorldToScreenPoint(new Vector3(mousePos.x, mousePos.y, cam.nearClipPlane));
transform.LookAt(target);
}
Your problem lies here: target = cam.WorldToScreenPoint(new Vector3(mousePos.x, mousePos.y, cam.nearClipPlane));
What you actually need to do is generate a ray that comes out of the camera with ScreenPointToRay(), then do a Physics.Raycast() with that ray and get the RaycastHit from it. Then set the target equal to the RaycastHit.
For example:
Ray screenRay;
RaycastHit screenRayHit;
float maxRaycastDistance;
screenRay = cam.ScreenPointToRay(mousePos.x, mousePos.y);
if(Physics.Raycast(screenRay, out screenRayHit, maxRaycastDistance))
{
target = screenRayHit;
}
else
{
//just sets the turret to aim at the endpoint of the ray if you aim at nothing
target = screenRay.GetPoint(maxRaycastDistance);
}

How to limit/Clamp RotateAround for camera movement in Unity?

I have a scene with a globe, where the camera rotates around the globe. I need to clamp the position and rotation of this movement in certain instances of the game. I have tried several methods but none have worked. My code is below:
private void LateUpdate()
{
if (Input.GetMouseButtonDown(1))
mouseStartPosition = GetMouseHit();
if (mouseStartPosition != null)
DragPlanet();
if (Input.GetMouseButtonUp(1))
StaticPlanet();
}
public void RotateCamera(Vector3 dragStartPosition, Vector3 dragEndPosition)
{
//normalised for odd edges
dragEndPosition = dragEndPosition.normalized *planetRadius;
dragStartPosition = dragStartPosition.normalized * planetRadius;
// Cross Product
Vector3 cross = Vector3.Cross(dragEndPosition, dragStartPosition);
// Angle for rotation
float angle = Vector3.SignedAngle(dragEndPosition, dragStartPosition, cross);
//Causes Rotation of angle around the vector from Cross product
holderTransform.RotateAround(planet.transform.position, cross, angle);
}
private static Vector3? GetMouseHit()
{
RaycastHit hit;
int layer_mask = LayerMask.GetMask("Planet"); //raycasting on the planet
if (Physics.Raycast(Camera.main.ScreenPointToRay(Input.mousePosition), out hit, Mathf.Infinity, layer_mask))
{
return hit.point;

Unity calculate 3D Mouse position

I'm trying to make a C# script for a free throw ball game and need to get the mouse position in the world, and it should be in 3D to be able to throw in all 3 axes. I'm kinda new to scripting and the script I wrote works, but not right. I am not sure how to get the depth or the y axis working, because the screen is only 2d .
using UnityEngine;
using System.Collections;
public class ShootBall : MonoBehaviour {
private Rigidbody rb;
private RaycastHit hit;
private Vector3 com;
private Vector3 shootDirection;
void Start () {
rb = GetComponent<Rigidbody>();
}
void Update () {
}
void OnMouseDown (){
com = rb.worldCenterOfMass;
Debug.Log (com);
}
void OnMouseDrag (){
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
Debug.Log(ray);
Physics.Raycast(ray, out hit);
}
void OnMouseUp (){
shootDirection = com - hit.point;
rb.AddForce (shootDirection * 100);
}
}
The distance from the camera needs to be set on the z-value of the vector being passed into ScreenPointToRay. The reason why Input.mousePosition works as a parameter for ScreenPointToRay is because Vector2 can be implicitly cast to Vector3. So try doing something like this:
float distanceFromCamera = Vector3.Distance(ballGameObject.transform.position, Camera.main.transform.position);
Vector3 inputPosition = new Vector3(Input.mousePosition.x, Input.mousePosition.y, distanceFromCamera);
Ray ray = Camera.main.ScreenPointToRay(inputPosition);
ballGameObject is the gameObject reference to the ball that will be thrown.

Categories