LibGDX loading scene2D widgets very slow for first time, need suggestions - java

I started using scene2D in my LibGDX game to make a more professional looking login/register menu. The only problem is that switching to those menus is very long for menu navigation (3-5 sec).
I want to know if there is a better way to load them before hand, like during the game's initial loading screen. The thing is that once one of the menus is loaded, it loads very quick the second time.
I know for sure that its the create method of my screens that takes this long. Here is all that it is loading:
public void create(){
stage = new Stage(new StretchViewport(1920, 1080));
Gdx.input.setInputProcessor(stage);
loginBox = new Image(Textures.Gui.BOX);
loginBox.setSize(650, 1000);
loginBox.setPosition(635, 40);
stage.addActor(loginBox);
loginLBL = new Label("Login", Archipelo.SKIN, "basic-large-font", Color.LIGHT_GRAY);
loginLBL.setPosition(880, 955);
stage.addActor(loginLBL);
selectionHighlight = new Image(Textures.Gui.SELECTION_HIGHLIGHT);
selectionHighlight.setSize(540, 140);
stage.addActor(selectionHighlight);
usernameTF = new TextField("", Archipelo.SKIN);
usernameTF.setMaxLength(24);
usernameTF.setPosition(usernameTFx, usernameTFy);
usernameTF.setSize(400, 60);
stage.addActor(usernameTF);
passwordTF = new TextField("", Archipelo.SKIN);
passwordTF.setPasswordMode(true);
passwordTF.setPasswordCharacter('•');
passwordTF.setPosition(passwordTFx, passwordTFy);
passwordTF.setSize(400, 60);
stage.addActor(passwordTF);
usernameLBL = new Label("Username", Archipelo.SKIN, "basic-medium-font", new Color(1, 1, 1, 0.5f));
usernameLBL.setPosition(usernameTFx + 10, usernameTFy + 5);
stage.addActor(usernameLBL);
passwordLBL = new Label("Password", Archipelo.SKIN, "basic-medium-font", new Color(1, 1, 1, 0.5f));
passwordLBL.setPosition(passwordTFx + 10, passwordTFy + 5);
stage.addActor(passwordLBL);
remember = new CheckBox(" Remember Login?", Archipelo.SKIN);
remember.setPosition(rememberX, rememberY);
remember.getCells().get(0).size(30, 30);
stage.addActor(remember);
errorLBL = new Label("", Archipelo.SKIN, "basic-small-font", Color.RED);
errorLBL.setPosition(750, 650);
errorLBL.setWrap(true);
errorLBL.setBounds(750, 500, 400, 250);
stage.addActor(errorLBL);
continueLBL = new Label("Continue", Archipelo.SKIN, "basic-big-font", Color.WHITE);
continueLBL.setPosition(875, 100);
stage.addActor(continueLBL);
}
Also, I load the uiskin files before in the game's initial loading screen. Archipelo.SKIN is a static variable that refers to that uiskin. I also wanted to mention that my screen class is custom made and that whenever create() is called it is because a new screen instance is being created.
The thing that I don't get is why it takes so long to create the screen the first time and then every other time, it still goes through the same process except its much faster. Is there a way to make it faster the first time?
Thanks in advance. If you need more info by all means ask.

To summarize the comments...
The OP had a convenience class for texture references, that listed the textures like this:
public class Gui {
public static final Texture BOX = new Texture("box.png");
public static final Texture SELECTION_HIGHLIGHT= new Texture("selectionHighlight.png");
//...
}
Since they are declared static, they are members of the class, not an instance of a class. Static members of a class are all initialized at once, but only the first time the class or an instance of the class is accessed. This setup results in all the Gui textures getting loaded all at once at some inopportune, unplanned time.
The Texture's constructor Texture(String filename) causes a texture to be loaded from a file, which is time-consuming, so the loading of the Gui class takes a few seconds.
The solution is to not instantiate member texture variables in their declaration. Instantiate them within some method so you can decide exactly when they should be loaded.

Related

Why is the animation not showing and is slowing down the rest?

