One question currently I am working on a team size seletion screen, So far I did it with checkboxes for team one is finished. Now next to that I wanted to draw another table with the same stage, I don't want to draw with a new Stage in order to save ressources. So my question is it Possible to draw multible tables with one stage next to each other? This is what I currently tried but it didn't work.
So I tried to give a second Table to the constructor something like:
stage.addActor(table,table2)
which did not work.
My second try was something like
stage.addActor(table);
stage.addActor(table2);
which did not work either.
public class TeamSelectScreen implements Screen {
public SEPGame game;
public SpriteBatch menuBatch;
public AssetManager assetManager;
public Viewport viewport;
public Stage stage;
public MenuScreen menuScreen;
public ButtonGroup<CheckBox> teamSelect;
public CheckBox Tank1;
public CheckBox Tank2;
public CheckBox Tank3;
public CheckBox Tank4;
public CheckBox Tank5;
public TeamSelectScreen(SEPGame game) {
game = new SEPGame();
menuBatch = new SpriteBatch();
assetManager = new AssetManager();
viewport = new FitViewport(SEPGame.WORLD_PIXEL_WIDTH, SEPGame.WORLD_PIXEL_HEIGHT);
menuScreen = new MenuScreen(game);
menuScreen.dispose();
stage = new Stage(viewport, menuBatch);
Gdx.input.setInputProcessor(stage);
assetManager.load(Assetdescriptor.backGround);
assetManager.load(Assetdescriptor.buttonNotePressed);
assetManager.load(Assetdescriptor.buttonPressed);
assetManager.load(Assetdescriptor.skinUI);
assetManager.finishLoading();
}
public void setupScreen() {
TextureAtlas menuUi = assetManager.get(Assetdescriptor.backGround);
Skin uiSkin = assetManager.get(Assetdescriptor.skinUI);
TextureRegion backGroundRegion = menuUi.findRegion(Regionnames.backGround);
Table table = new Table();
Table table2 = new Table();
Label title = new Label("Team Auswahl", uiSkin);
Tank1 = new CheckBox("Tank 1 Player", uiSkin);
Tank2 = new CheckBox("Tank 2 Player", uiSkin);
Tank3 = new CheckBox("Tank 3 Ki", uiSkin);
Tank4 = new CheckBox("Tank 4 Ki", uiSkin);
Tank5 = new CheckBox("Tank 5 Ki", uiSkin);
ChangeListener teamSizeChanger = new ChangeListener() {
#Override
public void changed(ChangeEvent event, Actor actor) {
}
};
Tank1.addListener(teamSizeChanger);
Tank2.addListener(teamSizeChanger);
Tank3.addListener(teamSizeChanger);
Tank4.addListener(teamSizeChanger);
Tank5.addListener(teamSizeChanger);
Table checkTable = new Table();
checkTable.defaults().pad(5);
checkTable.add(Tank1).row();
checkTable.add(Tank2).row();
checkTable.add(Tank3).row();
checkTable.add(Tank4).row();
checkTable.add(Tank5).row();
Table checkTable2 = new Table();
Table checkTable3 = new Table();
Table checkTable4 = new Table();
Table checkTable5 = new Table();
// Team 1
table.add(checkTable);
table.padRight(1200);
table.setFillParent(true);
table.pack();
table.setBackground(new TextureRegionDrawable(backGroundRegion));
// Team 2
table2.add(checkTable2);
table2.padRight(1000);
table.setFillParent(true);
table.pack();
// Add 2 Tables?
stage.addActor(table);
stage.addActor(table2);
}
#Override
public void show() {
}
#Override
public void render(float delta) {
Gdx.gl.glClearColor(1, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
menuScreen.dispose();
setupScreen();
stage.draw();
}
}
You're calling table.setFillParent(true) twice but never table2.setFillParent(true).
Another option would be adding a Stack with fill parent to the stage and then adding the two tables to the stack:
Stack stack = Stack(table, table2)
stack.setFillParent(true)
stage.addActor(stack)
Related
I'm trying to put an image as a background in a JavaFX scene, but my code isn't working.
Im trying to make a Battleship-game program in java eclipse but i'm stuck at a graphics problem.
public class WindowGUI extends Application{
Game game;
Image image;
public WindowGUI(Game game) {
this.game = game;
}
public static void main(String[] args) {
Game game = new Game();
new WindowGUI(game);
}
#Override
public void start(Stage stage) throws Exception {
stage.setTitle("Battleship");
image = new Image ("C:\\Users\\amali\\git\\inf101.v19.sem2\\inf101.v19.sem2\\src\\window\\battleshipbackground.jpg");
ImageView background = new ImageView(image);
Button startButton = new Button("START");
BorderPane newStack = new BorderPane();
newStack.getChildren().add(startButton);
newStack.getChildren().add(background);
stage.setScene(new Scene(newStack, 1300, 860));
stage.show();
startButton.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
// START THE GAME
}
});
}
}
When I first tried to run it, it worked and a new window opened with a button in the center, but the bakcground was blank. When i try setting an image as background in the window, behing the 'start'-button, nothing happens..
A better way to do it is to use the Background class rather than trying to add an ImageView as a child of your BorderPane.
Image image = new Image("C:\\Users\\amali\\git\\inf101.v19.sem2\\inf101.v19.sem2\\src\\window\\battleshipbackground.jpg");
BackgroundSize size = new BackgroundSize(BackgroundSize.AUTO,
BackgroundSize.AUTO,
false,
false,
true,
false);
Background background = new Background(new BackgroundImage(image,
BackgroundRepeat.NO_REPEAT,
BackgroundRepeat.NO_REPEAT,
BackgroundPosition.CENTER,
size));
newStack.setBackground(background);
Use BackgroundImage class.
or try this
JavaFX How to set scene background image
I've wrapped my brain around a challenge for 2 days now. I am all empty for ideas, so I hope someone out there know how to do this.
I got inspired by Angela Caicedo's city app, from the website https://blogs.oracle.com/acaicedo/entry/managing_multiple_screens_in_javafx, and trying to make a similar app-gui to show available rooms and lecture halls at my University.
I am using Java FX to build the gui, and I get the whole GUI printed out, which is a java fx pane with a image on it. What I want, however, is to just see a small part of the gui (the backgroundimage I am using is w:1500px h:500, so each part will be w:500px h:500px), then be able to push a button or a arrow (or similar) to move the window to the next step. On top of the image there is 3 panes with w:500px h:500px snapped to each other. Maybe this is a bad solution, considering all the pane-types Java FX has available.
So, what I need is a constrained viewer of sorts.
I've also used FMXL to build the GUI, having one FMXL document, one Controller and a css-file to handle the design.
I'm sure I've been everywhere on the internet by now, so I really hope someone has done this before in Java FX :)
Ok, here is some code example. The first sample works nice, but I want to implement the second example instead. I am reading on the TranslateTransition of JavaFX, but my efforts of trying to switch the code is hopeless..
1'st example (working, and is fading in and out of the fxml screen):
public boolean setScreen(final String name){
if (screens.get(name) != null) { //screen loaded
final DoubleProperty opacity = opacityProperty();
if (!getChildren().isEmpty()) { //if there is more than one screen
Timeline fade = new Timeline(
new KeyFrame(Duration.ZERO, new KeyValue(opacity, 1.0)),
new KeyFrame(new Duration(2000), new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent t) {
getChildren().remove(0); //remove the displayed screen
getChildren().add(0, screens.get(name)); //add the screen
Timeline fadeIn = new Timeline(
new KeyFrame(Duration.ZERO, new KeyValue(opacity, 0.0)),
new KeyFrame(new Duration(2000), new KeyValue(opacity, 1.0)));
fadeIn.play();
}
}, new KeyValue(opacity, 0.0)));
fade.play();
} else {
setOpacity(0.0);
getChildren().add(screens.get(name)); //no one else been displayed, then just show
Timeline fadeIn = new Timeline(
new KeyFrame(Duration.ZERO, new KeyValue(opacity, 0.0)),
new KeyFrame(new Duration(1000), new KeyValue(opacity, 1.0)));
fadeIn.play();
}
return true;
} else {
System.out.println("screen hasn't been loaded!!! \n");
return false;
}
}
Second example, the TranslateTransition I want to implement instead:
private final double IMG_WIDTH = 500;
private final double IMG_HEIGHT = 500;
private final int NUM_OF_IMGS = 3;
private final int SLIDE_FREQ = 4; // in secs
#Override
public void start(Stage stage) throws Exception {
stage.initStyle(StageStyle.UNDECORATED);
StackPane root = new StackPane();
Pane clipPane = new Pane();
// To center the slide show incase maximized
clipPane.setMaxSize(IMG_WIDTH, IMG_HEIGHT);
clipPane.setClip(new Rectangle(IMG_WIDTH, IMG_HEIGHT));
HBox imgContainer = new HBox();
ImageView imgGreen = new ImageView(new Image(getClass().getResourceAsStream("uib_01.jpg")));
ImageView imgBlue = new ImageView(new Image(getClass().getResourceAsStream("uib_02.jpg")));
ImageView imgRose = new ImageView(new Image(getClass().getResourceAsStream("uib_03.jpg")));
imgContainer.getChildren().addAll(imgGreen, imgBlue, imgRose);
clipPane.getChildren().add(imgContainer);
root.getChildren().add(clipPane);
Scene scene = new Scene(root, IMG_WIDTH, IMG_HEIGHT);
stage.setTitle("Image Slider");
stage.setScene(scene);
startAnimation(imgContainer);
stage.show();
}
private void startAnimation(final HBox hbox) {
EventHandler<ActionEvent> slideAction = (ActionEvent t) -> {
TranslateTransition trans = new TranslateTransition(Duration.seconds(1.5), hbox);
trans.setByX(-IMG_WIDTH);
trans.setInterpolator(Interpolator.EASE_BOTH);
trans.play();
};
EventHandler<ActionEvent> resetAction = (ActionEvent t) -> {
TranslateTransition trans = new TranslateTransition(Duration.seconds(1), hbox);
trans.setByX((NUM_OF_IMGS - 1) * IMG_WIDTH);
trans.setInterpolator(Interpolator.EASE_BOTH);
trans.play();
};
List<KeyFrame> keyFrames = new ArrayList<>();
for (int i = 1; i <= NUM_OF_IMGS; i++) {
if (i == NUM_OF_IMGS) {
keyFrames.add(new KeyFrame(Duration.seconds(i * SLIDE_FREQ), resetAction));
} else {
keyFrames.add(new KeyFrame(Duration.seconds(i * SLIDE_FREQ), slideAction));
}
}
Timeline anim = new Timeline(keyFrames.toArray(new KeyFrame[NUM_OF_IMGS]));
anim.setCycleCount(Timeline.INDEFINITE);
anim.playFromStart();
}
The screen should change on button click. I have this in a separate controller class:
import java.net.URL;
import java.util.ResourceBundle;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.image.ImageView;
import javafx.scene.input.MouseEvent;
public class roomAppController implements Initializable, ScreenController {
private ScreenPane myScreenPane;
#FXML
public ImageView bldArw_1;
public ImageView rmArw_1;
#FXML
private void handleExitButtonEvent(MouseEvent e) {
System.out.println("Button is clicked");
System.exit(0);
}
#FXML
private void handleNextPageEvent(MouseEvent e) {
if((ImageView)e.getSource() == bldArw_1) {
myScreenPane.setScreen("buildingScreen");
}
if((ImageView)e.getSource() == rmArw_1) {
myScreenPane.setScreen("roomScreen");
}
System.out.println("Clicked");
}
#Override
public void initialize(URL location, ResourceBundle resources) {
}
#Override
public void setScreenPane(ScreenPane screenPage) {
myScreenPane = screenPage;
}
}
I use libgdx's scene2d built-in UI library to make an UI in my game. I'm interesting how can I draw 2 images(or actors) in a table one on another? I'm looking to the similar like LayerDrawable in Android. Is there any exists stuff to make it?
There is a Stack widget in libGDX UI library for these purposes.
UPDATE: if you want to place one widget on top of another widget and these widgets have different size then you should wrap the smaller widget. Something like:
//First add actual content
stack.add(content);
//Second add wrapped overlay object
Table overlay = new Table();
overlay.add(overlayWidget).expand().fillX().bottom().left();
stack.add(overlay);
stack variable is a Stack instance
It's an actual excerpt from my project. You should tune it for your case.
You can use somethings like this :
//create stage
stage = new Stage(new StretchViewport(game.width, game.height));
//create table
Table table = new Table();
table.setSize(game.width,game.height); //fullscreen
//add Image 1
table.add(new Image(game.skin.getDrawable("image1")));
//add Image 2 (create new col)
table.add(new Image(game.skin.getDrawable("image2"))).width(xx).height(xx);
//add new row
table.row();
//add Image 3 - padding to draw over image1/2 && colspan
table.add(new Image(game.skin.getDrawable("image3"))).width(xx).height(xx).padTop(-50f).colspan(2);
//add table to stage
stage.addActor(table);
/*
* Add action
*
*/
#Override
public void render(float delta) {
...
//don't forget to draw ur stage
stage.act(delta); // or stage.act(Gdx.graphics.getDeltaTime())
stage.draw();
}
Also you can add action to stage/table or image etc ... :
stage.addAction(Actions.sequence(
Actions.fadeOut(0.0001f),
Actions.fadeIn(0.5f),
Actions.delay(0.1f),
Actions.run(new Runnable() {
#Override
public void run() {
//mmmm new screen
dispose();
game.setScreen(new BoobsScreen(game));
}
})));
Of course you can draw more than image : button, textbutton, label etc or add scrollPane for Table but before take a look at Skin on libgdx
For exemple a programmatically ninepatch textbutton :
private NinePatch processNinePatchFile(String fname) {
final Texture t = new Texture(Gdx.files.internal(fname));
final int width = t.getWidth() - 2;
final int height = t.getHeight() - 2;
return new NinePatch(new TextureRegion(t, 1, 1, width, height), 3, 3, 3, 3);
}
//create skin
skin = new Skin();
...
//create font
...
//create ninepatch button from android/assets/style/button
NinePatch ninepatch = processNinePatchFile("style/button.9.png");
skin.add("button.9", ninepatch);
//create textbuttonstyle
TextButton.TextButtonStyle textButtonStyle = new TextButton.TextButtonStyle();
textButtonStyle.font = skin.getFont("font_black_38");
textButtonStyle.fontColor = Color.DARK_GRAY;
textButtonStyle.up = skin.getDrawable("button.9");
skin.add("buttonTextStyle", textButtonStyle);
//now you can create textbutton
TextButton btn = new TextButton("Hello", game.skin.get("buttonTextStyle", TextButton.TextButtonStyle.class));
//add a clicklistener
btn.addListener(new ClickListener(){
#Override
public void clicked(InputEvent event, float x, float y) {
//mmmmmm add action for exemple
stage.addAction(Actions.sequence(Actions.fadeOut(0.5f), Actions.run(new Runnable() {
#Override
public void run() {
//dispose and load screen
dispose();
game.setScreen(new MoreBoobsScreen(game));
}
})));
}
});
table.add(btn);
To create bitmapfont take a look at Gdx freetype, it's really easy to use.
Trying to add multiple items to a scrollpane I quickly found that all "addActor" functions are Unsupported. So, I went with adding a table with all the items I wanted (this code misses a image that I still want to add) to make a scrollable credits screen... but this approach (currently) doesn't allow for overflow, rendering the ScrollPane useless. (My text is only shown up to what the screen's height allows, and isn't scrollable).
What's the way to make a scrollable pane with multiple widgets in LibGDX? (I only care about Android and Win/Lin/Mac platforms at the moment.
pane = new ScrollPane(null, skin);
pane.setFillParent(true);
paneContent = new Table(skin);
paneContent.setFillParent(true);
Label temp = new Label("", skin);
temp.setAlignment(Align.left, Align.center);
temp.setText( Gdx.files.internal("licenses/credits.txt").readString("UTF-8") );
paneContent.addActor(temp);
pane.setWidget(paneContent);
stage.addActor(pane);
If you want to put multiple items into the ScrollPane you simply need to put a table into it and call add() for each widget you want to put into the ScrollPane.
Below is an example of how to make your credits scrollable:
public class ScrollTest implements ApplicationListener {
private Stage stage;
private static final String reallyLongString = "This\nIs\nA\nReally\nLong\nString\nThat\nHas\nLots\nOf\nLines\nAnd\nRepeats.\n"
+ "This\nIs\nA\nReally\nLong\nString\nThat\nHas\nLots\nOf\nLines\nAnd\nRepeats.\n"
+ "This\nIs\nA\nReally\nLong\nString\nThat\nHas\nLots\nOf\nLines\nAnd\nRepeats.\n";
#Override public void create() {
this.stage = new Stage();
Gdx.input.setInputProcessor(this.stage);
final Skin skin = new Skin(Gdx.files.internal("skin/uiskin.json"));
final Label text = new Label(reallyLongString, skin);
text.setAlignment(Align.center);
text.setWrap(true);
final Label text2 = new Label("This is a short string!", skin);
text2.setAlignment(Align.center);
text2.setWrap(true);
final Label text3 = new Label(reallyLongString, skin);
text3.setAlignment(Align.center);
text3.setWrap(true);
final Table scrollTable = new Table();
scrollTable.add(text);
scrollTable.row();
scrollTable.add(text2);
scrollTable.row();
scrollTable.add(text3);
final ScrollPane scroller = new ScrollPane(scrollTable);
final Table table = new Table();
table.setFillParent(true);
table.add(scroller).fill().expand();
this.stage.addActor(table);
}
#Override public void render() {
this.stage.act();
Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
this.stage.draw();
}
#Override public void resize(final int width, final int height) {}
#Override public void pause() {}
#Override public void resume() {}
#Override public void dispose() {}
}
Edit: Added code on setting up a table inside of a ScrollPane.
I'm attempting to create a window that is divided into three parts. A non-resizable header and footer and then a content area that expands to fill the remaining area in the window. To get started, I created the following class:
public class MyWindow extends ApplicationWindow {
Color white;
Font mainFont;
Font headerFont;
public MyWindow() {
super(null);
}
protected Control createContents(Composite parent) {
Display currentDisplay = Display.getCurrent();
white = new Color(currentDisplay, 255, 255, 255);
mainFont = new Font(currentDisplay, "Tahoma", 8, 0);
headerFont = new Font(currentDisplay, "Tahoma", 16, 0);
// Main layout Composites and overall FillLayout
Composite container = new Composite(parent, SWT.NO_RADIO_GROUP);
Composite header = new Composite(container, SWT.NO_RADIO_GROUP);
Composite mainContents = new Composite(container, SWT.NO_RADIO_GROUP);;
Composite footer = new Composite(container, SWT.NO_RADIO_GROUP);;
FillLayout containerLayout = new FillLayout(SWT.VERTICAL);
container.setLayout(containerLayout);
// Header
Label headerLabel = new Label(header, SWT.LEFT);
headerLabel.setText("Header");
headerLabel.setFont(headerFont);
// Main contents
Label contentsLabel = new Label(mainContents, SWT.CENTER);
contentsLabel.setText("Main Content Here");
contentsLabel.setFont(mainFont);
// Footer
Label footerLabel = new Label(footer, SWT.CENTER);
footerLabel.setText("Footer Here");
footerLabel.setFont(mainFont);
return container;
}
public void dispose() {
cleanUp();
}
#Override
protected void finalize() throws Throwable {
cleanUp();
super.finalize();
}
private void cleanUp() {
if (headerFont != null) {
headerFont.dispose();
}
if (mainFont != null) {
mainFont.dispose();
}
if (white != null) {
white.dispose();
}
}
}
And this results in an empty window when I run it like this:
public static void main(String[] args) {
MyWindow myWindow = new MyWindow();
myWindow.setBlockOnOpen(true);
myWindow.open();
Display.getCurrent().dispose();
}
What am I doing wrong that I don't see three labels the way I'm trying to display them? The createContents code is definitely being called, I can step through it in Eclipse in debug mode.
Apparently, I needed to set the size and location of the labels to get them to appear.