Unity GUI Label show twice for no reason - c#

I'm working on an application where several GUI Label display names of planes.
And here's the result :
The problem is, if I rotate my camera by 180 °, those label are here, like there is a point symmetry :
So my label appear twice, once on the plane, which is good, and a second time, behind the camera.
I check if my script was not added twice, but there is no problem, more strange, if I look from an above view, the problem just disappear :
I have no idea where this can come from, here's my code, who is attached to every plane :
void OnGUI()
{
if (showInfos)
{
Rect r = new Rect((Camera.main.WorldToScreenPoint(gameObject.transform.position)).x+25, Camera.main.pixelHeight - (Camera.main.WorldToScreenPoint(gameObject.transform.position)).y+25, 75f, 75f);
GUI.Label(r, gameObject.transform.root.name);
}
}

You are drawing the labels whether or not they are in the view frustum or not.
From Camera.WorldToScreenPoint (emphasis mine):
Screenspace is defined in pixels. The bottom-left of the screen is (0,0); the right-top is (pixelWidth,pixelHeight). The z position is in world units from the camera.
You need to check if the Z value of the screen point is negative or positive (I don't know which one is in front of cam and which one is behind it, I don't use Unity), and according to that decide if it needs to be rendered or not.
void OnGUI()
{
if (showInfos)
{
var pt = Camera.main.WorldToScreenPoint(gameObject.transform.position);
if (pt.z > 0) //or < 0, no idea.
{
Rect r = new Rect(pt.x + 25, Camera.main.pixelHeight - pt.y + 25, 75f, 75f);
GUI.Label(r, gameObject.transform.root.name);
}
}
}

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.

SkiaSharp Touch Bitmap Image

