I am creating a game with a few friends, and I am currently working on the main menu. I figured out how to get regular old TextButtons, but ImageTextButtons are giving me a very hard time. I have two microphone images, one on and one off, and it should change when the user clicks it. I used a Texture Packing program, as part of this tutorial: https://www.youtube.com/watch?v=YPxd_xbnIpk
One of the numerous solutions I've been using is as follows:
MenuState Class-
Private skin = new Skin;
TextureAtlas buttonAtlas = new TextureAtlas ("mutebuttons.pack");
skin.addRegions(buttonAtlas);
TextButtonStyle buttonStyle = new TextButtonStyle();
ImageTextButtonStyle buttonStyle2 = new ImageTextButtonStyle();
buttonStyle.up = skin.getDrawable("soundIconON");
buttonStyle.down = skin.getDrawable("soundIconOFF");
muteButtons.pack contains the on and off mic image already (soundIconON/OFF).
Let me know if you require any more info, and thanks ahead of time.
Ed
Buttons check them selfs automatically. You don't need to do anything special and can always get the checked state by .isChecked. A button starts by default unchecked but you can change the button to checked when you create it by setChecked(true).
If you want to change the look of a button depending on it's checked state all you have to do is add the drawable. Internally it does something like If no checked state image just use default image.
Now for the type of button I think you will be fine with just a image button but any of the buttons can create a button with changeable looks. The ImageButton just allows you to add a image over the background of the button. These are the styles for the 3 different buttons:
TextButton.TextButtonStyle textButtonStyle =
new TextButton.TextButtonStyle(
Drawable up, //Background for up state
Drawable down, //background for down state
Drawable checked, //background for checked == true
BitmapFont font); //font
ImageButton.ImageButtonStyle imageButtonStyle =
new ImageButton.ImageButtonStyle(
Drawable up,
Drawable down,
Drawable checked,
Drawable imageUp, //Image for up state
Drawable imageDown, //Image for down state
Drawable imageChecked, //Image for checked == true
BitmapFont font);
//Never actually used this one, you made me aware of it's excistance. I think this is a redundant class.
ImageTextButton.ImageTextButtonStyle imageTextButtonStyle =
new ImageTextButton.ImageTextButtonStyle(
Drawable up,
Drawable down,
Drawable checked,
BitmapFont font);
So all you need to do is set the checked drawable and start clicking the button.
You can set these in a skin files as well, just call the proper drawable names from json. This is how I create a simple toggle button using text button.
com.badlogic.gdx.scenes.scene2d.ui.TextButton$TextButtonStyle:
{
default: { up: my_up_button, checked: my_checked_button, font: default-font, fontColor: white }
}
If I don't want text over it just hand a empty string. Alternatively you can alter the text on a click as well.
final TextButton button = new TextButton("Ewwww! Touch me!", skin);
button.addListener(new ClickListener() {
#Override
public void clicked(InputEvent event, float x, float y) {
super.clicked(event, x, y);
if (button.isChecked())
{
button.setText("Now I am unchecked!");
}
else
{
button.setText("Now I am checked!");
}
}
});
Related
I have the following basic GUI for demonstration:
I'm trying to achieve the following functionality but I've exhausted all avenues that I've attempted.
User can left click on any of the ImageView's and it will create an
arrow that follows the user's cursor around until the user let's go of
the mouse button. (arrow start x,y is where he clicked and end x,y is
where his mouse currently is) If the user clicked on the Red
ImageView and dragged it over the Blue ImageView and then let go,
the program would print User just clicked from R to B
If the user clicked on the Red ImageView and let go of the mouse but
was not over a different ImageView, the program would print User
just clicked from R but did not target a different ImageView.
Under all circumstances, the arrow will appear when the user clicks on
the ImageView and will disappear the second he lets go of the mouse.
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.Pane;
import javafx.scene.shape.Line;
import javafx.stage.Stage;
import java.util.HashMap;
public class Test extends Application
{
public static int HEIGHT = 500, WIDTH = 600;
#Override
public void start(Stage primaryStage) throws Exception
{
ImageView blue = new ImageView(new Image("blue.png")),
red = new ImageView(new Image("red.png")),
dark = new ImageView(new Image("dark.png"));
// Final array as to bypass the `final` requirement of event handler inner classes.
final ImageView[] hoveredOver = new ImageView[1];
final Line[] linePtr = new Line[1];
linePtr[0] = new Line();
linePtr[0].setStrokeWidth(10);
HashMap<ImageView, Character> lookup = new HashMap<ImageView, Character>(3)
{{
put(blue, 'B');
put(red, 'R');
put(dark, 'D');
}};
for (ImageView i : new ImageView[] { blue, red, dark })
{
i.setFitWidth(150);
i.setFitHeight(150);
// Set the anchor points of the click and display the arrow.
i.setOnMousePressed(e -> {
linePtr[0].setStartX(e.getX());
linePtr[0].setStartY(e.getY());
linePtr[0].setVisible(true);
});
// Move the arrow as the mouse moves.
i.setOnMouseDragged(e -> {
linePtr[0].setEndX(e.getX());
linePtr[0].setEndY(e.getY());
});
i.setOnMouseReleased(e -> {
// Not null means that the user WAS actually just now hovering over an imageview.
if (hoveredOver[0] != null)
System.out.printf("The user clicked from %c to %c!\n", lookup.get(i), lookup.get(hoveredOver[0]));
// Null means the user is not over an ImageView.
else
System.out.printf("The user initially clicked %c but did not drag to another Imageview.\n", lookup.get(i));
linePtr[0].setVisible(false);
});
// If the user enters ANY of the ImageViews,
// Set a variable so that the drag release listener
// can know about it!
i.setOnMouseDragOver(e -> hoveredOver[0] = i);
i.setOnMouseDragExited(e -> hoveredOver[0] = null);
}
blue.setX(400);
blue.setY(250);
red.setY(300);
red.setX(50);
/*
In this example I'm using a Pane but in my real program
I might be using a VBOX HBOX etc where I cannot freely move stuff around as I'd like.
This makes things extremely difficult and without using a 'Pane'
I don't know how this can even be done. Suggestions?
*/
Pane pneRoot = new Pane(blue, red, dark, linePtr[0]);
Scene scene = new Scene(pneRoot, WIDTH, HEIGHT);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args)
{
launch(args);
}
}
This was my best attempt and it's not even close. It moves a line (not an arrow, and ideally I want my arrow to curve as it moves much like this example image from a popular video game) but does not suit my needs. It cannot detect however when I let go while 'dragging over' an ImageView.
Is there a better way to do this? I feel like I can't simply the code I have down any further but there MUST be another way.
Java is an object-oriented language. The basic idea is that you create classes to represent the data you are modeling and then create objects from those classes. If you are tying things together with arbitrary maps to look things up, and arrays kicking around for no apparent reason, you are starting in the wrong place.
JavaFX has a system of observable properties. These wrap objects in a mutable way and can be observed so you can respond to changes.
Make sure you read and understand the documentation on MouseEvents and MouseDragEvents. There are three different modes for handling dragging. For events (mouse drag events) to be sent to nodes other than the one on which the drag was initiated during a mouse drag, you need to be in full "press-drag-release gesture" mode. You can activate this mode by calling startFullDrag() on the node when responding to a dragDetected event.
I would start with something like
public class NamedDragAwareImageView {
private final ObjectProperty<NamedDragAwareImageView> source ;
private final ObjectProperty<NamedDragAwareImageView> destination ;
private final String name ;
private final ImageView imageView ;
public NamedDragAwareImageView(ObjectProperty<NamedDragAwareImageView> source,
ObjectProperty<NamedDragAwareImageView> destination,
String name, String resource) {
this.source = source ;
this.destination = destination ;
this.name = name ;
this.imageView = new ImageView(new Image(resource));
imageView.setOnDragDetected(e -> {
source.set(this);
destination.set(null);
imageView.startFullDrag();
});
imageView.setOnMouseDragReleased(e -> {
if (source.get() != null && source.get() != this) {
destination.set(this);
}
});
// other image view config...
}
public ImageView getView() {
return imageView ;
}
public String getName() {
return name ;
}
}
Then you can do things like:
// observable properties to represent start and end nodes for drag:
ObjectProperty<NamedDragAwareImageView> source = new SimpleObjectProperty<>();
ObjectProperty<NamedDragAwareImageView> destination = new SimpleObjectProperty<>();
Pane root = new Pane();
// create your named image views, referencing the source and destination
// and add their image views to root, e.g.
NamedDragAwareImageView red = new NamedDragAwareImageView(source, destination, "Red", "red.png");
root.getChildren().add(red.getView());
// recommend using SVG paths (i.e. javafx.scene.shape.Path) for the arrow
// easy to draw programmatically, easy to manipulate elements etc:
Path arrowHead = new Path();
MoveTo arrowHeadStart = new MoveTo();
arrowHead.getElements().add(arrowHeadStart);
arrowHead.getElements().addAll(/* draw an arrow head with relative path elements... */);
arrowHead.setVisible(false);
// avoid arrowHead interfering with dragging:
arrowHead.setMouseTransparent(true);
// this will contain a MoveTo and a bunch of LineTo to follow the mouse:
Path arrowLine = new Path();
arrowLine.setMouseTransparent(true);
root.getChildren().addAll(arrowHead, arrowLine);
// change listener for source. source is set when drag starts:
source.addListener((obs, oldSource, newSource) -> {
if (newSource == null) return ;
arrowHeadStart.setX(/* x coord based on newSource */);
arrowHeadStart.setY(/* similarly */);
arrowHead.setVisible(true);
});
// change listener for destination. destination is only set
// when drag complete:
destination.addListener((obs, oldDestination, newDestination) -> {
if (newDestination != null) {
System.out.println("User dragged from "+source.get().getName()+
" to "+destination.get().getName());
}
});
root.setOnMouseDragOver(e -> {
if (source.get()==null && destination.get()!=null) {
// update arrowStart position
// add line element to arrowLine
}
});
root.setOnMouseReleased(e -> {
// clear arrow:
arrowHead.setVisible(false);
arrowLine.getElements().clear();
});
So I have a game I am working on and once you finish playing I want to be able for the user to tap on the "Play Again" button and be able to reset at the start.
To do this I create a Rectangle over the Texture and use the contains() method.
if(cloud.contains((float)Gdx.input.getX(),(float)(Gdx.graphics.getHeight()-Gdx.input.getY()))){
reset();
}
Reset method:
public void reset(){
speed=0;
paraY = Gdx.graphics.getHeight() - para[parachuteState].getHeight();
gameState=0;
backY = 0-Gdx.graphics.getHeight();
bach=0;
Gdx.input.setCursorPosition(Gdx.graphics.getWidth()/2,Gdx.graphics.getHeight()/2);
}
So what is happening is the program recognizes the button being pressed and resets but when the game is over again it automatically resets without displaying the end screen. I think that the cursor is not being moved to the center and is instead remaining on top of the button. Am I incorrectly using the setCursorPosition() method or is there another way to do this?
The button would be just right. It might looks more complex, but it's recommended way to do what you want to do.
So, to create a button you should do something like this:
Skin skin = new Skin();
skin.addRegions(uiTextureAtlas);
TextButton.TextButtonStyle buttonStyle = new TextButton.TextButtonStyle();
buttonStyle.up = skin.getDrawable("textureName");
buttonStyle.font = font;
Button button = new Button(buttonStyle);
button.addListener(new InputListener() {
#Override
public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) {
reset();
return true;
}
});
button.setSize(100, 100);
button.setPosition(300, 400);
then in your Screen class you create
Stage stage = new Stage();
stage.addActor(button);
Gdx.input.setInputProcessor(stage);
I have TextView and I want to draw Rounded Rectangle shape programmatically and I want to set that shape as a Background of TextView? and I want to change it colors dynamically, I have posted the picture ?
public static void makeRoundCorner(int bgcolor,int radius,View v,int strokeWidth,int strokeColor)
{
GradientDrawable gdDefault = new GradientDrawable();
gdDefault.setColor(bgcolor);
gdDefault.setCornerRadius(radius);
gdDefault.setStroke(strokeWidth, strokeColor);
v.setBackgroundDrawable(gdDefault);
}
here View v = your textview or button or anything.
I have a platform button the game screen, and I'm trying to make it so the user presses it once, clicks somewhere on the screen to draw one platform, and then if they clicked the screen again, nothing would happen.
Right now, before I click the platform button, nothing happens which is what I want. When I press the platform button, the user can click the screen to draw a platform, but, after pressing the platform button once, every time they click the screen, a platform gets drawn so I'm having trouble making it so they can only draw one. I thought using removeProcessor() would've worked, but it's not.
InputController inputProcessor;
InputMultiplexer multiplexer;
public GameScreen(FallDown game) {
this.game = game;
GAMESCREEN_STATE = WORLD_STATE_READY;
this.cam = new OrthographicCamera(FRUSTUM_WIDTH, FRUSTUM_HEIGHT);
this.cam.position.set(FRUSTUM_WIDTH / 2, FRUSTUM_HEIGHT / 2, 0);
this.cam.setToOrtho(false, FRUSTUM_WIDTH, FRUSTUM_HEIGHT);
batch = new SpriteBatch();
world = new World();
renderer = new WorldRenderer(batch, world);
cam.position.set(FRUSTUM_WIDTH / 2, 105, 0);
inputProcessor = new InputController(game, world, cam);
multiplexer = new InputMultiplexer();
}
Then, at the end of my render method I have
multiplexer.addProcessor(stage);
Gdx.input.setInputProcessor(multiplexer);
These are the listeners for my buttons and I'm just using the reset button as an alternate way to stop the user from drawing platforms.
reset_button.addListener(new InputListener() {
public boolean touchDown(InputEvent event, float x, float y,
int pointer, int button) {
multiplexer.removeProcessor(inputProcessor);
return true;
}
});
platform_button.addListener(new InputListener() {
public boolean touchDown(InputEvent event, float x, float y,
int pointer, int button) {
if (GAMESCREEN_STATE != WORLD_STATE_RUNNING) {
multiplexer.addProcessor(new InputController(game, world, cam));
}
return true;
}
});
Well, I would advice you not to add and remove processors that many times (especially the one in the render method.. move that to the constructor/create method).
An easy way to achieve what you are looking for is just have a boolean variable:
boolean createplatform = false;
And then set it to true when the button is pressed and to false when the first platform is created.
(So when you touch the screen, that boolean decides if a platform is created).
Using GWT I am displaying an image thumbnail with a ClickHandler that then shows the full image (can be several MB) in a centered PopupPanel. In order to have it centered the image must be loaded before the popup is shown, otherwise the top-left corner of the image is placed in the middle of the screen (the image thinks it is 1px large). This is the code I am using to do this:
private void showImagePopup() {
final PopupPanel popupImage = new PopupPanel();
popupImage.setAutoHideEnabled(true);
popupImage.setStyleName("popupImage"); /* Make image fill 90% of screen */
final Image image = new Image();
image.addLoadHandler(new LoadHandler() {
#Override
public void onLoad(LoadEvent event) {
popupImage.add(image);
popupImage.center();
}
});
image.setUrl(attachmentUrl + CFeedPostAttachment.ATTACHMENT_FILE);
Image.prefetch(attachmentUrl + CFeedPostAttachment.ATTACHMENT_FILE);
}
However, the LoadEvent event is never fired, and thus the image is never shown. How can I overcome this? I want to avoid using http://code.google.com/p/gwt-image-loader/ because I do not want to add extra libraries if I can avoid it at all. Thanks.
The onLoad() method will only fire once the image has been loaded into the DOM. Here is a quick workaround:
...
final Image image = new Image(attachmentUrl + CFeedPostAttachment.ATTACHMENT_FILE);
image.addLoadHandler(new LoadHandler() {
#Override
public void onLoad(LoadEvent event) {
// since the image has been loaded, the dimensions are known
popupImage.center();
// only now show the image
popupImage.setVisible(true);
}
});
popupImage.add(image);
// hide the image until it has been fetched
popupImage.setVisible(false);
// this causes the image to be loaded into the DOM
popupImage.show();
...
Hope that helps.