How do I get the mouse position on a gameobject in unity? - c#

I have currently started a developing a pixel art program in unity. I started with getting the mouse coordinates(x, y) on the ui image(texture) I used the code below but the get the mouse position in world space. I wanna get it in the space of the ui image only. The texture image is 32, 32 pixel wide and tall (x, y respected)
[SerializeField] private Text coordinatesText;
private Vector3 mousePos;
private float mouseX, mouseY;
void Update()
{
mousePos = Input.mousePosition;
mouseX = mousePos.x;
mouseY = mousePos.y;
coordinatesText.text = (mouseX + ", " + mouseY).ToString();
}
For like, when I hover the mouse on the very bottom left of the texture, which is a ui image, I get 0, 0 and when it's in the very top right, it's 32, 32.
Thanks in advance for your help!

Depending on the Render Mode your Canvas is set to, the answer differs ever so slightly. I also want to point out, RectTransform by default has a pivot point on its center, so the (0,0) will be in the center, not on the bottom-left.
The function you are looking for is RectTransformUtility. ScreenPointToLocalPointInRectangle. To use it, you need the RectTransform of your UI object, if the Render Mode of your Canvas is set to ScreenSpaceCamera, you will need the camera and the screen space position, which is the mouse position. I mentioned that it was different depending on the RenderMode due to the camera parameter needing to be null if your RenderMode is OverlaySpace for the function to work.
Another note, you will most likely want to implement IHandlers to know when the cursor is inside of the specific UI element.
Here is some example code:
using UnityEngine;
using UnityEngine.EventSystems;
public class TestScript : MonoBehaviour, IPointerClickHandler
{
[SerializeField] private Canvas parentCanvas = null; // the parent canvas of this UI - only needed to determine if we need the camera
[SerializeField] private RectTransform rect = null; // the recttransform of the UI object
// you can serialize this as well - do NOT assign it if the canvas render mode is overlay though
private Camera UICamera = null; // the camera that is rendering this UI
private void Start()
{
if (rect == null)
rect = GetComponent<RectTransform>();
if (parentCanvas == null)
parentCanvas = GetComponentInParent<Canvas>();
if (UICamera == null && parentCanvas.renderMode == RenderMode.ScreenSpaceCamera)
UICamera = parentCanvas.worldCamera;
}
public void OnPointerClick(PointerEventData eventData)
{
// this UI element has been clicked by the mouse so determine the local position on your UI element
RectTransformUtility.ScreenPointToLocalPointInRectangle(rect, eventData.position, UICamera, out Vector2 localPos);
// we now have the local click position of our rect transform, but as you want the (0,0) to be bottom-left aligned, need to adjust it
localPos.x += rect.rect.width / 2f;
localPos.y += rect.rect.height / 2f;
Debug.Log(localPos);
}
}
Here is a gif of the code working in a test scene. The image I have has a width and height of 32. I zoomed in the window so the clicks could be as closer to the edge to show the coordinates are properly set.

Related

Unity: screen space vs window space vs monitor space?

