Draw GUI.Label to mouse position - c#

Hey i wondered if you can draw GUI.Label to mouse position, and how you can do it?
I'am currently doing the script in Unity C#.
Script layout:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Test : MonoBehaviour {
public bool Hover = false;
void OnMouseOver()
{
Hover = true;
}
void OnMouseExit()
{
Hover = false;
}
void OnGUI()
{
if(Hover = true)
{
GUI.Label(new Rect(//Transform to mouse positon))
}
}
}

Use Input.mousePosition to create the Rect that is passed to GUI.Label. Note that both of these use screen coordinates but for Input.mousePosition the bottom-left of the screen is (0, 0), and for the Rect used by GUI.Label the top-left of the screen is (0, 0). Thus, you need to flip the y-values like this:
void OnGUI()
{
var mousePosition = Input.mousePosition;
float x = mousePosition.x;
float y = Screen.height - mousePosition.y;
float width = 200;
float height = 200;
var rect = new Rect(x, y, width, height);
GUI.Label(rect, "Test");
}
For more information, see Unity's documentation on Input.mousePosition and GUI.Label

You need to convert screen coordinates (mouse position) to GUI ones.
void OnGUI()
{
if(Hover = true)
{
Vector2 screenPos = Event.current.mousePosition;
Vector2 convertedGUIPos = GUIUtility.ScreenToGUIPoint(screenPos);
GUI.Label(new Rect(convertedGUIPos.x, convertedGUIPos.y, width, height))
}
}
I have not actually tested the code though.
More info here:
https://docs.unity3d.com/ScriptReference/GUIUtility.ScreenToGUIPoint.html

Related

¿How to get the bottomLeft and the topRight bounds of an sprite in Unity?

First, i will explain myself...
I was trying to make an script for the camera to follow the player and keep itself inside the Map.
After a litle research i found out that you can use a property of tileMap called tileMap.localBounds.min to find the bottomLeft corner and tileMap.localBounds.max to find the topRight corner of a tilemap.
The problem with that is that my map is not a tileMap, it`s a sprite.
So i try the following...
public Transform target;
public GameObject theMap;
private Vector3 bottomLeftLimit;
private Vector3 topRightLimit;
// These values are for the camera
private float halfHeight;
private float halfWidth;
void start()
{
target = PlayerController.instance.transform;
halfHeight = Camera.main.orthographicSize;
halfWidth = halfHeight * Camera.main.aspect;
// We assign the corners of our map
// Maybe we`ll have to change the image for a tileMap to use: tileMap.localBounds
bottomLeftLimit = theMap.GetComponent<SpriteRenderer>().sprite.bounds.min + new Vector3(halfWidth, halfHeight, 0f);
topRightLimit = theMap.GetComponent<SpriteRenderer>().sprite.bounds.max + new Vector3(-halfWidth, -halfHeight, 0f);
// We send the bound limits to the PlayerController script to keep the player inside the map
PlayerController.instance.SetBounds(theMap.GetComponent<SpriteRenderer>().sprite.bounds.min, theMap.GetComponent<SpriteRenderer>().sprite.bounds.max);
}
void LateUpdate()
{
transform.position = new Vector3(target.position.x, target.position.y, transform.position.z);
// Keep the camera inside the bounds
transform.position = new Vector3(Mathf.Clamp(transform.position.x, bottomLeftLimit.x, topRightLimit.x), Mathf.Clamp(transform.position.y, bottomLeftLimit.y, topRightLimit.y), transform.position.z);
}
But it seems that the value of sprite.bounds.max and sprite.bounds.min are always 0 (the center), so it doesn`t work to set the bounds for the camera.
Anyone can help? I would aprecciate it a lot...
SpriteBoundsFinder.cs
using UnityEngine;
using UnityEngine.UI;
public class SpriteBoundsFinder : MonoBehaviour
{
public Image image;
private void Update()
{
var rectTransform = image.GetComponent<RectTransform>();
var sizeDelta = rectTransform.sizeDelta;
var position = image.transform.position;
var bottomLeft = position - new Vector3(sizeDelta.x / 2, sizeDelta.y / 2);
var topRight = position + new Vector3(sizeDelta.x / 2, sizeDelta.y / 2);
Debug.Log($"bottomLeft: {bottomLeft}, topRight: {topRight}");
}
}
You can use this to find the bottom left and top right corner of a sprite in world space. Assuming you're using an overlay canvas. If not, let me know.
The reason this works is because a sprite will always be stretched to have the same width and height as the RectTransform of its Image component's GameObject.

Updating Texture During Movement

I'm new to this so not completely sure whether I am posting this correctly, but I have been having a few issues when creating my game. My main goal is to create a topdown shooter styled game, using movement where the 'player' rotates based on the current position of the mouse and can press 'w' to move towards it at a set speed.
The main issue is, when the game loads, the movement works exactly how I want it to, but the texture itself is not moving, but only the drawRectangle.
Game1.cs:
player = new Player(Content, #"graphics\Player1", 500, 500, spritePosition);
spritePosition = new Vector2(player.CollisionRectangle.X, player.CollisionRectangle.Y);
protected override void Update(GameTime gameTime)
{
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed || Keyboard.GetState().IsKeyDown(Keys.Escape))
Exit();
KeyboardState keyboard = Keyboard.GetState();
MouseState mouse = Mouse.GetState();
IsMouseVisible = true;
distance.X = mouse.X - spritePosition.X;
distance.Y = mouse.Y - spritePosition.Y;
//Works out the rotation depending on how far away mouse is from sprite
rotation = (float)Math.Atan2(distance.Y, distance.X);
// TODO: Add your update logic here
spritePosition = spriteVelocity + spritePosition;
spriteOrigin = new Vector2(player.DrawRectangle.X / 2, player.DrawRectangle.Y / 2);
if (Keyboard.GetState().IsKeyDown(Keys.W))
{
spriteVelocity.X = (float)Math.Cos(rotation) * tangentialVelocity;
spriteVelocity.Y = (float)Math.Sin(rotation) * tangentialVelocity;
}
else if(spriteVelocity != Vector2.Zero)
{
Vector2 i = spriteVelocity;
spriteVelocity = i -= friction * i;
}
This is the main movement code from the Update function as well as where the new player has been created.
Player.cs:
class Player
{
Texture2D sprite;
Rectangle drawRectangle;
int health = 100;
public Player(ContentManager contentManager, string spriteName, int x , int y, Vector2 velocity)
{
LoadContent(contentManager, spriteName, x, y, velocity);
}
public Rectangle CollisionRectangle
{
get { return drawRectangle; }
}
public Rectangle DrawRectangle
{
get { return drawRectangle; }
set { drawRectangle = value; }
}
public int Health
{
get { return health; }
set {
health = value;
if (health <= 0)
health = 0;
if (health > 100)
health = 100;
}
}
public Vector2 Velocity
{
get { return Velocity; }
set { Velocity = value; }
}
public void Update(GameTime gameTime, KeyboardState keyboard, MouseState mouse)
{
}
public void Draw(SpriteBatch spriteBatch)
{
spriteBatch.Draw(sprite, drawRectangle, Color.White);
}
private void LoadContent(ContentManager contentManager, string spriteName, int x, int y, Vector2 velocity)
{
sprite = contentManager.Load<Texture2D>(spriteName);
drawRectangle = new Rectangle(x - sprite.Width / 2, y - sprite.Height / 2, sprite.Width, sprite.Height);
}
}
I didn't know what to include in the Update function of the player.cs, whether the code for movement should go in there or the main Game1.cs.
Hopefully this is enough code for you guys to be able to help. Sorry for there being quite a lot of code, but I'm just unsure where the error is occurring.
Thanks in advance
For the rotation you would want to use 'another' kind of spriteBatch.Draw, because the draw function can have more parameters than your currently using.
The full draw function is as followed:
SpriteBatch.Draw(Texture2D texture, Vector2 position, Rectangle sourceRectangle, Color color, float rotation, Vector2 origin, float scale, SpriteEffects effects, float layerdepht)
As you can see, now we have a parameter for rotation that can be used.
So your code will look something like this:
spriteBatch.Draw(sprite, drawRectangle, null, Color.White, rotation, Vector2.Zero, 1, SpriteEffects.None, 0);
As for your question for where your code should go. It is good to learn yourself to put the code where it belongs, in this case the player. Because when your programs become bigger, it would be very messy to do it this way.
To call the update function in your player class, you can just simply call player.Update(gameTime, keyboard, mouse) in the Update of Game1.

My axes won't show up

I'm trying to implement a class drawing a 3D indicator such as this one :
indicating the current rotation of the camera by drawing each axis at every frame as if it was in 3D.
However, when my code runs I just can't see anything being drawn. When I try to draw it in Update() nothing is appearing on the screen but I still can see "The axes have been drawn in Update" showing up in the console. I tried to do it in OnPostRender() but it doesn't seem to be triggered, "The axes have been drawn" doesn't show up in the console.
What could I be doing wrong ?
using UnityEngine;
using System.Collections;
using System.IO;
using UnityEngine.UI;
public class AxesManager : MonoBehaviour {
private static readonly int DEFAULT_AXIS_LENGTH = 100;
private Material _xMaterial;
private Material _yMaterial;
private Material _zMaterial;
private Vector3 _origin;
private int _length;
// Use this for initialization
void Start () {
UpdateMaterials();
_origin = GetAxesOrigin();
_length = DEFAULT_AXIS_LENGTH;
}
// Update is called once per frame
void Update () {
//ClearAxes();
//DrawAxes();
//Debug.Log("The axes have been drawn in Update");
}
void OnPostRender()
{
DrawAxes();
Debug.Log("The axes have been drawn");
}
private void DrawAxes()
{
//draw x axis
GL.PushMatrix();
GL.MultMatrix(transform.localToWorldMatrix);
_xMaterial.SetPass(0);
GL.LoadOrtho();
GL.Begin(GL.LINES);
GL.Color(Color.green);
GL.Vertex(_origin);
GL.Vertex(new Vector3(_length, 0, 0));
GL.End();
GL.PopMatrix();
//draw y axis
GL.PushMatrix();
GL.MultMatrix(transform.localToWorldMatrix);
_yMaterial.SetPass(0);
GL.LoadOrtho();
GL.Begin(GL.LINES);
GL.Color(Color.red);
GL.Vertex(_origin);
GL.Vertex(new Vector3(0, _length, 0));
GL.End();
GL.PopMatrix();
//draw z axis
GL.PushMatrix();
GL.MultMatrix(transform.localToWorldMatrix);
_zMaterial.SetPass(0);
GL.LoadOrtho();
GL.Begin(GL.LINES);
GL.Color(Color.blue);
GL.Vertex(_origin);
GL.Vertex(new Vector3(0, 0, _length));
GL.End();
GL.PopMatrix();
}
private void ClearAxes()
{
//clear the axes here
}
private Vector3 GetAxesOrigin()
{
return new Vector3(100,100,0);
}
private void UpdateMaterials()
{
_xMaterial = Resources.Load("Materials" + Path.DirectorySeparatorChar + "XAxisMaterial", typeof(Material)) as Material;
_yMaterial = Resources.Load("Materials" + Path.DirectorySeparatorChar + "YAxisMaterial", typeof(Material)) as Material;
_zMaterial = Resources.Load("Materials" + Path.DirectorySeparatorChar + "ZAxisMaterial", typeof(Material)) as Material;
}
}
EDIT : After having attached the script to a camera (rendering the top layer), I can now see OnPostRender() being triggered, but nothing shows up and no errors. What could it be ?

How to detect mouse click on GUITexture in unity

I am trying to add controls through mouse in place of keyboard in the game.
I added 4 movement keys and 1 fire button through the GUI texture in unity.
In the game there is already a player controller which controls the player through keyboard strokes
I didnt get, how to make the player move if the direction button (GUITexture) is clicked
Button Script
using UnityEngine;
using System.Collections;
public class RightButton : MonoBehaviour {
public Texture2D bgTexture;
public Texture2D airBarTexture;
public int iconWidth = 32;
public Vector2 airOffset = new Vector2(10, 10);
void start(){
}
void OnGUI(){
int percent = 100;
DrawMeter (airOffset.x, airOffset.y, airBarTexture, bgTexture, percent);
}
void DrawMeter(float x, float y, Texture2D texture, Texture2D background, float percent){
var bgW = background.width;
var bgH = background.height;
GUI.DrawTexture (new Rect (x, y, bgW, bgH), background);
var nW = ((bgW - iconWidth) * percent) + iconWidth;
GUI.BeginGroup (new Rect (x, y, nW, bgH));
GUI.DrawTexture (new Rect (0, 0, bgW, bgH), texture);
GUI.EndGroup ();
}
}
I am unable to add the GUI Button in place of GUI.DrawTexture, its giving invalid argument error
and so i am unable to add how to check the button is clicked or not
Thanks
GUITexture is part of the legacy GUI system. An example of how to get this to work as a button is here.
using UnityEngine;
using System.Collections;
public class RightButton : MonoBehaviour {
public Texture bgTexture;
public Texture airBarTexture;
public int iconWidth = 32;
public Vector2 airOffset = new Vector2(10, 10);
void start(){
}
void OnGUI(){
int percent = 100;
DrawMeter (airOffset.x, airOffset.y, airBarTexture, bgTexture, percent);
}
void DrawMeter(float x, float y, Texture texture, Texture background, float percent){
var bgW = background.width;
var bgH = background.height;
if (GUI.Button (new Rect (x, y, bgW, bgH), background)){
// Handle button click event here
}
var nW = ((bgW - iconWidth) * percent) + iconWidth;
GUI.BeginGroup (new Rect (x, y, nW, bgH));
GUI.DrawTexture (new Rect (0, 0, bgW, bgH), texture);
GUI.EndGroup ();
}
}

Having problems drawing animations in monogame

I am trying to create a spaceship with multiple animations (idle, attack, damaged, etc)
But when I'm trying to change the animations I see the first frame of the current animation for a split second on the "old" position (where the animation was changed the last time)
Picture for explanation: http://i.imgur.com/L3O8rsc.png
The red rectangle is supposed to be a health bar.
The class that runs my animations:
using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
namespace Test
{
class Animation
{
Texture2D spriteStrip;
float scale;
int elapsedTime;
int frameTime;
int frameCount;
int currentFrame;
Color color;
// The area of the image strip we want to display
Rectangle sourceRect = new Rectangle();
// The area where we want to display the image strip in the game
Rectangle destinationRect = new Rectangle();
public int FrameWidth;
public int FrameHeight;
public bool Active;
public bool Looping;
public Vector2 Position;
public void Initialize(Texture2D texture, Vector2 position, int frameWidth, int frameHeight, int frameCount, int frametime, Color color, float scale, bool looping)
{
this.color = color;
this.FrameWidth = frameWidth;
this.FrameHeight = frameHeight;
this.frameCount = frameCount;
this.frameTime = frametime;
this.scale = scale;
Looping = looping;
Position = position;
spriteStrip = texture;
elapsedTime = 0;
currentFrame = 0;
Active = true;
}
public void Update(GameTime gameTime)
{
if (Active == false) return;
elapsedTime += (int)gameTime.ElapsedGameTime.TotalMilliseconds;
if (elapsedTime > frameTime)
{
currentFrame++;
if (currentFrame == frameCount)
{
currentFrame = 0;
if (Looping == false)
Active = false;
}
elapsedTime = 0;
}
sourceRect = new Rectangle(currentFrame * FrameWidth, 0, FrameWidth, FrameHeight);
destinationRect = new Rectangle((int)Position.X - (int)(FrameWidth * scale) / 2, (int)Position.Y - (int)(FrameHeight * scale) / 2, (int)(FrameWidth * scale), (int)(FrameHeight * scale));
}
public void Draw(SpriteBatch spriteBatch)
{
if (Active)
{
spriteBatch.Draw(spriteStrip, destinationRect, sourceRect, color);
}
}
}
}
The reason that I wrote the whole code is because I don't know where the problem is.
In my Game1.cs class I have:
Global Variables:
Texture2D playerTexture;
Texture2D playerShootingTexure;
Animation playerAnimation = new Animation();
Animation ShootingAnimation = new Animation();
...
protected override void LoadContent()
{
spriteBatch = new SpriteBatch(GraphicsDevice);
playerTexture = Content.Load<Texture2D>("Graphics/Player/PlayerShip");
playerShootingTexure = Content.Load<Texture2D>("Graphics/Player/Player_Shooting");
playerAnimation.Initialize(playerTexture, Vector2.Zero, playerTexture.Width / 5, playerTexture.Height, 5, 50, Color.Wheat, 1f, true);
ShootingAnimation.Initialize(playerShootingTexure, Vector2.Zero, playerShootingTexure.Width / 5, playerShootingTexure.Height, 5, 50, Color.WhiteSmoke, 0.75f, true);
}
Where I change the animations:
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
// Start drawing
spriteBatch.Begin();
if (Player_Attacking == false)
{
player.PlayerAnimation = playerAnimation;
}
else
{
player.PlayerAnimation = ShootingAnimation;
}
player.Draw(spriteBatch);
spriteBatch.End();
base.Draw(gameTime);
}
Note: Player_Attacking is a boolean variable. When 'Space' is pressed, the value of the variable changes to TRUE, when 'Space' is released, value is FALSE
Please help!
Thanks in advance!
And sorry for huge wall of text
I'm a little unclear on the exact issue, so maybe you can help clarify if I'm not understanding.
But based on your picture, it seems when you press space to fire, the player animation should change to light up his gun with blue flames (or w/e it is :)) And it looks like it is doing that, but it's in the wrong position (above the health bar - I see the laser it is shooting is in the right location :))
But then it corrects itself once the shooting is done, as shown by the second picture (no more blue flames).
So this implies the Animation for the Player Shooting is using the wrong position.
Are you:
Updating your Player Shooting Animation's Position in your Player Update?
Calling your Player Shooting Animation's Update in your Player Update?
so you should have this somewhere in your Player Update
PlayerAnimation.Position = Position;
PlayerAnimation.Update(gameTime);
Also, try moving the check for which Player Animation to use in the Update of your Game1.cs:
protected override void Update(GameTime gameTime)
{
if (Player_Attacking == false)
{
player.PlayerAnimation = playerAnimation;
}
else
{
player.PlayerAnimation = ShootingAnimation;
}
player.Update(gameTime);
}

Categories

Resources