LWJGL mouse hover and clickable text

Hi,

I am trying to create a menu for my game using strings as buttons, however, I dont know how to get the color of a string to change if it is moused over, and how to tell if it has been clicked on or not

Here is some of the menu code

	public void draw() {
		Color.white.bind();
		loadText();
		backg();
			
		handleInput();
		
		for(int i = 0; i < options.length; i++) {
		font.drawString(Display.getWidth() / 2 - 250, Display.getHeight() - 150, "Play", Color.black);
		font.drawString(Display.getWidth() / 2 - 200, Display.getHeight() - 100, "Options", Color.black);
		font.drawString(Display.getWidth() / 2- 100, Display.getHeight() - 50, "Quit", Color.black);
		}
		
		cleanUp();
	}

Thanks,

  • Dan

This can be done with the Rectangle library. You make two rectangles, one for the text (x, y, width, height) and the mouse (x, y, 1, 1).

You can check intersection by calling Rectangle.intersects(Rectangle rect)

Ok I gave it a shot, but I got a bit stuck,

Here is my new code:

	public Rectangle rect, mouse;

	public void draw() {
		Color.white.bind();
		loadText();
		backg();
			
		handleInput();
		
		for(int i = 0; i < options.length; i++) {

		rect.setBounds(Display.getWidth() / 2 - 250, Display.getHeight() - 150, 100, 32);
		mouse.setBounds(Display.getWidth() / 2 - 250, Display.getHeight() - 150, 1, 1);

		font.drawString(Display.getWidth() / 2 - 250, Display.getHeight() - 150, "Play", Color.black);
		font.drawString(Display.getWidth() / 2 - 200, Display.getHeight() - 100, "Options", Color.black);
		font.drawString(Display.getWidth() / 2- 100, Display.getHeight() - 50, "Quit", Color.black);
		}
		if(currentChoice == 0) {
			font.drawString(Display.getWidth() / 2 - 250, Display.getHeight() - 150, "Play");
		}
		else if(currentChoice == 1) {
			font.drawString(Display.getWidth() / 2 - 200, Display.getHeight() - 100, "Options", Color.yellow);
		}
		else if(currentChoice == 2) {
			font.drawString(Display.getWidth() / 2- 100, Display.getHeight() - 50, "Quit", Color.yellow);
		}
		cleanUp();
	}
	
	public void handleInput() {
		if(Mouse.isInsideWindow()) {
			if(mouse.intersects(rect)) {
				font.drawString(Display.getWidth() / 2 - 250, Display.getHeight() - 150, "Play", Color.green);
			}
		}

	}

What am I doing wrong?

Thanks,
-Dan

First, without understanding what the rest of your class is doing and what the other variables like ‘options’, ‘mouse’, ‘currentChoice’, etc. are, all I can do is make assumptions;

So, assuming that ‘currentChoice’ uses an integer to represent which menu item the mouse is currently hovered over, then we need a conditional statement to print only that menu item in a different color;
The following code may work, but again, I’m only assuming based on your variable names and current code, since I don’t have enough code to test anything;


	public Rectangle rect, mouse;

	public void draw() {
		Color.white.bind();
		loadText();
		backg();

		handleInput();
		Color colorSelected = Color.black;

		if(currentChoice == 0) {
			colorSelected = Color.yellow;
		}

		font.drawString(Display.getWidth() / 2 - 250, Display.getHeight() - 150, "Play", colorSelected);
		colorSelected = Color.black;

		if(currentChoice == 1) {
			colorSelected = Color.yellow;
		}

		font.drawString(Display.getWidth() / 2 - 200, Display.getHeight() - 100, "Options", colorSelected);
		colorSelected = Color.black;

		if(currentChoice == 1) {
			colorSelected = Color.yellow;
		}

		font.drawString(Display.getWidth() / 2- 100, Display.getHeight() - 50, "Quit", colorSelected);

		cleanUp();
	}

	public void handleInput() {
		if(Mouse.isInsideWindow()) {
			if(mouse.intersects(rect)) {
				// Something to do with 'currentChoice' should maybe go here? Or does it get set somewhere else...
			}
		}
	}

What is currentChoice and how does it get set to 0-2?
Why are the string drawing commands in a for loop of and what is ‘options’?

