Screen positions of GUI elements in Unity3D - user-interface

I am using the standard GUI of Unity3D.
How can I get the screen position of a GUI element?

Basically you can't. Using better words, as you already noticed GUI.Button simply returns a bool that indicated if the button has been pressed.
Since you are actually re-creating the button every frame (your GUI.Button code is inside a callback such as Update,FixedUpdate, OnGUI,...), and when you are calling GUI.Button you are passing it the Rect bounds by your self, there isn't actually any need of querying any object to retrieve the actual coordinates. Simply store them somewhere.
Rect buttonBounds = new Rect (50,60,100,20);
bool buttonPressed = GUI.Button (buttonBounds, "get postion");
if (buttonPressed)
{
//you know the bounds, because buttonBounds button has been pressed
}

Try this:
var positionGui : Vector2;
positionGui = Vector2 (guiElement.transform.position.x * Screen.width, guiElement.transform.position.y * Screen.height);

you can do something like this
public static Rect screenRect
(float tx,
float ty,
float tw,
float th)
{
float x1 = tx * Screen.width;
float y1 = ty * Screen.height;
float sw = tw * Screen.width;
float sh = th * Screen.height;
return new Rect(x1,y1,sw,sh);
}
public void OnGUI()
{
if (GUI.Button(screenRect(0.4f, 0.6f, 0.2f, 0.1f), "TRY AGAIN"))
{
Application.LoadLevel(0);
}
print ("button position + framesize"+screenRect(0.4f, 0.6f, 0.2f, 0.1f));
}

Related

Centering an Actor horizontally and vertically causes the bounds to be wrong

I have a button in the center of my stage and want to scale it from the center as soon as the user starts to tap on it and then reset the scale as soon as he releases his finger.
This is the code I use:
private int size;
private Texture texture;
private Action scaleAction, scaleDownAction;
public PlayButtonActor(int x, int y, int size) {
this.size = size;
setBounds(x, y, size, size);
this.texture = new Texture("data/play_button.png");
this.setTouchable(Touchable.enabled);
setOrigin(size / 2, size / 2);
final float finalSize = size;
addListener(new InputListener() {
#Override
public void touchUp(InputEvent event, float x, float y, int pointer, int button) {
event.handle();
removeAction(scaleAction);
scaleDownAction = Actions.parallel(
Actions.scaleTo(1f, 1f, 0.1f)
);
addAction(scaleDownAction);
}
#Override
public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) {
removeAction(scaleDownAction);
scaleAction = Actions.parallel(
Actions.scaleTo(1.4f, 1.4f, 0.2f)
);
addAction(scaleAction);
return true;
}
});
}
#Override
public void draw(Batch batch, float parentAlpha) {
final float realSize = this.getScaleX() * size;
batch.draw(this.texture, this.getX() - realSize / 2, this.getY() - realSize / 2, realSize, realSize);
}
This works as it successfully scales the button, however only the top right quadrant of the button is clickable.
How can I make it so that the button scales from / to the center while the bounds of it are still correct all the time?
Thanks in advance!
Don't set the texture, but add the texture as an Image:
add(new Image(texture));
then scale the image. The clickable Area will always be the full Button size, independant from the image scaling.

Aligning animation with direction Unity