I am trying to take a Ui object's screen space position and translate that to what I am calling 'monitor space'.
As far as I can tell, screen space, in Unity, is relative to the applications' window. That is, even if the app is not full screen, and moved around on your monitor, 0,0 will still be the lower left of the app window.
I need to translate one of those screen space values into the actual position within the user's monitor. This is especially important when considering that the user might have multiple monitors.
I am not finding anything to get this done, though.
I am hoping to find a platform agnostic solution, but if it must be Windows-only than I can make that work as well.
Any help on this would be greatly appreciated.
Thank you
Now after TEEBQNE's answer I also wanted to give it a shot using the native solution.
As mentioned this will be only for Windows PC Standalone and requires
Unity's new Input System (see Quick Start)
One of the solutions from Getting mouse position in c#
For example if you want to use System.Windows.Forms then copy the according DLL from
C:\Windows\Microsoft.NET\Framework64\v4.x.xx
into your project under Assets/Plugins
Then in code you can use
using System.Windows.Forms;
If this is more efficient (or even works this way) I can't tell - only on the phone here - but I hope the idea gets clear ;)
So the idea is:
store initial cursor position
Set your cursor to certain positions of interest using WarpCursorPosition using Unity screen coordinates as input
read out the resulting absolute monitor coordinates using the native stuff
in the end reset the cursor to the original position
This might look somewhat like
using UnityEngine;
using UnityEngine.InputSystem;
public static class MonitorUtils
{
// Store reference to main Camera (Camera.main is expensive)
private static Camera _mainCamera;
// persistent array to fetch rect corners
// cheaper then everytime creating and throwing away a new array
// especially when fetching them every frame
private static readonly Vector3[] corners = new Vector3[4];
// For getting the UI rect corners in Monitor pixel coordinates
public static void GetMonitorRectCorners(this RectTransform rectTransform, Vector2Int[] output, bool isScreenSpaceCanvas = true, Camera camera = null)
{
// Lazy initialization of optional parameter
if (!camera) camera = GetMainCamera();
// Store initial mouse position
var originalMousePosition = Mouse.current.position.ReadValue();
// Get the four world space positions of your RectTtansform's corners
// in the order bottom left, top left, top right, bottom right
// See https://docs.unity3d.com/ScriptReference/RectTransform.GetWorldCorners.html
rectTransform.GetWorldCorners(corners);
// Iterate the four corners
for (var i = 0; i < 4; i++)
{
if (!isScreenSpaceCanvas)
{
// Get the monitor position from the world position (see below)
output[i] = WorldToMonitorPoint(corners[i], camera);
}
else
{
// Get the monitor position from the screen position (see below)
output[i] = ScreenToMonitorPoint(corners[i], camera);
}
}
// Restore mouse position
Mouse.current.WarpCursorPosition(originalMousePosition);
}
// For getting a single Unity world space position in Monitor pixel coordinates
public static Vector2Int WorldToMonitorPoint(Vector3 worldPoint, Camera camera = null)
{
// Lazy initialization of optional parameter
if (!camera) camera = GetMainCamera();
var screenPos = camera.WorldToScreenPoint(worldPoint);
return ScreenToMonitorPoint(screenPos, camera);
}
// For getting a single Unity world space position in Monitor pixel coordinates
public static Vector2Int ScreenToMonitorPoint(Vector3 screenPos, Camera camera = null)
{
// Lazy initialization of optional parameter
if (!camera) camera = GetMainCamera();
// Set the system cursor position there based on Unity screen space
Mouse.current.WarpCursorPosition(screenPos);
// Then get the actual system mouse position (see below)
return GetSystemMousePosition();
}
// Get and store the main camera
private static Camera GetMainCamera()
{
if (!_mainCamera) _mainCamera = Camera.main;
return _mainCamera;
}
// Convert the system mouse position to Vector2Int for working
// with it in Unity
private static Vector2Int GetSystemMousePosition()
{
var point = System.Windows.Forms.Cursor.Position;
return new Vector2Int(point.X, point.Y);
}
}
So you can either simply use
var monitorPosition = MonitorUtils.WorldToMonitorPoint(someUnityWorldPosition);
// or if you already have the `Camera` reference
//var monitorPosition = MonitorUtils.WorldToMonitorPoint(someUnityWorldPosition, someCamera);
or if you already have a screen space position like e.g. in a ScreenSpace Overlay canvas
var monitorPosition = MonitorUtils.ScreenToMonitorPoint(someUnityWorldPosition);
// or if you already have the `Camera` reference
//var monitorPosition = MonitorUtils.ScreenToMonitorPoint(someUnityWorldPosition, someCamera);
or you can get all four corners of a UI element at once using e.g.
var monitorCorners = new Vector2Int [4];
someRectTransform.GetMonitorRectCorners(monitorCorners, isScreenSpaceCanvas);
// or again if you already have a camera reference
//someRectTransform.GetMonitorRectCorners(monitorCorners, isScreenSpaceCanvas, someCamera);
Little example
public class Example : MonoBehaviour
{
[Header("References")]
[SerializeField] private Camera mainCamera;
[SerializeField] private RectTransform _rectTransform;
[SerializeField] private Canvas _canvas;
[Header("Debugging")]
[SerializeField] private bool isScreenSpace;
[Header("Output")]
[SerializeField] private Vector2Int bottomLeft;
[SerializeField] private Vector2Int topLeft;
[SerializeField] private Vector2Int topRight;
[SerializeField] private Vector2Int bottomRight;
private readonly Vector2Int[] _monitorPixelCornerCoordinates = new Vector2Int[4];
private void Awake()
{
if (!mainCamera) mainCamera = Camera.main;
if (!_canvas) _canvas = GetComponentInParent<Canvas>();
isScreenSpace = _canvas.renderMode == RenderMode.ScreenSpaceOverlay;
}
private void Update()
{
if (Keyboard.current.spaceKey.isPressed)
{
_rectTransform.GetMonitorRectCorners(_monitorPixelCornerCoordinates, isScreenSpace);
bottomLeft = _monitorPixelCornerCoordinates[0];
topLeft = _monitorPixelCornerCoordinates[1];
topRight = _monitorPixelCornerCoordinates[2];
bottomRight = _monitorPixelCornerCoordinates[3];
}
}
}
You will see that moving your mouse each and every frame isn't a good idea though ^^
Now you can see the four corners being updated depending on the actual position on the screen.
Note: while Unity Screenspace is 0,0 at the bottom left in normal display pixels 0,0 is actually rather top-left. So you might need to invert these.
Alright first off - sorry for the late response just got back and was able to type up an answer.
From what I have found, this solution does not work in the editor and produces odd results on Mac with retina display. In the editor, the Screen and Display spaces appear to be exactly the same. There is probably a solution to fix this but I did not look into the specifics. As for Mac, for whatever reason, the internal resolution outputted is always half the actual resolution. I am not sure if this is just a retina display bug with Unity or a general Mac bug. I tested and ran this test script on both a Windows computer and Mac with a retina display. I have yet to test it on any mobile platform.
I do not know exactly what you would like to achieve with the values you wish to find, so I set up a demo scene displays the values instead of using them.
Here is the demo script:
using UnityEngine;
using System.Collections.Generic;
using UnityEngine.UI;
public class TestScript : MonoBehaviour
{
[SerializeField] private RectTransform rect = null;
[SerializeField] private List<Text> text = new List<Text>();
[SerializeField] private Canvas parentCanvas = null;
[SerializeField] private Camera mainCam = null;
private void Start()
{
// determine the canvas mode of our UI object
if (parentCanvas == null)
parentCanvas = GetComponentInParent<Canvas>();
// only need a camera in the case of camera space canvas
if (parentCanvas.renderMode == RenderMode.ScreenSpaceCamera && mainCam == null)
mainCam = Camera.main;
// generate initial data points
GenerateData();
}
/// <summary>
/// Onclick of our button to test generating data when the object moves
/// </summary>
public void GenerateData()
{
// the anchored position is relative to screen space if the canvas is an overlay - if not, it will need to be converted to screen space based on our camera
Vector3 screenPos = parentCanvas.renderMode == RenderMode.ScreenSpaceCamera ? mainCam.WorldToScreenPoint(transform.position) : rect.transform.position;
// our object relative to screen position
text[0].text = "Screen Pos: " + screenPos;
// the dimensions of our screen (The current window that is rendering our game)
text[1].text = "Screen dimensions: " + Screen.width + " " + Screen.height;
// find our width / height normalized relative to the screen space dimensions
float x = Mathf.Clamp01(screenPos.x / Screen.width);
float y = Mathf.Clamp01(screenPos.y / Screen.height);
// our normalized screen positions
text[2].text = "Normalized Screen Pos: " + x + " " + y;
// grab the dimensions of the main renderer - the current monitor our game is rendered on
#if UNITY_STANDALONE_OSX
text[3].text = "Display dimensions: " + (Display.main.systemWidth * 2f) + " " + (Display.main.systemHeight * 2f);
// now find the coordinates our the UI object transcribed from screen space normalized coordinates to our monitor / resolution coordinates
text[4].text = "Display relative pos: " + (Display.main.systemWidth * x * 2f) + " " + (Display.main.systemHeight * y * 2f);
#else
text[3].text = "Display dimensions: " + Display.main.systemWidth + " " + Display.main.systemHeight;
// now find the coordinates our the UI object transcribed from screen space normalized coordinates to our monitor / resolution coordinates
text[4].text = "Display relative pos: " + (Display.main.systemWidth * x) + " " + (Display.main.systemHeight * y);
#endif
}
/// <summary>
/// Just for debugging - can be deleted
/// </summary>
private void Update()
{
if (Input.GetKey(KeyCode.A))
{
rect.anchoredPosition += new Vector2(-10f, 0f);
}
if (Input.GetKey(KeyCode.W))
{
rect.anchoredPosition += new Vector2(0f, 10f);
}
if (Input.GetKey(KeyCode.S))
{
rect.anchoredPosition += new Vector2(0f, -10f);
}
if (Input.GetKey(KeyCode.D))
{
rect.anchoredPosition += new Vector2(10f, 0f);
}
}
}
I accounted for the parent canvas being either Overlay or Camera mode and put in a check for an OSX build to adjust to the proper screen dimensions.
Here is a gif of the build on OSX. I set the window to be 1680x1050 and my computer's current resolution is 2880x1800. I had also test it on Windows but did not record it as the example looks nearly identical.
Let me know if you have more questions about the implementation or if there are issues with other platforms I did not test.
Edit: Just realized you want the screen space coordinate relative to the monitor space. I will correct the snippet in a little bit - in a meeting right now.
Edit2: After a bit more looking, it will not be easy to get the exact coordinates without the window being centered or getting the standalone window's position. I do not believe there is an easy way to get this information without a dll, so here is a implementation for mac and a solution for windows.
Currently, the solution I have will only get the screen position if the standalone player is windowed and centered on your screen. If the player is centered on the screen, I know that the center of my monitor is half the dimensions of its resolution, and know that the center point of my window matches up to this point. I can now get the bottom left corner of my window relative to my monitor and not a (0,0) coordinate. As the screen space has the bottom left corner at (0,0), you can now adjust the position to monitor space by adding the position of the newly calculated bottom left position.
Here is the new new GenerateData method:
/// <summary>
/// Onclick of our button to test generating data when the object moves
/// </summary>
public void GenerateData()
{
// the anchored position is relative to screen space if the canvas is an overlay - if not, it will need to be converted to screen space based on our camera
Vector3 screenPos = parentCanvas.renderMode == RenderMode.ScreenSpaceCamera ? mainCam.WorldToScreenPoint(transform.position) : rect.transform.position;
// grab the display dimensions
Vector2 displayDimensions;
// bug or something with mac or retina display on mac where the main.system dimensions are half of what they actually are
#if UNITY_STANDALONE_OSX || UNITY_EDITOR_OSX
displayDimensions = new Vector2(Display.main.systemWidth * 2f, Display.main.systemHeight * 2f);
#else
displayDimensions = new Vector2(Display.main.systemWidth, Display.main.systemHeight);
#endif
// the centerpoint of our display coordinates
Vector2 displayCenter = new Vector2(displayDimensions.x / 2f, displayDimensions.y / 2f);
// half our screen dimensions to find our screen space relative to monitor space
Vector2 screenDimensionsHalf = new Vector2(Screen.width / 2f, Screen.height / 2f);
// find the corners of our window relative to the monitor space
Vector2[] displayCorners = new Vector2[] {
new Vector2(displayCenter.x - screenDimensionsHalf.x, displayCenter.y - screenDimensionsHalf.y), // bottom left
new Vector2(displayCenter.x - screenDimensionsHalf.x, displayCenter.y + screenDimensionsHalf.y), // top left
new Vector2(displayCenter.x + screenDimensionsHalf.x, displayCenter.y + screenDimensionsHalf.y), // top right
new Vector2(displayCenter.x + screenDimensionsHalf.x, displayCenter.y - screenDimensionsHalf.y) // bottom right
};
for (int z = 0; z < 4; ++z)
{
text[z].text = displayCorners[z].ToString();
}
// outputting our screen position relative to our monitor
text[4].text = (new Vector2(screenPos.x, screenPos.y) + displayCorners[0]).ToString();
}
Once you are able to either get or set the windowed screen, you can properly re-orient the lower-left corner relative to the monitor dimensions or you can set the window back to the center point of your monitor. The above snippet would also work for a full-screen player. You would just need to determine how far off the aspect ratio of the player window is to your monitor, which allows you to find how large the black bars would be on the edges.
I assumed what you had wanted was straightforward but from what I can tell an OS-agnostic solution would be difficult. My above solution should work for any platform when the player is windowed if you can either get or set the standalone window position and for any platform that is full-screened with the theoretical approach I mentioned.
If you want more info on how to adjust the implementation for the full-screened window let me know.