Your current if-else statements are aimed in the right direction, but some of your drawing commands are running twice since the for loop runs all the commands at least once and then the if-else statements possibly run them again;

Ok, this is options and currentChoice, the variables rect and mouse are not actually doing anything because Im not sure how to use them, oh and any idea how I can change Color.yellow to a rgb or hex value? I tried Color(1, 1, 1) but that doesnt work

	private String[] options = {
		"Play",
		"Options",
		"Quit"
	};
	
	private void select() {
		if(currentChoice == 0) {
		Game.state = State.RAND;
		}
		else if(currentChoice == 1) {

		}
		else if(currentChoice == 2) {
			Display.destroy();
			System.exit(0);
		}
	}

Any ideas? thanks very much for your help,

  • Dan

Any ideas?

Thanks

  • Dan

[quote]any idea how I can change Color.yellow to a rgb or hex value?
[/quote]
[icode]
int argb = ((a & 0xFF) << 24) | ((r & 0xFF) << 16) | ((g & 0xFF) << 8) | ((b & 0xFF));
[/icode]
and the reverse:
[icode]
int a = (argb & 0xFF000000) >> 24;
int r = (argb & 0x00FF0000) >> 16;
int g = (argb & 0x0000FF00) >> 8;
int b = (argb & 0x000000FF);
[/icode]

Also see http://docs.oracle.com/javase/7/docs/api/java/awt/Color.html#getRGB()
And: http://docs.oracle.com/javase/7/docs/api/java/lang/Integer.html#toHexString(int)

EDIT: for your mouse-rectangle intersection, just use [icode]rect.contains(mouseX, mouseY)[/icode]

How would I implement that color code?

and here is the new input code, but its null for some reason

	   public void draw() {
	      Color.white.bind();
	      loadText();
	      backg();

	      handleInput();


	      rect.setBounds(Display.getWidth() / 2 - 250, Display.getHeight() - 150, 100, 32);
	      if(currentChoice == 0) {
	         colorSelected = Color.yellow;
	      }

	      font.drawString(Display.getWidth() / 2 - 250, Display.getHeight() - 150, "Play", colorSelected);
	      colorSelected = Color.black;

	      if(currentChoice == 1) {
	         colorSelected = Color.yellow;
	      }

	      font.drawString(Display.getWidth() / 2 - 200, Display.getHeight() - 100, "Options", colorSelected);
	      colorSelected = Color.black;

	      if(currentChoice == 1) {
	         colorSelected = Color.yellow;
	      }

	      font.drawString(Display.getWidth() / 2- 100, Display.getHeight() - 50, "Quit", colorSelected);

	      cleanUp();
	   }
    public void handleInput() {
		      if(Mouse.isInsideWindow()) {
		    	 if(rect.contains(Mouse.getDX(), Mouse.getDY()))
		    		 mouse.intersects(rect);
		    	 colorSelected = Color.green;
		      }
		   }
	   

Ideas?

Thanks,

  • Dan

Ah, just realized you’re using LWGL :-X

I’m unfortunantly not very familar with LWJGL, but read this thread for LWJGL color stuff, should answer your question: http://www.java-gaming.org/index.php?topic=30108.0

Also remove the [icode]mouse.intersects(rect);[/icode] line and you should be good.

Edit for your edit: (Damn, ninja’s by Z-Man while off in notepad)


public class MenuButton {
      
      //change these to whatever
      public static final Color COLOR_SELECTED = Color.green;
      public static final Color COLOR_UNSELECTED = Color.black;

      public Rectangle rect;
      public String text;

      public MenuButton(String s, Rectangle r) {
            test = s;
            rect = r;
      }
}