So the problem is when I move the character(he is not humanoid) his walk animation is not aligned with the direction of his movement, for example, if I press W then he moves forward but his walk animation turns 90 degrees left, I have no idea where the problem might be. Here's the code I have:
public class PlayerControler : MonoBehaviour
{
public float MovSpeed = 3;
public float SmoothTime = 0.1f;
float TurnSmoothVelocity;
public float SpeedSmoothTime = 0.1f;
float SmoothVelocity;
float CurrentSpeed;
Animator animator;
void Start()
{
animator = GetComponent<Animator>();
}
void Update()
{
Vector2 Input = new Vector2(UnityEngine.Input.GetAxisRaw("Horizontal"), UnityEngine.Input.GetAxisRaw("Vertical"));
Vector2 InputDirection = Input.normalized;
if (InputDirection != Vector2.zero)
{
float TargetRotation = Mathf.Atan2(InputDirection.x, InputDirection.y) * Mathf.Rad2Deg;
transform.eulerAngles = Vector3.up * Mathf.SmoothDampAngle(transform.eulerAngles.y , TargetRotation, ref TurnSmoothVelocity, SmoothTime);
}
float targetSpeed = MovSpeed * InputDirection.magnitude;
CurrentSpeed = Mathf.SmoothDamp(CurrentSpeed, targetSpeed, ref SmoothVelocity, SmoothTime);
transform.Translate(transform.forward * CurrentSpeed * Time.deltaTime, Space.World);
float animationSpeedPercent = .5f * InputDirection.magnitude;
animator.SetFloat("SpeedPercent", animationSpeedPercent, SpeedSmoothTime, Time.deltaTime);
}
}
The Animated Object should be the Child of the Controller that has this Script assigned.
Just make an EmptyGameObject, add this script and parent your Animated Character under that Object.
If it's still not working correctly there might be something wrong with the Animation. The Script looks right to me.

Processing detecct whether mouse is inside a bouncing circle when clicked

Trying to determine whether the mouse has been clicked within a certain ball and when it is clicked I want to display text that relates to that specific ball, this is what I have so far any help would be appreciated.
int rad = 60; // Width of the shape
float xpos1, ypos1; // Starting position of shape
float xspeed = 4; // Speed of the shape
float yspeed = 4; // Speed of the shape
int xdirection = 1; // Left or Right
int ydirection = 1; // Top to Bottom
boolean overBox1 = false;
void setup()
{
size(1200, 800);
noStroke();
frameRate(30);
ellipseMode(RADIUS);
// Set the starting position of the shape
xpos1 = width/2;
ypos1 = height/2;
}
void draw()
{
background(102);
circleone();
}
void circleone()
{
xpos1 = xpos1 + ( xspeed * xdirection );
ypos1 = ypos1 + ( yspeed * ydirection );
if (xpos1 > width-rad || xpos1 < rad) {
xdirection *= -1;
}
if (ypos1 > height-rad || ypos1 < rad) {
ydirection *= -1;
}
ellipse(xpos1, ypos1, rad, rad);
}
void mouseClick()
{
if (overCircle(xpos1,ypos1,rad)==true)
{
println("YO");
}
}
boolean overCircle(float x, float y, int radius) {
float disX = x - mouseX;
float disY = y - mouseY;
if (sqrt(sq(disX) + sq(disY)) <radius) {
return true;
} else {
return false;
}
}
This logic seems overcomplicated:
float disX = x - mouseX;
float disY = y - mouseY;
if (sqrt(sq(disX) + sq(disY)) <radius)
You could just use the dist() function instead:
return dist(x, y, mouseX, mouseY) < radius;
Then if you want to display some text when the ball is clicked, you're going to have to add more than a println() statement. You might set a boolean variable to true, and then in the draw() function you'd check that variable and draw something to the screen when it's true.
If you're trying to get many clickable balls on the screen, then you might think about creating classes that represent a ball and putting your logic in there.
But you haven't really asked a question. You've posted some code, haven't told us what you expect it to do, what it does instead, or how those two things are different. Stack Overflow isn't really designed for general "how do I do this" type questions. It's for more specific "I tried X, expected Y, but got Z instead" type questions. So you'll have much better luck if you post a MCVE instead of your entire project and ask a specific question about a specific line of code. Good luck.

How to remove previous shape after draw() in Processing