In the app I'm trying to develop a key part is getting the position of where the user has touched. First I thought of using a tap gesture recognizer but after a quick google search I learned that was useless (See here for an example).
Then I believe I discovered SkiaSharp and after learning how to use it, at least somewhat, I'm still not sure how I get the proper coordinates of a touch. Here are sections of the code in my project that are relevant to the problem.
Canvas Touch Function
private void canvasView_Touch(object sender, SKTouchEventArgs e)
{
// Only carry on with this function if the image is already on screen.
if(m_isImageDisplayed)
{
// Use switch to get what type of action occurred.
switch (e.ActionType)
{
case SKTouchAction.Pressed:
TouchImage(e.Location);
// Update simply tries to draw a small square using double for loops.
m_editedBm = Update(sender);
// Refresh screen.
(sender as SKCanvasView).InvalidateSurface();
break;
default:
break;
}
}
}
Touch Image
private void TouchImage(SKPoint point)
{
// Is the point in range of the canvas?
if(point.X >= m_x && point.X <= (m_editedCanvasSize.Width + m_x) &&
point.Y >= m_y && point.Y <= (m_editedCanvasSize.Height + m_y))
{
// Save the point for later and set the boolean to true so the algorithm can begin.
m_clickPoint = point;
m_updateAlgorithm = true;
}
}
Here I'm just seeing or TRYING to see if the point clicked was in range of the image and I made a different SkSize variable to help. Ignore the boolean, not that important.
Update function (function that attempts to draw ON the point pressed so it's the most important)
public SKBitmap Update(object sender)
{
// Create the default test color to replace current pixel colors in the bitmap.
SKColor color = new SKColor(255, 255, 255);
// Create a new surface with the current bitmap.
using (var surface = new SKCanvas(m_editedBm))
{
/* According to this: https://learn.microsoft.com/en-us/xamarin/xamarin-forms/user-interface/graphics/skiasharp/paths/finger-paint ,
the points I have to start are in Xamarin forms coordinates, but I need to translate them to SkiaSharp coordinates which are in
pixels. */
Point pt = new Point((double)m_touchPoint.X, (double)m_touchPoint.Y);
SKPoint newPoint = ConvertToPixel(pt);
// Loop over the touch point start, then go to a certain value (like x + 100) just to get a "block" that's been altered for pixels.
for (int x = (int)newPoint.X; x < (int)newPoint.X + 200.0f; ++x)
{
for (int y = (int)newPoint.Y; y < (int)newPoint.Y + 200.0f; ++y)
{
// According to the x and y, change the color.
m_editedBm.SetPixel(x, y, color);
}
}
return m_editedBm;
}
}
Here I'm THINKING that it'll start, you know, at the coordinate I pressed (and these coordinates have been confirmed to be within the range of the image thanks to the function "TouchImage". And when it does get the correct coordinates (or at least it SHOULD of done that) the square will be drawn one "line" at a time. I have a game programming background so this kind of sounds simple but I can't believe I didn't get this right the first time.
Also I have another function, it MIGHT prove worthwhile because the original image is rotated and then put on screen. Why? Well by default the image, after taking the picture, and then displayed, is rotated to the left. I had no idea why but I corrected it with the following function:
// Just rotate the image because for some reason it's titled 90 degrees to the left.
public static SKBitmap Rotate()
{
using (var bitmap = m_bm)
{
// The new ones width IS the old ones height.
var rotated = new SKBitmap(bitmap.Height, bitmap.Width);
using (var surface = new SKCanvas(rotated))
{
surface.Translate(rotated.Width, 0.0f);
surface.RotateDegrees(90);
surface.DrawBitmap(bitmap, 0, 0);
}
return rotated;
}
}
I'll keep reading and looking up stuff on what I'm doing wrong, but if any help is given I'm grateful.

Open GUI on Certain HTC VIVE Controller Angle/Turn

I am Trying to make a GUI for HTC VIVE but having trouble in opening it on certain controller angle.
I have done some work and achieved a bit sketchy one because my object is a child which make it hard for me to track its rotation or position, as i wanted it to open only when controller is at certain angle (as a guy looking at his watch)
Here is some visual Example:
This is my controller rotation without GUI:
As i rotate the controller the GUI should show something like this:
Here is some code I have managed
void RayCastFromHead() // is just a name for Method i am raycasting from a dummy which contains left Grip button
{
if (Physics.Raycast(dummy.position, dummy.up, out hitInfo, 30))
{
transform.rotation.ToAngleAxis(out tempAngle, out tempAxis);
if (hitInfo.collider.name.Contains("Camera (eye)"))
{
if (dummy.gameObject.GetComponent<MeshRenderer>().enabled)
{
if ((transform.localEulerAngles.z > 270.0f && transform.localEulerAngles.z < 315.0f)&&
(transform.position.y > 0.9f && transform.position.y < 2f))
{
staticRotaion = transform.localRotation;
canvasOnHead.GetComponent<TweenScale>().PlayForward();
}
}
}
}
}
I do not know that it is a right method to do this kind of task? In Simple manner i want to show GUI on certain controller rotation.
This is My hierarchy what i am talking about
This is the same i wanna do with my GUI it should open when my hand angle is something like this image
There is a simple solution to handle UI rotation.
I suppose you have a canvas for your GUI. This canvas can be child of any object. If you add the canvas (root of this menu) as a child of the left hand it should move and rotate with the left hand.
Note that the render mode of the canvas must be World Space.
This is the parent (left hand):
set the values of canvas's rect transform correctly (most important part is pos.z, I changed the scale of the canvas instead of changing the z. I could change width and height of canvas but it would have adverse effects)
it will behave as you described when rotating the parent object (left hand):
Edit
Add this script to your camera
public class LookAtWatchController : MonoBehaviour
{
public GameObject menuGUI;
public GameObject hand;
void Update(){
if(transform.eulerAngles.x > 10)
{
menuGUI.transform.eulerAngles = new Vector3(transform.eulerAngles.x, 0, 0);
menuGUI.SetActive(true);
menuGUI.transform.position = hand.transform.position;
}
else{
menuGUI.SetActive(false);
}
}
}
assign the gui menu to menuGUI
assign the left hand to hand
you can also include the rotation elements of the hand in the menuGUI rotation:
menuGUI.transform.eulerAngles = new Vector3(transform.eulerAngles.x, hand.transform.eulerAngles.y, hand.transform.eulerAngles.z);
I haven't tested this yet but menuGUI.transform.eulerAngles = new Vector3(transform.eulerAngles.x, 0, 0); should also work fine.
As you see below the rotation.eulerAngles.x of camera and canvas are the same when canvas is seen right in front of camera

Jump animation using animation class

I need a little help in my little 2D game I want to create in XNA. I had almost no knowledge of programming before I got interested in XNA and C#, so maybe my problem is simple, but I just can't figure it out.
So basically, I have a base class, and I created an additional class Animation for animating sprites. I implemented some methods so that when the player presses "right" it would change the animation's current texture and increment X by a number of xf; anyway, the main idea is that I'm using just one instance of my class (basically, one object of type animation which changes its texture and properties based on what key is pressed).
So, I had no problems making it run right or left. Works out pretty well. The big problem started when I wanted to implement the jump sprite. So I created the 6 frames necessary for the sprite, but to animate it I have virtually no idea how to do it.
The only thing it does right now is to loop through the frames of the sprite, but the position (both .X and .Y) remain the same. The thing is, I have a Vector2 position which holds the animation's current position, and it's fine with running because I simply increment it. However, when it comes to jumping, I want it to increment .X, but the .Y should be decremented (thus going up) until frame number 3; after frame number 3, until the last frame, I want the .Y position to go down (thus fall) with the corresponding animations (erm, frames).
So, basically, I don't know how to modify the .X and .Y so that it would display the frames that I need in the time I need. I don't know if you really understood what I'm trying to say; basically when I press the "up" key, it loops through the frames but the position remains the same.
My idea was to use a reference to the actual Vector2 position which holds the animation's current position and pass it to the method in the other Animation.cs class, namely the PlayAnimJump, and modify the position after each frame and return it to the actual Game1.cs by reference. Even if I would do that (though I fail to see what good it would be), it wouldn't be updating the position as it should. So, any ideas?
Here is the code for the PlayAnimJump method from the Animation class:
public void PlayAnimJump(GameTime gameTime)
{
elapsed += (float)gameTime.ElapsedGameTime.Seconds;
sourceRect = new Rectangle(currentFrame * frameWidth, 0, frameWidth, frameHeight);
currentFrame = 0;
if (elapsed >= frameTime)
{
if (currentFrame <=3)
{
if (looping)
{
currentFrame++;
}
}
else if (currentFrame > 3)
{
currentFrame++;
}
elapsed = 0;
}
}
The default constructor for that class:
public Animation(ContentManager Content,string asset,float frameSpeed, int numbOfFrames, bool looping,Vector2 positionIT)
{
this.assetName = asset;
this.frameTime = frameSpeed;
this.numbOfFrames = numbOfFrames;
this.looping = looping;
this.animation = Content.Load<Texture2D>(asset);
frameWidth=(animation.Width / numbOfFrames);
frameHeight=animation.Height;
position = positionIT;
}
Here is the code (from the main) when the up key is pressed:
else if (up)
{
check = animation1.GetAsset();
if (check == "eright")
{
animation1.SetFrameSpeed(0.8f);
animation1.SetNumbOfFrames(6);
animation1.ChangeTexture(Content, "SarimCumVreJiorjica");
animation1.PlayAnimJump(gameTime);
/*position1.x +=2f;
position1.Y -=2f;
*/
}
So, I'm not sure how, but I'm supposed to change position1 according to the frame that's displayed by the animation in that second. Am I missing something?
If your animation class had a reference to the object that you wanted to move (i.e the object holding the position field) then you could modify it within the animation class, within the PlayAnimJump method.
Or, to reduce coupling, you could just have PlayAnimJump return a variable indicating how far into the jump you are (maybe a percentage of the jump, from 0 to 1). Then, you could use the percentage outside to set the objects position. So, if the jump is halfway done, the return value would be 0.5f, which you could use in an equation to determine the players y position. An example equation would be:
float percent = animation1.PlayAnimJump(gameTime);
float y = Math.Sin(percent * Math.PI) * maxJumpHeight;
player.positon.y = y;
This uses a sine wave to determine the players height throughout the jump animation. You would just need to write the code that determines the percentage of the way through the jump (currentFrame) in the PlayAnimJump method and return it.
Formula of the frуefall for Y coordinate is
y = g * t ^ 2 / 2 + v0 * t + y0
Characters jump from height y0 vith start velocity v0 by Y axis and gravity gradually slows down and starts to fall.
Calculate deltaY using following formula
deltaY = g * t ^ 2 / 2 + v0 * t
First show the frame on which the character is pushed off the ground, then the frame on which it rises until it reaches the peak of the jump. Once the sign change deltaY from + to - show how the character change pose for fall. Something like that.

UI and unity position

I have this problem, that I want to be able to click on a "tile" on the screen and then a pop-up menu should be shown just next to the tile. I can click on the tile and then a pop-up menu shows up but not where I want it.
On the picture here I've clicked on the top left one.
My code for placing the picture is as following:
using UnityEngine;
using System.Collections;
public class TowerMenu : MonoBehaviour
{
bool showMenu = false;
float x;
float y;
GUIStyle myStyle;
public Texture2D[] towers;
void OnGUI()
{
if(showMenu)
{
//Bear tower
GUI.Button(new Rect(x + 10, y - 25, 50, 50), towers[0]);
//Seal tower
GUI.Button(new Rect(x + 10, y + 25, 50, 50), towers[1]);
}
}
public void ShowMenu(Vector2 pos)
{
showMenu = true;
x = pos.x;
y = pos.y;
}
}
Hope anyone can help me :)
Sry, i cant comment because i dont have enough rep, this is a comment to Steven Mills answer and comments to that post.
The first error comes because you are calling WorldToViewportPoint as if it was a static member function which it isnt(Think of if you had 2 Cameras you would have to specify which Camera you want, reading up on what a static member is would be helpful here). What you need to do to fix this is get a reference of your MainCamera and call the function from that instance(best method would probably be with a public variable and dragging the camera on the script in the editor)
The second error occurs because you are trying to give a Vector3 to ShowMenu() which requires a Vector2. The third is probably a product of the compiler trying to fix error 2
This is a logical error because the tiles are GameObjects and thus the transform.position are positions in 3d space. What you actually want is the 2d-pixel-position on the screen of your MainCamera. To get this you need to call WorldToScreenPoint instead of WorldToViewportPoint. Sadly, as you will notice you will also get a Vector3 here which is not what you want, but you can just take the x and y coordinates as your pixel screen coordinates. the z-coordinate denotes the distance from the camera.
Hope that clears it up a little instead of confusing you ;D
Feel free to ask again, but also try to read the Unity Script Reference and try to understand what is written there and what it means :)
By the look of it, your ShowMenu method is receiving a pos of (0,0), which is why the two buttons are placed at what seems to be a position of (10,-25) and (10,25) respectively.
Without seeing the code calling ShowMenu I can't be sure what location you're giving, but my guess would be that the tiles belong to a parent object, and you're passing the local position instead of the world position.
If you post the code in which you call ShowMenu I may be able to point out any problems.
EDIT:
Based on the information provided in the comments, the problem is that the position needs converting between the world coordinates and screen coordinates:
void OnMouseDown()
{
if(state == State.water)
{
errorHandler.sendError("You can't click on that");
}
if(state == State.ice)
{
towerMenu.ShowMenu(camera.WorldToViewportPoint(this.transform.position));
}
}
and change the ShowMenu to this:
public void ShowMenu(Vector3 pos)
{
showMenu = true;
x = pos.x;
y = pos.y;
}

Categories