How to get color of the pixel I clicked on in Unity? Is there a GetPixel alternative that works with floats?

I'm using a Texture2D to display a map, and I need to get the color of the pixel I clicked on. I used Input.mousePosition to get the float coordinates, but using GetPixel to get the color requires the coordinates to be integers.
I am having trouble with getting GetPixel to find the coordinate that I clicked on.
When using floats and clicking on say, the rightmost side of the texture, I get a number like 27.xxx, but when I cast it to an integer, it displays a coordinate 27 pixels from the leftmost side of the texture. The way floats represent pixels confuses me a great deal, maybe clarifying that would help.
public class ProvinceSelectScript : MonoBehaviour {
public Material SpriteMain;
public Color SelectedCol;
public Color NewlySelectedCol;
public Texture2D WorldColMap;
Vector2 screenPosition;
Vector2 worldPosition;
void Start()
{
WorldColMap = (Texture2D)SpriteMain.GetTexture("_MainTexture");
NewlySelectedCol = Color.blue;
}
private void OnMouseDown()
{
screenPosition = new Vector2(Input.mousePosition.x,Input.mousePosition.y);
worldPosition = Camera.main.ScreenToWorldPoint(screenPosition);
SelectedCol = WorldColMap.GetPixel(((int)(worldPosition.x)+(WorldColMap.width/2)) , (int)((worldPosition.y)+(WorldColMap.height / 2)));
SpriteMain.SetColor("_SelectedProvince", SelectedCol);
SpriteMain.SetColor("_NewlySelectedProvince", NewlySelectedCol);
}
}
The worldPosition in the question isn't calculated in a way that's useful if you're using a perspective camera or if your camera is pointed any direction but directly forward.
To find the world position of the click, the best way to go about that is to use Camera.ScreenPointToRay to calculate the position of the click when intersecting the plane made by the position of the sprite and its local forward.
Either way, a world position does not mean anything to the sprite, which could be positioned anywhere in world space. You should rather use transform.InverseTransformPoint to calculate the local position you're clicking on. At that point, you can then use the spriterenderer's bounds to convert to normalized form (0-1 originating fromt he bottom-left instead of world unit lengths originating from the center).
But, once you have the local sprite position of the click expressed in normalized form, you can try to use GetPixelBilinear to get the color at the UV of (x,y) of the click. If the sprite is super simple, this MAY work. If it is animated or nine-sliced, or anything else it probably won't, and you'll have to reverse-engineer what UV the mouse is actually hovering over.
Camera mainCam;
SpriteRenderer sr;
void Start()
{
WorldColMap = (Texture2D)SpriteMain.GetTexture("_MainTexture");
NewlySelectedCol = Color.blue;
mainCam = Camera.main; // cache for faster access
sr = GetComponent<SpriteRenderer>(); // cache for faster access;
}
private void OnMouseDown()
{
Plane spritePlane = new Plane(transform.position, transform.forward);
Ray pointerRay = Camera.main.ScreenPointToRay(Input.mousePosition);
if (spritePlane.Raycast(pointerRay, out distance))
{
Vector3 worldPositionClick = pointerRay.GetPoint(distance);
Vector3 localSpriteClick = transform.InverseTransformPoint(worldPositionClick);
// convert [(-extents,-extents),(extents,extents)] to [(0,0),(1,1)]
Vector3 localSpriteExtents = sr.sprite.bounds.extents;
localSpriteClick = localSpriteClick + localSpriteExtents ;
localSpriteClick.x /= localSpriteExtents.x * 2;
localSpriteClick.y /= localSpriteExtents.y * 2;
// You clicked on localSpriteClick, on a very simple sprite (where no uv magic is happening) this might work:
SelectedCol = WorldColMap.GetPixelBilinear(localSpriteClick.x, localSpriteClick.y);
SpriteMain.SetColor("_SelectedProvince", SelectedCol);
}

Unity Align prefab to top left (2D Game)

I'm making my first game where obstacles (which are prefabs) are placed by a script into a scene. They are all different sizes in a 2D environment. I am placing them using this code below
Instantiate(normal1, new Vector3(x, y , 0), Quaternion.identity);
This works perfectly, except that I need all of the obstacles to be positioned from the top left. So if I would have 0, 0 for my x and y, only the obstacle's corner would be covering the 0, 0 position, not the entire thing. From the little I've worked with GUI elements, you can align to however you like. Is this the same with prefab, and if so, how? Or can you somehow move the origin of the object?
I assume you are talking about non-UI elements.
The easiest thing would be to give your objects a parent GameObject and arrange them in a way so the parent GameObject already has the pivot where you want it (the top-left corner). You do this by first positioning the (future) parent object correctly and then simply drag the child object into it in the hierachy (while it keeps its current position).
Then in your script you have to use Camera.ScreenToWorldPoint in order to find the top-left screen corner position in the 3D world like
// an optional offset from the top-left corner in pixels
Vector2 PixelOffsetFromTopLeft;
// Top Left pixel is at
// x = 0
// y = Screen height
// and than add the desired offset
var spawnpos = new Vector2(0 + PixelOffsetFromTopLeft.x, Screen.height - PixelOffsetFromTopLeft.y);
// as z we want a given distance to camera (e.g. 2 Units in front)
spawnedObject = Instantiate(Prefab, camera.ScreenToWorldPoint(new Vector3(spawnpos.x, spawnpos.y, 2f)), Quaternion.identity);
Full script I used as example
public class Spawner : MonoBehaviour
{
public GameObject Prefab;
public Vector2 PixelOffsetFromTopLeft = Vector2.zero;
private GameObject spawnedObject;
private Camera camera;
private void Start()
{
camera = Camera.main;
}
private void Update()
{
if (Input.anyKeyDown)
{
// you don't need this I just didn't want to mess up the scene
// so I just destroy the last spawned object before placing a new one
if (spawnedObject)
{
Destroy(spawnedObject);
}
// Top Left pixel is at
// x = 0
// y = Screen height
// and than add the desired offset
var spawnpos = new Vector2(0 + PixelOffsetFromTopLeft.x, Screen.height - PixelOffsetFromTopLeft.y);
// as z we want a given distance to camera (e.g. 2 Units in front)
spawnedObject = Instantiate(Prefab, camera.ScreenToWorldPoint(new Vector3(spawnpos.x, spawnpos.y, 2f)), Quaternion.identity);
}
}
}
This will now always spawn the object anchored to the top left. It will not keep it this way if the camera moves or the window is resized.
If your question was about keeping that position also when the window is resized you can use the same code e.g. in an Update method (later you due to efficiency you should only call it when really needed / window actually was resized) like
public class StickToTopLeft : MonoBehaviour
{
private Camera camera;
public Vector2 PixelOffsetFromTopLeft = Vector2.zero;
private void Start()
{
camera = Camera.main;
}
// Update is called once per frame
private void Update()
{
var spawnpos = new Vector2(0 + PixelOffsetFromTopLeft.x, Screen.height - PixelOffsetFromTopLeft.y);
// This time simply stay at the current distance to camera
transform.position = camera.ScreenToWorldPoint(new Vector3(spawnpos.x, spawnpos.y, Vector3.Distance(camera.transform.position, transform.position)));
}
}
This now keeps the object always anchored to the top-left corner also after resizing the window and allows to adjust its offset afterwards.

Scale ingame color picker

Hey,
I am working on a 3D room editor where you can grab an object from a menu and put it back in a room. You also get the option to give these objects a different color, this is done by the color picker. I now have a script that works the way I want it only if I enlarge the color picker, then he does not pick up the colors anymore and he does not move the selector circle anymore.
How do I solve this?
GIF Color picker at 1.8 scale
GIF Color picker at above 2 scale
Color picker script:
Color[] Data;
SpriteRenderer SpriteRenderer;
GameObject ColorPicker;
GameObject Selector;
BoxCollider Collider;
public GameObject target;
Ray rayray;
private Plane MyPlane;
public int Width { get { return SpriteRenderer.sprite.texture.width; } }
public int Height { get { return SpriteRenderer.sprite.texture.height; } }
public Color Color;
void Awake()
{
ColorPicker = transform.Find("ColorPicker").gameObject;
SpriteRenderer = ColorPicker.GetComponent<SpriteRenderer>();
Selector = transform.Find("Selector").gameObject;
Collider = ColorPicker.GetComponent<BoxCollider>();
Data = SpriteRenderer.sprite.texture.GetPixels();
Color = Color.white;
Debug.Log(Collider);
MyPlane = new Plane(transform.TransformDirection(Vector3.forward), transform.position);
}
void Update()
{
if (Input.GetMouseButton(0))
{
rayray = Camera.main.ScreenPointToRay(Input.mousePosition);
MyPlane = new Plane(transform.TransformDirection(Vector3.forward), transform.position);
Vector3 screenPos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
screenPos = new Vector3(screenPos.x, screenPos.y);
//check if we clicked this picker control
RaycastHit[] ray = Physics.RaycastAll(rayray.origin, rayray.direction);
foreach (RaycastHit h in ray)
{
Debug.Log(h.collider.name);
if (h.collider.name == "ColorPicker")
{
Selector.transform.position = screenPos;
//get color data
screenPos -= ColorPicker.transform.position;
int x = (int)(screenPos.x * Width);
int y = (int)(screenPos.y * Height) + Height;
if (x > 0 && x < Width && y > 0 && y < Height)
{
Color = Data[y * Width + x];
target.GetComponent<Renderer>().material.color = Color;
Debug.Log(Width);
Debug.Log(Height);
}
}
}
}
}
EDIT:
GIF
This is the inspector from the color picker color field
This is the inspector from the main camera
IMAGE:
This is the inspector from the color picker color field
This is the inspector from the main camera
It is hard to know for sure without seeing your scene in the Unity editor but I have a few things I would check that may solve your problem.
Check to make sure that when you are scaling your GameObject that the BoxCollider is being scaled correctly. You should be able to see the Gizmo when selecting your GameObject after you scale it. Make sure it is covering the same areas of the UI before/after you scale it. The BoxCollider is used to detect mouse clicks on the object as a whole and unless the ray hits that collider, none of the other functionality will work.
It doesn't look like the script is taking into account scale changes for the color picker. Take a look where you get your X/Y coordinates for picking the color (under the //get color data comment). You will notice it multiplies the screen position by Height and Width which are taken from the size of your texture. This would need to be scaled accordingly to sample the correct area of the texture.
If you still can't get it to work, I would suggest posting a screen shot of your scene hierarchy and relevant GameObjects so we can see how it is all setup.

something wrong with rotation controls in 2d top down shooter in unity3d

I am trying to get my character to face the mouse by rotating on its y axis. It rotates a little, but it do not face the mouse. The Camera's position is directly above the player, and its in orthographic view I see many other examples of top down shooters and there almost exactly like mine so i don't know whats the problem please help thank you.
using UnityEngine;
using System.Collections;
public class playermovementscript : MonoBehaviour {
public float movementspeed = 5f;
public float bulletspeed = 10f;
public GameObject bullet;
public GameObject shooter;
public Vector3 target;
public Camera camera;
// Use this for initialization
void Start () {
//refrence to main camera
Camera camera;
}
// Update is called once per frame
void Update () {
//call movement function in every frame
movement ();
// cheek for input of f in every frame if true execute shoot function
if (Input.GetKeyDown (KeyCode.F)) {
shoot();
}
}
void movement(){
// makes refrence to gameobjects rigidbody and makes its velocity varible to equal values of axis x and y
gameObject.GetComponent<Rigidbody>().velocity = new Vector3(Input.GetAxisRaw("Horizontal")*movementspeed,0,Input.GetAxisRaw("Vertical")*movementspeed);
// makes vector 3 type target equall to mouse position on pixial cordinates converted in to real world coordniates
target = camera.ViewportToWorldPoint (new Vector3(Input.mousePosition.x,Input.mousePosition.y,camera.transform.position.y - transform.position.y));
//target.x -= transform.position.x;
//target.z -= transform.position.z;
// states the vector 3 values of target
Debug.Log (target);
// makes object local z face target and iniziates up axis
transform.LookAt (target,Vector3.up);
}
Going to make an attempt to explain what's going on...
target = camera.ViewportToWorldPoint (new Vector3(Input.mousePosition.x,Input.mousePosition.y,camera.transform.position.y - transform.position.y));
The above code is trying to convert a mouse position which is in Screen Space (which measures the position from (0,0) to the width/height of the screen in pixels) to a Viewport Space (which measure the same screen but with a different measure, it measures the positions from (0,0) to (1,1)).
In Unity
Screen Space Measurement: Origin (0,0) to the max width/height
Viewport Measurement: Origin (0,0) to (1,1)
Reference: http://docs.unity3d.com/ScriptReference/Camera.html
If you desire to still use "ViewportToWorldPoint" then you could do a "ScreenToViewportPoint" then follow it with a "ViewPortToWorldPoint".
Otherwise, you could look into using "ScreenToWorldPoint" from the start.

Categories