I cant figure this out. I have a sketch with little rotating rectangles on it. They rotate on every draw(). However the previous rectangle remains visible. I tried moving background() around but it either gets rid of all the rectangles apart from one or it doesn't clear the screen. I would like to be able to clear all the rectangles after each draw.
Here is the code:
//Create array of objects
ArrayList<Circle> circles = new ArrayList<Circle>();
ArrayList<Connector> centrePoint = new ArrayList<Connector>();
void setup(){
size(800, 800);
frameRate(1);
rectMode(CENTER);
background(204);
for(int i = 1; i < 50; i++){
float r = random(100,height-100);
float s = random(100,width-100);
float t = 20;
float u = 20;
println("Print ellipse r and s " + r,s);
circles.add(new Circle(r,s,t,u,color(14,255,255),random(360),random(5),random(10)));
}
//Draw out all the circles from the array
for(Circle circle : circles){
circle.draw();
float connectStartX = circle.x1;
float connectStartY = circle.y1;
println("PrintconnectStartX and Y " + connectStartX,connectStartY);
for(Circle circleEnd : circles){
float connectEndX = (circleEnd.x1);
float connectEndY = (circleEnd.y1);
centrePoint.add(new Connector(connectStartX,connectStartY,connectEndX,connectEndY));
}
}
//For each ellipse, add the centre point of the ellipse to array
for(Connector connectUp : centrePoint){
println(connectUp.connectStartX ,connectUp.connectStartY ,connectUp.connectEndX ,connectUp.connectEndY);
stroke(100, 0, 0);
if (dist(connectUp.connectStartX ,connectUp.connectStartY ,connectUp.connectEndX ,connectUp.connectEndY) < 75){
connectUp.draw(connectUp.connectStartX ,connectUp.connectStartY ,connectUp.connectEndX ,connectUp.connectEndY);
}
}
//For the line weight it should equal the fat of the node it has come from ie
//for each circle, for each connectUp if the x==connectStartX and y==connectStartY then make the line strokeWeight==fat
for(Circle circle : circles){
for(Connector connectUp : centrePoint){
if (connectUp.connectStartX == circle.x1 & connectUp.connectStartY == circle.y1 & (dist(connectUp.connectStartX ,connectUp.connectStartY ,connectUp.connectEndX ,connectUp.connectEndY) < 75)){
print(" true "+ circle.fat);
float authority = circle.fat;
strokeWeight(authority*1.5);
connectUp.draw(connectUp.connectStartX ,connectUp.connectStartY ,connectUp.connectEndX ,connectUp.connectEndY);
}
}
}
}
void update(){
}
void draw() {
for(Circle circle : circles){
circle.rot =+0.02;
circle.draw();
circle.rot = random(-6,6);
}
}
//Need to connect each ellipse to all the other ellipses
class Connector {
public float connectStartX;
public float connectStartY;
public float connectEndX;
public float connectEndY;
public color cB;
public float thickness;
public Connector(float connectStartX, float connectStartY, float connectEndX, float connectEndY){
this.connectStartX = connectStartX;
this.connectStartY = connectStartY;
this.connectEndX = connectEndX;
this.connectEndY = connectEndY;
//this.cB = tempcB;
//this.thickness = thickness;
}
void draw(float connectStartX, float connectStartY, float connectEndX, float connectEndY){
line(connectStartX, connectStartY, connectEndX, connectEndY);
// float fat = random(255);
//fill(fat);
stroke(100, 0, 0);
}
}
class Circle{
public float x1;
public float y1;
public float x2;
public float y2;
public color cB;
public float rot;
public float fat = random(5);
public float fert = 0.1;
public Circle(float x1, float y1, float x2, float y2, color tempcB, float rot, float fat, float fert){
this.x1 = x1;
this.y1 = y1;
this.x2 = x2;
this.y2 = y2;
this.cB = tempcB;
//Tilt - I think this is done in radians
this.rot = rot;
//Authority -this is the fill
this.fat = fat;
//Fertility- this is a multiplier for the tilt
this.fert = fert;
}
void draw(){
pushMatrix();
translate(x1, y1);
fert = random(0.5);
rot = random(-6,6);
rotate(rot*fert);
translate(-x1, -y1);
//float fat = random(255);
fill(fat);
rect(x1, y1, 24, 36);
popMatrix();
}
}
You've got a few things going on in your code that I've seen in your previous posts. The way you're doing your drawing doesn't make a ton of sense, and I'll explain why.
Here's what most Processing sketches do:
Use the setup() function to setup any data structures you'll use in your program. Don't do any drawing from the setup() function.
Call background() every frame to clear out old frames.
Draw everything you want to be drawn in the frame in the draw() function.
Modify the data structures to change what you're drawing on the screen.
Your code is a bit too long for an MCVE, so here's a little example that handles the drawing in a more standard way:
ArrayList<PVector> circles = new ArrayList<PVector>();
void setup() {
size(500, 500);
ellipseMode(RADIUS);
//setup your data structures here
circles.add(new PVector(250, 250));
//don't do any drawing yet
}
void mousePressed() {
//modify the data structure whenever you want to change what's on the screen
circles.add(new PVector(mouseX, mouseY));
}
void keyPressed() {
//modify the data structure whenever you want to change what's on the screen
if (!circles.isEmpty()) {
circles.remove(0);
}
}
void draw() {
//call background every frame to clear out old frames
background(0);
//draw everything
for (PVector p : circles) {
ellipse(p.x, p.y, 20, 20);
}
}
Notice how this is different from what you're doing. Here's what you do:
You use the setup() function to setup your data structures, but then you draw the background and some of the objects to the screen.
You then don't call background() from draw(), so you're always stuck with whatever has already been drawn.
You then only draw a subset of what you want on the screen, so you can't redraw your whole scene.
You have to modify your code to no longer draw anything from setup(), to call the background() function every frame, and to draw everything you want on the screen every frame.
What you are doing is printing every single circle or line...ect. You need to have a timer that removes them every so often. If you do it too fast you get a strobe like look. So have a timer that removes the first rect from the array list every so often.

