I have a little problem/question...
I want to hide one sprite and show another one but eclipse gives me error "The local ... may not have been inatialized". Unfortunatelly I don't have another idea to hide and show those sprites...
Can anybody help me?
Code:
protected Scene onCreateScene() {
final Scene scene = new Scene();
Sprite backgroundSprite = new Sprite(0, 0, this.mBackgroundTextureRegion, getVertexBufferObjectManager());
scene.attachChild(backgroundSprite);
final Katapulta S_katapulta_wystrzelona = new Katapulta(10, 300, this.mKatapulta_wystrzelona, getVertexBufferObjectManager());
final Katapulta S_katapulta_zaladowana = new Katapulta(10, 300, this.mKatapulta_zaladowana, getVertexBufferObjectManager()){
#Override
public boolean onAreaTouched(TouchEvent pSceneTouchEvent, float pTouchAreaLocalX, float pTouchAreaLocalY) {
// IN THIS LINE I HAVE ERROR S_katapulta_zaladowana.setVisible(false);
S_katapulta_wystrzelona.setVisible(true);
return true;
}
};
scene.attachChild(S_katapulta_zaladowana);
scene.attachChild(S_katapulta_wystrzelona);
S_katapulta_wystrzelona.setVisible(false);
scene.registerTouchArea(S_katapulta_zaladowana);
return scene;
}
Just use setVisible(false); instead of S_katapulta_zaladowana.setVisible(false); Because of the way you used the onAreaTouched() method.
Try adding this.
setOnSceneTouchListener(this);
Try by setting tag to all sprites .Then call the sprite using tag and then make it Invisible
You have to initialize the variable so that it is actually pointing to something it can use
ie;
int x = new int;
x = 69;
Related
I'm trying to draw a stage and a string with a specific font, but when I draw the stage, the string disappears, but the images do not. I suppose it's a simple thing, but I have no idea. I've already tried to change the order to render, but that doesn't seem to be the problem. Any help would be aprecciated.
#Override
public void create() {
stage = new Stage();
Gdx.input.setInputProcessor(stage);
batch = new SpriteBatch();
textatlas = new TextureAtlas("Agorafunfa.txt");
TextureAtlas.AtlasRegion a = textatlas.findRegion("spider");
spider = new Sprite(a);
img = new Texture("Captura.PNG");
yesa = new BitmapFont(Gdx.files.internal("yesa.fnt"));
font = "Escape Planet";
img3 = new Texture("saturno.png");
funciona = new BitmapFont(Gdx.files.internal("yesa.fnt"));
starte = "Começar";
opcoes = "Opções";
Skin skin = new Skin();
skin.addRegions(ta);
final TextButton.TextButtonStyle tbs = new TextButton.TextButtonStyle();
tbs.font = yesa;
tbs.checked = skin.getDrawable("comecaversao2");
tbs.up = skin.getDrawable("comeca");
b = new TextButton("Começar",tbs);
b.setHeight(250);
b.setWidth(300);
b.setPosition(-10, 50);
b.addListener(new ClickListener() {
#Override
public void clicked(InputEvent event, float x, float y) {
}
});
stage.addActor(b);
Gdx.input.setInputProcessor(stage);
}
public void render() {
Gdx.gl.glClearColor(1, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
batch.begin();
batch.draw(img,0,0);
batch.draw(img3, 200,170, 250, 170);
yesa.setColor(Color.WHITE);
yesa.draw(batch,font,430,300);
stage.draw();//if I comment this line, the string appears
batch.end();
}
You're on right track, stage.draw() is causing the problem. You're calling it without closing the spritebatch before. If you look into stage's source code you'll see it has its own spritebatch. Call batch.end() before drawing the stage.
Rendering a batch inside another opened batch will result in all kind of weird behaviour that makes you think the fault lies in everything but the batch.
As these type of problems pop up frequently nowadays I checked out the stage docs, there is clear information that it uses its own batch, you can even set your own with the constructor stage(Viewport viewport, Batch batch). If you use that constructor you don't need to use the solution above. However the docs doesn't mention batches needs to be closed, not even in the batch docs. This is something that probably should be added so we can avoid the same issues popping up.
Possible duplicate of this and this.
I am trying to create a Java application that uses JavaFX to allow the user to create shapes by selecting radio button options and then clicking and dragging in a BorderPane area to create their shapes.
I am on the right track so far. The problem I'm having is with getting them positioned correctly. I'm hoping that someone can help me figure out why the shapes aren't being created in the place that I expect them to.
Currently, the first shape I create gets placed in the upper left hand corner of the HBox that I have in the Center section of the BorderPane, regardless of where I click to start creating. Dragging the mouse seems to accurately size the box in accordance with the cursor.
Subsequent attempts to create shapes results in shapes created off-location of the cursor, and dragging will resize, but also not in correlation with the cursor.
Here is my code. I've taken out parts that aren't relevant to the issue at hand to hopefully make it more readable:
public class Main extends Application{
public static String shapeType = "";
public static String color = "";
static Rectangle customRectangle = null;
public void start(Stage mainStage) throws Exception{
Group root = new Group();
Scene scene = new Scene(root, 600, 400);
BorderPane borderPane = new BorderPane();
.....
HBox canvas = new HBox();
Group canvasGroup = new Group();
canvas.getChildren().add(canvasGroup);
canvas.setStyle("-fx-background-color: yellow");
borderPane.setTop(shapeOptions);
borderPane.setLeft(colorOptions);
borderPane.setCenter(canvas);
canvas.addEventFilter(MouseEvent.ANY, new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
if(event.getEventType() == MouseEvent.MOUSE_PRESSED && shapeType != ""){
switch(shapeType){
case "rectangle":
createCustomRectangle(event, color, canvasGroup);
}
}
if(event.getEventType() == MouseEvent.MOUSE_DRAGGED){
switch (shapeType){
case "rectangle":
editCustomRectangle(event);
}
}
}
});
root.getChildren().add(borderPane);
mainStage.setScene(scene);
mainStage.show();
}
public static void createCustomRectangle(MouseEvent event, String color, Group canvasGroup){
customRectangle = new Rectangle(0, 0, 10,10);
customRectangle.relocate(event.getX(), event.getY());
customRectangle.setFill(Color.RED);
canvasGroup.getChildren().add(customRectangle);
}
public static void editCustomRectangle(MouseEvent event){
customRectangle.setWidth(event.getX() - customRectangle.getTranslateX());
customRectangle.setHeight(event.getY() - customRectangle.getTranslateY());
}
public static void main(String[] args){
launch(args);
}
}
I also wanted to attach a couple of images to make my issue more clear. Here is attempting to create the first shape:
Clicking and dragging to create first shape
And here is trying to create a subsequent shape:
Clicking and dragging to create another shape
Hopefully the description, code, and images are enough to convey what's going on. Any help would be greatly appreciated.
Thanks!
Let's start fixing each problem at a time. First of all a friendly advice, try to name your variables in a way that helps the reader understand their meaning and their identity ( when I first saw the canvas variable I thought it was an actual Canvas ).
Now your layout is something like this :
BorderPane
TOP
- Something
CENTER
- HBox
- Group
- Rectangle
- Rectangle
- ...
Left
- Something
Bottom
- Something
The HBox takes all the available height and calculates it's width depending on its children. So in order to take all the
available space inside the BorderPane you need to actually specify it or bind its preferredWidthProperty with the
widthProperty of the BorderPane.
From the documentation of the Group class you can see that :
Any transform, effect, or state applied to a Group will be applied to
all children of that group. Such transforms and effects will NOT be
included in this Group's layout bounds, however, if transforms and
effects are set directly on children of this Group, those will be
included in this Group's layout bounds.
So when you relocate the Node ( the actual rectangle ) the method relocate() just set the translateX and translateY values and that transformation is applied to the Group's layout bounds as well. To fix that you could change the Group to an AnchorPane.
The way you resize the rectangle is not correct. You need to take the first mouse click coordinates when the first click event takes place and then on a drag event you will take the new coordinates, calculate the delta value of X and Y and just add that value to the width and height for the rectangle finally update the firstX and firstY variable on drag event listener :
deltaX = event.getX() - firstX;
deltaY = event.getY() - firstY;
customRectangle.setWidth(customRectangle.getWidth + deltaX);
customRectangle.setHeight(customRectangle.getHeight + deltaY);
Here is an example of the above :
import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
public class Main extends Application {
public static String shapeType = "";
public static String color = "";
private static Rectangle customRectangle = null;
private double firstX = 0;
private double firstY = 0;
public void start(Stage mainStage) throws Exception {
BorderPane mainPane = new BorderPane();
HBox centerPane = new HBox();
centerPane.prefWidthProperty().bind(mainPane.widthProperty());
centerPane.prefHeightProperty().bind(mainPane.heightProperty());
AnchorPane anchorPane = new AnchorPane();
anchorPane.prefWidthProperty().bind(centerPane.widthProperty());
anchorPane.prefHeightProperty().bind(centerPane.heightProperty());
centerPane.getChildren().add(anchorPane);
centerPane.setStyle("-fx-background-color: yellow");
shapeType = "rectangle";
mainPane.setCenter(centerPane);
centerPane.addEventFilter(MouseEvent.ANY, new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
if (event.getEventType() == MouseEvent.MOUSE_PRESSED && shapeType != "") {
switch (shapeType) {
case "rectangle":
firstX = event.getX();
firstY = event.getY();
createCustomRectangle(event, color, anchorPane);
}
}
if (event.getEventType() == MouseEvent.MOUSE_DRAGGED) {
switch (shapeType) {
case "rectangle":
editCustomRectangle(event);
firstX = event.getX();
firstY = event.getY();
}
}
}
});
Scene scene = new Scene(mainPane, 600, 400);
mainStage.setScene(scene);
mainStage.show();
}
public void createCustomRectangle(MouseEvent event, String color, AnchorPane canvasGroup) {
customRectangle = new Rectangle(0, 0, 10, 10); // or just set the actual X and Y from the start
customRectangle.relocate(event.getX(), event.getY());
customRectangle.setFill(Color.RED);
canvasGroup.getChildren().add(customRectangle);
}
public void editCustomRectangle(MouseEvent event) {
double deltaX = event.getX() - firstX;
double deltaY = event.getY() - firstY;
double width = customRectangle.getWidth() + deltaX;
double height = customRectangle.getHeight() + deltaY;
customRectangle.setWidth(width);
customRectangle.setHeight(height);
}
public static void main(String[] args) {
launch(args);
}
}
Well, first off, customRectangle.relocate(event.getX(), event.getY()); clearly isn't doing what it's supposed to do. It might be better to create the rectangle at the appropriate spot in the first place.
Instead of:
customRectangle = new Rectangle(0, 0, 10,10);
customRectangle.relocate(event.getX(), event.getY());
try:
customRectangle = new Rectangle(event.getX(), event.getY(), 10,10);
Secondly, it looks like customRectangle.getTranslateX() and customRectangle.getTranslateY() always return 0, so I'd take a look at those methods and see what's going on there as well. Good luck, hope this helped.
Edit:
instead of relocate maybe try using setTranslateX() and setTranslateY().
Thanks everyone for the suggestions! I found what I think is the most straight forward solution to my problem. One large part was that Group was not the kind of node that would allow my intended action. It appended every newly added Node/Object to the right of the previously created one. So, I switched to a StackPane and got better results. The problem there is that it creates everything on the center of the StackPane. My solution to that was to set the alignment for the shape as it's created. Largely, everything else remained the same.
Here is the pertinent code segments for anyone looking to perform a similar operation (my original post has more complete code):
StackPane stackCanvas = new StackPane();
stackCanvas.setStyle("-fx-background-color: yellow");
borderPane.setTop(shapeOptions);
borderPane.setLeft(colorOptions);
borderPane.setCenter(stackCanvas);
public static void createCustomRectangle(MouseEvent event, String color, StackPane stackCanvas){
customRectangle = new Rectangle();
StackPane.setAlignment(customRectangle, Pos.TOP_LEFT);
stackCanvas.getChildren().add(customRectangle);
customRectangle.setTranslateX(event.getX());
customRectangle.setTranslateY(event.getY());
customRectangle.setFill(Color.RED);
}
I have a class called InputHandler which implements InputProcessor and is the InputProcessor for my Gameworld. That works just fine. But now I'm trying to built a main menu and my clickListeners do not work, but instead touchDown() from my InputHandler-class is called. I created an instance of all my screens to be able to switch between them easily but I have no idea how to fix that. I've heard of an InputMultiplexer but I have no plan how to integrate such a thing in my code to solve my problems. I tried to return false from my touchDown() and other methods but my ClickListeners don't do anything at all even after that.
Here is my code:
1st my "Main"Class where I create all the screens:
public void create(){
mainMenuScreen = new MainMenuScreen(this);
gameScreen = new GameScreen(this);
setScreen(mainMenuScreen);
}
the game class with its inputProcessor:
public GameScreen(final Stapler gam) {
this.game = gam;
world = new World(new Vector2(0, StaplerValues.WORLD_GRAVITY), true);
Gdx.input.setInputProcessor(new InputHandler(world));
my InputHandler:
public class InputHandler implements InputProcessor {
World world;
public InputHandler(World world) {
this.world = world;
}
public boolean touchDown(int x, int y, int pointer, int button) {
// this is called even when i'm in my main menu and want to click a button
return false;
}
public boolean touchUp(int x, int y, int pointer, int button) {
// your touch up code here
return false; // return true to indicate the event was handled
}
public boolean touchDragged(int x, int y, int pointer) {
return false;
}
and my main menu with its clickListeners:
public class MainMenuScreen implements Screen {
public MainMenuScreen(final Stapler gam) {
game = gam;
stage = new Stage();
table = new Table();
table.setFillParent(true);
stage.addActor(table);
Gdx.input.setInputProcessor(stage);
// Add widgets to the table here.
TextureRegion upRegion = new TextureRegion(new Texture(
Gdx.files.internal("boxLila.png")));
TextureRegion downRegion = new TextureRegion(new Texture(
Gdx.files.internal("boxGruen.png")));
BitmapFont buttonFont = new BitmapFont(
Gdx.files.internal("fonts/bodoque.fnt"), false);
buttonFont.setScale(2);
TextButtonStyle style = new TextButtonStyle();
style.up = new TextureRegionDrawable(upRegion);
style.down = new TextureRegionDrawable(downRegion);
style.font = buttonFont;
play = new TextButton("Play", style);
play.addListener(new ClickListener() {
public void clicked(InputEvent e, float x, float y) {
game.setScreen(game.gameScreen);
}
});
// add the button with a fixed width
table.add(play).width(500);
// then move down a row
table.row();
}
The click listener works but only if i didnt create an instance of GameWorld in the first place. How can I solve that they grab the right input depending on which screen is currently shown? Please try give an answer as detailed as possible because I'm quite new to all that stuff. And sorry for that mess of code and my bad english an thanks in advance!!!
There is globally only one InputProcessor for the entire game. When you call Gdx.input.setInputProcessor(new InputHandler(world));, it replaces the InputProcessor that you set in your MainMenuScreen class.
One simple solution is to just change the game's input processor every time you switch between screens (in the show() method).
If you want two InputProcessors to both work simultaneously, you need to combine them using an InputMultiplexer, and set the multiplexer as your game's InputProcessor.
For organization's sake, I use multiple scenes for my game and rather than having each scene have a constructor that receives a Viewport (my game is scalable), I would like to set each stage's viewport separate of the constructor, then after the viewport is set, add the actors. In the main class, it would happen like this:
public void setStage(Stage s)
{
if(currentStage != null)
currentStage.dispose();
currentStage = s;
currentStage.setViewport(view);
}
To make this go fluidly, each stage has an init method that is called within an overriden setViewport:
#Override
public void setViewport(Viewport v)
{
super.setViewport(v);
init();
}
However, all this gives me is a black screen... I have tried updating the camera and viewport, but no avail (note that the actors are having their render methods called).
Why am I getting this black screen and how do I fix it? If it's not possible I'll just revert to using the constructor.
If I understood correctly you want to do this:
Stage stage1 = new Stage();
stage1.getViewport().update(width, height);
rather than this:
Stage stage1 = new Stage (new StretchViewport(width, height)); // It doesn't have to be StretchViewport
In the first case (what you are trying to do) a ScalingViewport will be costructed automatically for you with dimensions of the Gdx.graphics and an orthographic camera and acts like a StretchViewport. Why not using the second case directly where you pass the viewport you want. You can always alter your viewport whenever you want by calling stage1.getViewport().update(width, height);
or by calling stage1.setViewport(width, height, false); in older Libgdx versions.
Viewport has changed recently so if you can extend Viewport class to Override the update method maybe you can achieve what you want:
public class ViewportExtendClass extends StretchViewport{
public ViewportExtendClass(float worldWidth, float worldHeight) {
super(worldWidth, worldHeight);
}
#Override
public void update (int screenWidth, int screenHeight, boolean centerCamera) {
super.update(screenWidth, screenHeight, centerCamera);
// DO YOUR INITIALIZATION HERE
}
}
From your main class you create new stage :
Stage stage1 = new Stage (new ViewportExtendClass (width, height));
and then you call :
stage1.getViewport().update(width, height);
Like this you can alter stage viewport and re initialize your assets.
#Override
public void setViewport(Viewport v)
{
super.setViewport(v);
this.getViewport().update(Gdx.graphics.getWidth(), Gdx.graphics.getHeight(), false);
Camera c = this.getViewport().getCamera();
c.position.set(c.viewportWidth/2, c.viewportHeight/2, 0);
init();
}
This works, but you should also be able to update the Viewport like that at the begin of your application, if you continue to use the same one. I set the position like that instead of centering because some of my Stages will be larger than the screen.
Here is the method that's giving me trouble:
private static final String theURL = "/optimize/images/prun0.png";
public static void createChallenge() {
Stage challStage = new Stage();
Group challGroup = new Group();
Rectangle rect = new Rectangle(900, 500);
Image image = new Image(theURL);
System.out.println(image.getHeight()); //Prints 0.0
rect.setFill(new ImagePattern(image)); //Gives runtime error: "Image must be non-null"
challStage.setResizable(false);
challStage.setTitle("Optimize!");
//ImageView iv = new ImageView(image);
challGroup.getChildren().add(rect);
Scene challScene = new Scene(challGroup, 900, 500);
challStage.setScene(challScene);
challStage.setMinHeight(500);
challStage.setMinWidth(900);
challStage.show();
challStage.centerOnScreen();
challStage.setX(challStage.getX()-150);
}
As it says, it throws a runtime error about image being null. Am I missing something basic? Also, the ultimate goal here is to put an image onto a Stage or Scene. I tried to do it simply with adding ImageView objects to the defined challGroup, but the Stage came up blank. Due to this, I tried to add the image to a Rectangle object and there found the actual runtime error. I have thrice-checked the URL. I've also tried using "file:prun0.png" to similar results. Any advice is appreciated. Thanks to all.