The animation isn't showing on the Pane background and it slows down the other animation already present. I pass on the Pane background as a parameter so I don't know maybe that is the cause but I have other methods doing that and it's not causing any problems.
public static void fireAnimation(Pane animatedBackground) {
AnimationTimer animationTimer = new AnimationTimer(){
#Override
public void handle (long now){
listFireParticles.addAll(addFireParticles(200,200));
for(Iterator<FireParticles> iteratorFirePart = listFireParticles.iterator(); iteratorFirePart.hasNext();){
FireParticles fireParticle = iteratorFirePart.next();
fireParticle.particlesUpdate();
if(!fireParticle.isAlive()){
iteratorFirePart.remove();
continue;
}
fireParticle.render(graphicsContext);
}
Canvas canvas = new Canvas (400, 400);
graphicsContext = canvas.getGraphicsContext2D();
animatedBackground.getChildren().add(canvas);
}
};
animationTimer.start();
System.out.println("ANIMATION");
}
You are creating a new canvas for each animation frame, rather than reusing an existing one.
You take a Pane and you add a new Canvas to it.
You do this an AnimationTimer handle method.
The timer method is called each pulse.
Be default, JavaFX generates a pulse sixty times a second.
In one second, your pane will contain sixty canvases.
In a minute there will be 3600 canvases.
In a day there will be five million one hundred and eighty four thousand canvases.
At some point before that, something is going to slow down and break.
FAQ
How would I make the canvas stop being created so many times? I can't figure it out.
Remove the lines which create a canvas and add it to the scene graph from the animation timer handle method.
Create the canvas and add it to the scene graph (e.g. a pane) only once, outside of the handle method.
Store a reference to the canvas and access the reference in the handle method.
You likely have other issues in code not shown, so don't expect a simple fix as outlined above to just make your application work as you expect.
Perhaps something roughly like this:
final int W = 200;
final in H = 200;
List<FireParticle> fireParticles = createFireParticles(W, H);
Canvas canvas = new Canvas (W, H);
animatedBackground.getChildren().add(canvas);
AnimationTimer animationTimer = new AnimationTimer() {
#Override
public void handle (long now){
GraphicsContext2D graphicsContext = canvas.getGraphicsContext2D();
graphicsContext.clearRect(0, 0, W, H);
if (fireParticles.isEmpty()) {
this.stop();
animatedBackground.getChildren().remove(canvas);
return;
}
for (Iterator<FireParticle> iteratorFirePart = fireParticles.iterator(); iteratorFirePart.hasNext();) {
FireParticle fireParticle = iteratorFirePart.next();
fireParticle.particlesUpdate();
if (!fireParticle.isAlive()){
iteratorFirePart.remove();
continue;
}
fireParticle.render(graphicsContext);
}
}
};
animationTimer.start();
Important: the above code is indicative only. I make no assertion it will exhibit the behaviour you wish. It is untested and won't work stand-alone, I didn't even try to compile it. Without the requested minimal example, that is the best that can be provided.

How to put Object into a panel?

So I have a list of Object, with a random height and weight. I also have a random number of those objects into a variable.
What I'm trying to do is to print all those object into the correct panel (I have 2 panel).
First of, my GUI and Object class (Blocks) are 2 separated class. Into the GUI, I'm doing this :
private JPanel initPanelBloc() {
panelBloc = new JPanel();
bloc = new Bloc(false);
panelBloc.add(bloc);
return panelBloc;
}
My Bloc class :
public class Bloc extends JPanel{
private int hauteur, largeur, nombreBloc;
private boolean premierPassage = true;
private ArrayList<Bloc> listeBlocRestant;
private Random rand = new Random();
public Bloc(boolean premierPassage) {
this.hauteur = 10 + rand.nextInt(50 - 10);
this.largeur = 10 + rand.nextInt(50 - 10);
listeBlocRestant = new ArrayList<Bloc>();
if(premierPassage == true) {
this.nombreBloc = 5 + rand.nextInt(30 - 5);
insererBlocList();
}
}
public ArrayList<Bloc> insererBlocList(){
premierPassage = false;
for(int i=0; i<nombreBloc; i++) {
Bloc bloc = new Bloc(false);
listeBlocRestant.add(bloc);
}
return listeBlocRestant;
}
public void paintComponent(Graphics2D g) {
Graphics2D g2 = (Graphics2D) g;
g2.fillRect(10, 20, this.largeur, this.hauteur);
}
I've got also a 3rd class where I call the GUI class :
public Optimisation() {
this.aff = new InterfaceGraphique();
}
And its in the above class where I need to do what I want.
I did not write in this what I want to do because I still don't know how to do it. Should I create a for each loop and take the list of blocks and for every blocks I want them to be print on the panel, with an x and y (of the fillRect) change between blocs ? I'm really lost, I tried to think about this yesterday but still no clue..
Cordially
I'm lost lol I do not understand everything in there since its with the click and so on
Well, the clicks are really not relevant to the painting concept.
The painting concept is you store the object you want to paint in an ArrayList. Then in the paintComponent() method you iterate through the ArrayList to paint each object.
In my example you have a method addRectangle(...) which adds one Rectangle object at a time. You can manually add a Rectangle by invoking this method without using a mouse. This allows you to add Rectangles of a different size/location/color.
For example you just change the code as follows:
private static void createAndShowGUI()
{
DrawingArea drawingArea = new DrawingArea();
drawingArea.addRectangle(new Rectangle(10, 10, 200, 100), Color.RED);
drawingArea.addRectangle(new Rectangle(210, 110, 20, 100), Color.BLUE);
Now the red rectangle will appear when you run the code.
The key points are:
you need a way to add the object you want to paint to your class
you then need to paint these objects in your paintComponent() method. You can't hardcode the painting the way you are currently doing it.
In your code your Bloc object will need to contain the information needed to paint the bloc.

Prefuse : Organizing edges for clarity

I'm working on my personal family tree in Java/Eclipse, and happily bumped into prefuse as for graphic representation.
So far the result looks adaquate in regard to my database feed, but I'm still missing key points to make it easier to browse.
Point 1: verteces represent either a person or a union, and my graph is directed from older to younger members. This is reflected by the arrows on the edges. Yet I'd love to group the arrows in 1 direction only (I'm trying to group generations together if you like), but I can't start to find how to do that. For information, I'm using the NodeLinkTreeLayout as of now.
Point 2: aside from the graph itself, my app main window contains a second JPanel where I would like to modify / insert members. So I want to add an action to each node to call the procedures in the second JPanel. My research on how to access a java class from a node are inconclusive so far, it seems that all the examples from the starter prefuse pack are only based on graph interaction.
There it is. You might already have understood that I'm very new to prefuse and not a pro in Java. So any comment / directions / advice would really be appreciated. I will add a screecap and my graph code so you can see what could be done better.
Thank you for your time, and looking forward to reading your insights.
yorran
public class ShowGraph extends Display {
public static final String EDGES = "graph.edges";
public ShowGraph() {
super(new Visualization());
Graph mG = FamGraph.getGraph();
m_vis.addGraph("graph", mG);
m_vis.setInteractive("graphe.edges", null, false);
m_vis.setValue("graph.nodes", null, VisualItem.SHAPE, new Integer(Constants.SHAPE_ELLIPSE));
EdgeRenderer edgeR = new EdgeRenderer(Constants.EDGE_TYPE_CURVE, Constants.EDGE_ARROW_FORWARD);
LabelRenderer nodeR = new LabelRenderer("name");
nodeR.setRoundedCorner(8, 8);
nodeR.setHorizontalAlignment(Constants.LEFT);
DefaultRendererFactory drf = new DefaultRendererFactory();
drf.setDefaultRenderer(nodeR);
drf.setDefaultEdgeRenderer(edgeR);
m_vis.setRendererFactory(drf);
int[] palette = new int[] {
ColorLib.rgb(255, 180, 180), ColorLib.rgb(190, 190, 255)
};
DataColorAction nFill = new DataColorAction("graph.nodes", "label", Constants.NOMINAL, VisualItem.FILLCOLOR, palette);
ColorAction edges = new ColorAction("graph.edges", VisualItem.STROKECOLOR, ColorLib.gray(230));
ColorAction arrow = new ColorAction("graph.edges", VisualItem.FILLCOLOR, ColorLib.gray(230));
ColorAction text = new ColorAction("graph.nodes", VisualItem.TEXTCOLOR, ColorLib.gray(0));
ActionList color = new ActionList();
color.add(nFill);
color.add(edges);
color.add(arrow);
color.add(text);
ActionList layout = new ActionList(Activity.INFINITY);
//layout.add(new ForceDirectedLayout("graph", true));
layout.add(new NodeLinkTreeLayout("graph"));
layout.add(new RepaintAction());
m_vis.putAction("color", color);
m_vis.putAction("layout", layout);
setSize(1200, 900); //size controlled by parent jpanel - Comment out after tests
pan(360, 250);
setHighQuality(true);
addControlListener(new DragControl());
addControlListener(new PanControl());
addControlListener(new ZoomControl());
addControlListener(new ZoomToFitControl());
m_vis.run("color");
m_vis.run("layout");
}
public static void main(String[] args) {
Fulltree.fireUp();
ShowGraph mG = new ShowGraph();
JFrame frame = new JFrame("My family chart");
JPanel thePanel = new JPanel();
frame.getContentPane().add(thePanel);
thePanel.add(mG);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}
So after a lot of reseach, I'm answering to my own questions in case someone meets the same issues :
as for point 1 : ForceDirectedGraph is a lot better than NodeLinkTreeLayout, especially when your graph starts counting many members. Family branches make a lot more sense than viewing generations aligned.
as for point 2 : node related actions are the way to go, through a ControlListener:
addControlListener(new ControlAdapter() {
public void itemClicked(VisualItem item, MouseEvent e) {
// anything you need here
// even filter right and left click for a sub menu
}
});
One more thing : if you add actions to your graph (search, predicates...), make sure to stop them if you need to rebuild your graph at some point. If you don't, your actions will generate errors you will spend hours (if not days) to debug.

Drawing Overlapping Images in Libgdx with a Table

Basically, I'm trying to draw an empty health bar as an image, and then the actual health bar on top of it as another image so that I can just shorten the actual health bar when I need to update it. This is what I have so far:
TextureAtlas HUDatlas = new TextureAtlas(Gdx.files.internal("data/ui/HUDPack/textures.pack"));
emptyPlayerHealthBar = new Image(HUDatlas.findRegion("empty-health-bar"));
playerHealthBar = new Image(HUDatlas.findRegion("health-bar"));
//Creating the table
table = new Table(skin);
table.debug();
table.setBounds(0, 0, Gdx.graphics.getWidth(), 50);
table.left();
table.top();
table.add(playerHealthBar);
table.add(emptyPlayerHealthBar);
stage.addActor(table);
But this draws them side-by-side. How do I draw it so that the images are overlapping (empty-health-bar on the bottom and health-bar on top)?
I used this code to place a diamond over a box:
Image boxImage = new Image(Assets.instance.gifts.box);
Image diamondImage = new Image(Assets.instance.gifts.diamond);
Stack diamondBox = new Stack();
diamondBox.addActor(boxImage);
diamondBox.addActor(diamondImage);
tbl.add(diamondBox).width(20).height(20);
tbl.row();
You should probably use Scene2D's WidgetGroup (or, if you're not using layout managers, e.g. Table, Group) for that, e.g.
TextureAtlas HUDatlas = new TextureAtlas(Gdx.files.internal("data/ui/HUDPack/textures.pack"));
emptyPlayerHealthBar = new Image(HUDatlas.findRegion("empty-health-bar"));
playerHealthBar = new Image(HUDatlas.findRegion("health-bar"));
// creating the group
WidgetGroup group = new WidgetGroup();
group.addActor(playerHealthBar);
group.addActor(emptyPlayerHealthBar);
// creating the table
table = new Table(skin);
table.setBounds(0, 0, Gdx.graphics.getWidth(), 50);
table.debug().left().top().add(group);
stage.addActor(table);
Note that you can offset those bars simply by using .setPosition() on them, as usual with libGDX's 2.5D objects. Also, you can make your libGDX code more concise by using method chaining, although that's mostly a matter of style.

JavaFX - SWT interop: application freezes

I am building a RCP application, based on Eclipse 3.5. Thanks to two articles (1, 2) that I've found on oracle.com, I have been able to implement a working RCP view, that displays a pie chart.
Unfortunately, if I close the view and reopen it, then the applications freezes and never comes back.
I am using JavaFX 2.2.7, under JDK 1.6.0.31 on Windows 7 X64.
Here is the code. The view is a standard subclass of org.eclipse.ui.part.ViewPart.
Composite panel = new Composite(parent, SWT.NONE);
RowLayout layout = new RowLayout();
panel.setLayout(layout);
FXCanvas fxCanvas = new FXCanvas(panel, SWT.NONE) {
#Override
public Point computeSize(int wHint, int hHint, boolean changed) {
getScene().getWindow().sizeToScene();
int width = (int) getScene().getWidth();
int height = (int) getScene().getHeight();
return new Point(width, height);
}
};
Scene scene = new Scene(new Group());
RGB rgb = panel.getBackground().getRGB();
Color color = Color.rgb(rgb.red, rgb.green, rgb.blue);
scene.setFill(color);
ObservableList<PieChart.Data> pieChartData = FXCollections.observableArrayList();
pieChartData.add(new PieChart.Data("label1", 20));
pieChartData.add(new PieChart.Data("label2", 20));
pieChartData.add(new PieChart.Data("label3", 20));
pieChartData.add(new PieChart.Data("label4", 20));
pieChartData.add(new PieChart.Data("label5", 20));
Chart chart = new PieChart(pieChartData);
chart.setLegendSide(Side.RIGHT);
((Group) scene.getRoot()).getChildren().add(chart);
fxCanvas.setScene(scene);
Can anyone help?
The issue is solved. It was caused by some Thread naming tweaks somewhere else in the app. There are definitely things that one should not do. Overly relying on thread names is one of them. :)
A utility class was relying on thread names to run code in the UI thread and because JavaFX changes the name of the running thread, the utility class would not work correctly anymore.

Categories

Resources