Unity: Changing direction character faces when using InputManager(side scroller)

I'm creating a simple side scroller with a couple people using Unity and am definitely a beginner. The character being used is 3D and runs forward well, but when running backwards he still faces forward. I have the controls setup in the InputManager so pressing A moves backwards and D moves forward but I'm not sure what to do so he faces his respective movement.
Any help would be greatly appreciated and if you need more information besides the following code I have for the movement let me know, it's based off another post I found.
var speed : float = 6.0;
var jumpSpeed : float = 6.0;
var gravity : float = 12.0;
//This variable is now inheriting the Vector3 info (X,Y,Z) and setting them to 0.
private var moveDirection : Vector3 = Vector3.zero;
function MoveAndJump() {
var controller : CharacterController = GetComponent(CharacterController);
if(controller.isGrounded) {
//moveDirection is inheriting Vector3 info. This now sets the X and Z coords to receive the input set to "Horizontal" and "Vertical"
moveDirection = Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical")); //Allows player Input
moveDirection = transform.TransformDirection(moveDirection); //How to move
moveDirection *= speed; //How fast to move
if(Input.GetButtonDown("Jump")) {
animation.Play("Jump");
moveDirection.y = jumpSpeed;
}
}
//Apply gravity
moveDirection.y -= gravity * Time.deltaTime;
//This moves the controller
controller.Move(moveDirection * Time.deltaTime);
if(Input.GetButton("Fire1")){
animation.Play("Attack");
}
if(Input.GetButton("Vertical")){
animation.Play("Run");
}
}
function Update() {
MoveAndJump();
}
For what it's worth another problem I'm having involves having two different animations being able to work at the same time, like run and attack. I figured I should mention while I'm here if anybody knew how to go about that. Thank you again for your time!
I ended up solving this based off a different code I stumbled upon, then called the function inside of Update():
var speed : float;
var jumpSpeed : float;
var gravity : float;
private var moveDirection : Vector3 = Vector3.zero;
function MoveJumpAttack() {
var controller : CharacterController = GetComponent(CharacterController);
if (controller.isGrounded) {
moveDirection = Vector3(Input.GetAxis("Horizontal"), 0, 0);
moveDirection *= speed;
if (moveDirection.sqrMagnitude > 0.01)
transform.rotation = Quaternion.Slerp (transform.rotation, Quaternion.LookRotation (moveDirection), 90);
}
moveDirection.y -= gravity * Time.deltaTime;
controller.Move(moveDirection * Time.deltaTime);
}

Resources