public void draw() {
    Color.white.bind();
    loadText();
    backg();
    
    for(MenuButton button: menuButtons) { //menuButtons is an ArrayList<MenuButton>
        if(Mouse.isInsideWindow() && button.rect.contains(Mouse.getX(), Mouse.getY())
            colorSelected = MenuButton.COLOR_SELECTED;
        else
            colorSelected = MenuButton.COLOR_UNSELECTED;
        font.drawString(button.rect.getX(), button.rect.getY(), button.text, colorSelected);
    }
    cleanUp();
}

An approach that I use and would suggest would be to encapsulate the code related to the different options in their own class. For example a Button class that knows it’s position, it’s bounds, knows what color it should be, and manages it’s own drawing. Then you simply create a Button for each option, position them, and update them as to the location of the mouse (or simply check it’s bounds against the mouse position). The Button class can then take care of deciding what color it should be and how to draw itself. Here is a rough sudo-code example to illustrate my point and to show you a couple ways you could implement this:


// Update cycle
for(Button btn : buttons)
   btn.setMouseOver(btn.getBounds().contains(mouseX, mouseY));

//==========================================================//

// Alternative update cycle
for(Button btn : buttons)
   btn.updateMousePos(mouseX, mouseY); // Or whatever method name

updateMousePos(int x, int y) {
   mouseOver = bounds.contains(x,y);
}

//==========================================================//

// Render cycle
for(Button btn : buttons)
   btn.render();

render() {
   if(mouseOver)
      // Set text color one way
   else
      // Set text color the other way

   // Draw text
}

EDIT: As for your question about Color, it looks like you’re using Slick2D so you can refer to the javadoc for Slick2D’s Color class here. A brief glance looks like you can use the getRed() getGreen() getBlue() and getAlpha() methods to get the RGB components.

^ See my edit-edit-then-ninja’d above for exactly what Z-Man is talking about, and what I agree would be a good course of action.

Ok I have tried to use your code, but I dont think I am using it correctly, here have a look:

    public static class MenuButton {
        
        //change these to whatever
        public static final Color COLOR_SELECTED = Color.green;
        public static final Color COLOR_UNSELECTED = Color.black;

        public Rectangle rect;
        public String text;

        public MenuButton(String s, Rectangle r) {
              text = s;
              rect = r;
        }
  }

	public void draw() {
	    Color.white.bind();
	    loadText();
	    backg();
	    	    
	    for(MenuButton button: menuButtons) { //menuButtons is an ArrayList<MenuButton>
	        if(Mouse.isInsideWindow() && button.rect.contains(Mouse.getX(), Mouse.getY()))
	            colorSelected = MenuButton.COLOR_SELECTED;
	        else
	            colorSelected = MenuButton.COLOR_UNSELECTED;
	        font.drawString(button.rect.getX(), button.rect.getY(), button.text, colorSelected);
		    font.drawString(Display.getWidth() / 2 - 250, Display.getHeight() - 150, "Play", colorSelected);
	    }
	    cleanUp();
	}

I cant quite figure out what I am doing wrong :confused:
Thanks,

  • Dan

Check if mouse is on top of the button atm. If it is, render it with hovered color.
Check if mouse is on top of the button and if left mouse button was clicked. If it was, perform certain function.

Isnt it already doing that? Sorry I havent done any mouse things before :confused:

Thanks,

  • Dan

Any ideas?

We’re almost there, thanks,

  • Dan

Its very simple really. I’m sorry, but now is the time to figure it out, we have given you many solutions already. Why do you call cleanup after select is run? That makes no sense. You should not be drawing the strings in the for loop. Why is MenuButton static? That will cause a lot of issues. What is loadText()? There are so many things that could be messing this up, you need to post your full code for that class.

Also, if you really only have ~3 months of programming experience, you should really think about coming back to game dev in a few months. It seems you have the right intentions when it comes to your code (how your write it), but it also seems you don’t knows about a few basic programming guidelines or rules/whatever. Its only going to get harder from here on out, and not having a good grip on the language is just going to screw you up later on!

I highly recommend getting a good, solid programming book, such as Code Complete; it will teach you not just a language, but fundamental aspects of programming such as design patterns, how to recognize and approach different types of problems, and software as a product of construction and design, rather than simply writing. That being said a good book about the language you use in particular is also a good idea.
Online resources are great, but I don’t think they are an equal substitute for a good book.

That’s what I was trying to say, thank you!
In addition to getting a book, make sure you code a lot, but try to write your code with the new functions and design patterns you will learn about. There’s a lot more to coding than if statements and loops, and you really need to learn about them before you starting messing with games. Game development pretty much requires you to know about almost every aspect of your language of choice because of its nature. Networking/Graphics/File IO/Sound etc… You need to know everything. Its a very rewarding experience though, and you’ll learn a lot about programming in general!

I like to think of gamedev as interdisciplinary. At least that [comic] is what it seems like to me sometimes. :wink: