Why doesn't this code work. There are no errors, but nothing is drawn.
The render method contains:
effect = new ParticleEffect();
effect.setPosition(200, 200);
effect.start();
float delta = Gdx.graphics.getDeltaTime();
GL10 gl = Gdx.app.getGraphics().getGL10();
gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
spriteBatch.begin();
effect.draw(spriteBatch, delta);
spriteBatch.end();
If you are creating a new effect every frame, it will never move or do anything, since it will be reset each frame. You should create the effect outside your loop.
I don't know how the particleeffect will be with no setup. So you should also try adding a texture and set it's preferences.
I think only creating constructor for the ParticleEffect does not suffice, so you have to load particle effect file using effect object you have created in the following manner. Also you have to take this thing out of the loop.
effect.load(Gdx.files.internal("data/yellow_particle"),
Gdx.files.internal("data"));
Run once:
effect = new ParticleEffect();
effect.load(Gdx.files.internal("path/to/your/particle.p", "directory/with/your/particle/png"));
effect.setPosition(200, 200);
effect.start();
Run in render:
spriteBatch.begin();
effect.draw(spriteBatch, delta);
spriteBatch.end();
And in dispose:
effect.dispose();
Particle.png can be copied from libgdx sources for example:
https://github.com/libgdx/libgdx/blob/master/extensions/gdx-tools/assets/particle.png
And watch again the video tutorial - you are messing and missing many things:
http://www.youtube.com/watch?v=LCLa-rgR_MA
The tutorial itself covers less things, than video, but pasting here for hope it will be updated:
https://github.com/libgdx/libgdx/wiki/2d-particle-effects
Make the particle-effects in your class's constructor. Dont make particle-effects objects every time in your render method. Thats why, your particle effects are initializing every time, and you cant see anything.
Related
I have a problem with my texture. The table works perfect, but when I try to add a texture Android Studio doesn't agree with me.
private Sprite tiger2;
.
batch.begin();
batch.setColor(tiger2.getColor());
batch.draw(
tiger2,
Gdx.graphics.getWidth() / 2f - tiger2.getRegionWidth() / 2f,
Gdx.graphics.getHeight() / 2f - tiger2.getRegionHeight() / 2f,
tiger2.getRegionWidth(),
tiger2.getRegionHeight()
);
batch.end();
.
tiger2 = new Sprite(new Texture("tiger2.png"));
.
I don't know if this is how I should write it:
table.add(tiger2);
I get this error:
Cannot resolve method 'add(com.badlogic.gdx.graphics.g2d.Sprite)'
table.add(**tiger2**);
You are trying to add a Sprite to the table not a Texture and this is the core reason why you are having problems. It is basically the same as doing int i = "Hello World" which would yield a error like incompatible types. In other words a Integer container cannot hold a String.
If you hover over the line you will see that table.add expects a actor. If you would go to the definition of Sprite you notice that this does not extend Actor in any way. So doing Actor a = new Sprite() results in the same error as above, you cannot put a Sprite object in a Actor container. These are core fundamentals of programming.
So what are compatible Actors? Everything that inherits Actor such as Label, TextButton, Table, ScrollPane, Window, Dialogue, etc. You can extend Action yourself too and create your very own Actor, but since you are struggling with this you should wait with this.
The easiest solution is to use scene2d.ui.Image. If you inspect this class you see it extends from Widget and if you inspect Widget you see it extends from Actor and thus Image is a actor since you are a child of your mother and your mother of your grandmother.
If you inspect what the Image constructor takes then you will notice the easiest thing to do is to create a SpriteDrawable, since Image does not take a Sprite like table.add does not take a Sprite either. SpriteDrawable takes a sprite and is a Drawable and that is compatible with the constructor of Image.
Image image = new Image(new SpriteDrawable(mySprite));
table.add(image);
Image takes a Texture too so if you are not doing fancy Sprite stuff with your sprite you can just create the Image with a Texture as well. You can see this in your IDE by typing new Image( and intellisense will let you know the compatible constructors.
Try to understand these types and use your IDE and the documentation to find out what you can use. With Android Studio you can right click a class and do goto -> declaration and see the class in question. Other IDE's have equivalent methods unless you are using something like Notepad of course.
Assuming the table is a Scene2D Table:
A texture is not an actor and cannot be added to a table. To fix this you can add the texture to an Image (an actor containing a texture). It would look something like this:
Image tiger2Image = new Image(new Texture("tiger2.png"));
table.add(tiger2Image);
The problem:
I've been creating a Snake game in Java and everything is working smoothly. The only problem I've having is displaying the score. Each time the snake "eats" an apple, the score increases by 10. Instead of displaying the current score, it simply writes over the present score without actually erasing it. When I attempt to erase the content before re-displaying, I get an error and nothing appears, other than my background colour.
I have other Graphics components, including a paint() that I do NOT want affected.
My attempt (theoretical):
I display the score using a Graphics object that calls
drawString("Current score: " + currScore, 0, (Constants.TOTAL_HEIGHT + 15));
I figured I have to call a clearRect() method, which makes sense to me. Unfortunately, I get a NullPointerException at the line specifying clearRect().
I'm not using Graphics2D just so I can first be familiar with Graphics. If resolving this issue involves Graphics2D, I have no problem using it.
My attempt (the method in question):
public void displayScore(Graphics g) {
//clearScore.clearRect(0, getY(), getWidth(), getHeight());
//g.clearRect(0, getY(), getWidth(), getHeight());
g.drawString("Current score: " + currHighScore, 0, (Constants.TOTAL_HEIGHT + 15));
}
In the code, clearScore is a Graphics object declared in the class outside of any methods. My reason for using this was to avoid affecting the other graphics. I attempted each of the clearRect() lines and both produced the same NullPointerException, which is why I have them commented out.
(Constants.TOTAL_HEIGHT + 15) is responsible for assigning the Y-coordinate.
The Error Message:
Exception in thread "Thread-3" java.lang.NullPointerException
at com.nmw.view.CanvasFrame.displayScore(CanvasFrame.java:149)
at com.nmw.view.CanvasFrame.drawAll(CanvasFrame.java:43)
at com.nmw.view.CanvasFrame.run(CanvasFrame.java:64)
at java.lang.Thread.run(Thread.java:722)
drawAll is where I call all of my methods that take in Graphics to draw a segment of the game.
Apologies for the lengthy question =/
Your problem is that you are likely trying to draw with a null Graphics object. This usually occurs if you are not drawing within the paint(...) method if AWT or paintComponent(...) if Swing. The solution,
draw within one of those two methods (depending on the library you're using).
Always call the super's method within your painting method.
Or use a Label (AWT) or JLabel (Swing) to display the data.
To be blunt, your statement: "I have other Graphics components, including a paint() that I do NOT want affected." -- is an unrealistic requirement if this is an AWT project and if you don't want to use a Label.
And this statement:
In the code, clearScore is a Graphics object declared in the class outside of any methods. My reason for using this was to avoid affecting the other graphics.
Is not how you should do drawing, ever. You're finding out now why. If you happen to get a Graphics context during the running of the program, use it to assign Graphics to your class field, and then try to use that class field, you'll often get the NPE like you're seeing because a Graphics object thus obtained is not long-lasting.
If you need more in-depth help, please post your actual assignment requirements and more code. In particular your drawing methods. Best would be to create and post an sscce.
Edit
You state in comment:
My Snake game is an independent project I've been doing to learn more about Graphics. I've only been using the AWT library, however, I'll try using a Label. Thank you for your response and explanation of why I got the NullPointerException
If this is for your own project and not a school assignment, then I think that you will want to avoid using AWT and instead use Swing. It is much more powerful and flexible than AWT. There really is no reason why you'd want to use AWT now adays.
I'm working on a painting application using the LibGDX framework, and I am using their FrameBuffer class to merge what the user draws onto a solid texture, which is what they see as their drawing. That aspect is working just fine, however, the area the user can draw on isn't always going to be the same size, and I am having trouble getting it to display properly on resolutions other than that of the entire window.
I have tested this very extensively, and what seems to be happening is the FrameBuffer is creating the texture at the same resolution as the window itself, and then simply stretching or shrinking it to fit the actual area it is meant to be in, which is a very unpleasant effect for any drawing larger or smaller than the window.
I have verified, at every single step of my process, that I am never doing any of this stretching myself, and that everything is being drawn how and where it should, with the right dimensions and locations. I've also looked into the FrameBuffer class itself to try and find the answer, but strangely found nothing in there either, but, given all of the testing I've done, it seems to be the only possible place for this issue to be created somehow.
I am simply completely out of ideas, having spent a considerable amount of time trying to troubleshoot this problem.
Thank you so much Synthetik for finding the core issue. Here is the proper way to fix this situation that you elude to. (I think!)
The way to make frame buffer produce a correct ratio and scale texture regardless of actual device window size is to set the projection matrix to the size required like so :
SpriteBatch batch = new SpriteBatch();
Matrix4 matrix = new Matrix4();
matrix.setToOrtho2D(0, 0, 480,800); // here is the actual size you want
batch.setProjectionMatrix(matrix);
I believe I've solved my problem, and I will give a very brief overview of what the problem is.
Basically, the cause of this issue lies within the SpriteBatch class. Specifically, assuming I am not using an outdated version of the class, the problem lies on line 181, where the projection matrix is set. The line :
projectionMatrix.setToOrtho2D(0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
This is causing everything that is drawn to, essentially, be drawn at the scale of the window/screen and then stretched to fit where it needs to afterwards. I am not sure if there is a more "proper" way to handle this, but I simply created another method within the SpriteBatch class that allows me to call this method again with my own dimensions, and call that when necessary. Note that it isn't required on every draw or anything like that, only once, or any time the dimensions may change.
I'm planning to write a simple spaceshooter. I have read that the repaint() method is only a request, and it doesn't execute every time it's called. I believe I'm noticing the effects of this, as my spaceship tends to lag ever so slightly when I'm moving it. Currently I'm simply drawing my ship in a a JPanel's paintComponent() method, and keep calling repaint() on regular intervals (my panel's also Runnable). Seeing as repaint() may potentially screw me over, I'm trying to find a way to work arround it, however I've ran out of ideas. The code I have so far:
private void renderGraphics() {
if (MyImage == null) {
MyImage = new BufferedImage(getPreferredSize().width,
getPreferredSize().height, BufferedImage.TYPE_INT_RGB);
}
MyGraphics = MyImage.getGraphics();
MyGraphics.setColor(Color.BLACK);
MyGraphics.fillRect(0, 0, getPreferredSize().width, getPreferredSize().height);
MyGraphics.drawImage(ship.getImage(), ship.getCurrentX(), ship.getCurrentY(), null);
}
The idea was to create my own graphics, and then make the JPanel draw it, and keep calling this instead of repaint() in my run() method, however I have no idea how to do that. I'd appriciate any input on the matter.
There are multiple ways to approach this.
The best is probably to use BufferStrategy and draw to that, of which I have included a code snippet that should work for you.
You can take this one step further and abandon Swing altogether, just using Frame/BufferStrategy. There is a fully working example (from which the code snippet was taken and adapted) in my question here:
AWT custom rendering - capture smooth resizes and eliminate resize flicker
Anyway, here is an implementation BufferStrategy that you should be able to just drop in:
// you should be extending JFrame
public void addNotify() {
super.addNotify();
createBufferStrategy(2);
}
private synchronized void render() {
BufferStrategy strategy = getBufferStrategy();
if (strategy==null) return;
sizeChanged = false;
// Render single frame
do {
// The following loop ensures that the contents of the drawing buffer
// are consistent in case the underlying surface was recreated
do {
MyGraphics draw = strategy.getDrawGraphics();
draw.setColor(Color.BLACK);
draw.fillRect(0, 0, getPreferredSize().width, getPreferredSize().height);
draw.drawImage(ship.getImage(), ship.getCurrentX(), ship.getCurrentY(), null);
draw.dispose();
// Repeat the rendering if the drawing buffer contents
// were restored
} while (strategy.contentsRestored());
// Display the buffer
strategy.show();
// Repeat the rendering if the drawing buffer was lost
} while (strategy.contentsLost());
}
any drawing will still be performed in the Swing Thread, so no matter what you try work around, it wont help.
Make sure you are not doing any lengthy calculations in the swing thread, this may be stopping repaint from being executed as soon as it needs to be executed
Separate all the logic into 2 parts. Static and Dynamic. (e.g. sea and moving ship. Ship changes shape/location on a static image of sea)
Draw static content in an image once and use the image in your paintComponent(). Call dynamic parts painting after the static image.
Use setClip() to restrict repainting areas.
Calling repaint without any arguments means that the whole panel is repainted.
If you need to repaint parts of the screen (the spaceship has moved to a different location) you should make shure that only those parts of the screen are repainted. The areas that stay the same should not be touched.
Repaint takes coordinates of a rectangle that should be repainted. When moving the ship you should know the old coordinates of the ship and the coordinates the ship should move to.
repaint( oldShipCoordinateX, oldShipCoordinateY, shipWidth, shipLength );
repaint( newShipCoordinateX, newShipCoordinateY, shipWidth, shipLength );
This is usually much faster than calling repaint() without arguments. However you have extra effort to remember the last position of the ship and must be able to calculate the new position of the ship.
See also: http://download.oracle.com/javase/tutorial/uiswing/painting/index.html - especially step 3
Just for code that you post here:
1/ if you want to display Image/ImageIcon, then the best and easiest way is to Use Labels
2/ as you mentioned Runnable{...}.start(); Swing is simple threaded and all output to GUI must be done on EDT; you have to look at Concurrency in Swing, result is that all output from BackGround Task(s) must be wrapped into invokeLater(), and if is there problem with perfomancie then into invokeAndWait()
3/ if you be switch (between JComponents)/add/delete/change Layout then you have to call revalidate() + repaint() as last lines in concrete code block
EDIT:
dirty hack would be paintImmediately()
I have read that the repaint() method is only a request, and it doesn't execute every time it's called
It consolidates multiple repaint() requests into one to be more efficient.
I believe I'm noticing the effects of this, as my spaceship tends to lag ever so slightly when I'm moving it.
Then post your SSCCE that demonstrates this problem. I suspect the problem is your code.
Regarding the solution you accepted, take a look at Charles last posting: Swing/JFrame vs AWT/Frame for rendering outside the EDT comparing Swing vs AWT solutions.
As part of a larger project I'm trying to implement a facility using JOGL that will export 3D renderings to bitmap formats. We do this by creating a GLJPanel and drawing the scene we want to it, then extracting the bitmap. This all works fine as long as the system has at least one visible window on the screen - not necessarily the window containing the panel we are drawing to.
But if we try to do this without making any window visible the GLJPanel won't draw. Stepping through the JOGL source I find that it won't draw unless it has a valid peer - essentially unless addNotify() has been called on it. The documentation says that addNotify() is only called when the panel is made part of a visible window heirarchy. Changing to a GLCanvas doesn't make much difference - the failure mode is different. WindowsOnscreenGLDrawable.realized is not set, and this means lockSurface returns LOCK_SURFACE_NOT_READY, causing makeCurrent() to fail.
Any help would be welcome on how to create a Java app that can create and export 3D scenes without having to make it's window visible.
Not sure if I should be answering my own question, but here goes with what I found seems to work now.
The key is GLPbuffer, which is an offscreen GLAutoDrawable and can be created without a visible component heirarchy.
This article was helpful in getting it to work. I'll leave off accepting this answer until I've confirmed it's fully functional.
I should also say that the answer came from this forum, not my own meagre brain.
You should look into method: glReadPixels() more info here. Basically it works more or less like this:
Init(); //doing some initializations in your JOGL app
glDrawBuffer(GL_BACK);
DrawGLScene(); //doing drawing here
glReadBuffer(GL_BACK);
//Copy the image to the array imageData
glReadPixels(0, 0, WIDTH, HEIGHT, GL_RGBA, GL_UNSIGNED_BYTE, imageData);