Java - double buffering NullPointerException - java

I'm writing a simple game. I have 3 classes the first one: ball which take care of every thing refereed to it, the second one game which made out of an array of "ball"s and the final one is windows, the one which contains the MAIN thread.
window.paint calls game.draw in order to receive the graphics of the game scene.While the game itself double buffering it in order that the Image object can be moved to the Player's ball location(yet to be implemented).
So my problem caused because I'm creating an Image object but somewhy this initialized to null, thus I get NullPointerException.
Here is the source of the methods which handle the painting:
public class MyWindow extends JFrame {
//...the other code
public void paint(Graphics g){
thegame.draw();
repaint();
}
}
public class Game extends JFrame implements Runnable {
ball[] cellmap;
//...the other code
public void draw(){
Image GameImage = createImage(800,800);
Graphics GameGraphics = GameImage.getGraphics();
for(int i = 0;i<cellmap.length;i++)
cellmap[i].draw(GameGraphics);
g.drawImage(GameImage, 0, 0, this);
}
}
public class Ball extends JFrame {
//...the other code
public void draw(Graphics g){
g.setColor(Color.red);
g.fillOval((int)(this.x+this.radious),(int)(this.y+this.radious),
(int)this.radious,(int)this.radious);
}
}

1) please read Java Naming Conventions
2) not good idea paint directly to the JFrame, put your painting to the JComponent, JLabel, JPanel
3) for Painting in Swing use method paintComponent, please not methods paint(Graphics g) or draw(Graphics g)
4) if you want to delay or animate you painting use javax.swing.Timer

Related

Swing - stop image from blinking

I have been practicing with java's swing features recently, and in one of my classes that extends the class JPanel, I have overriden the method paintComponent() so that it will paint my BufferedImage onto the JPanel. I also have a method on it to move around. Before this issue, I have had a problem that shows the process of moving as it repaints too quickly. So, I created a boolean variable called available which is set to false when the image is still in the moving process. But, now I see that the screen is taking away the entire image and putting it back, causing it to blink. Here is my basic pseudocode:
class A extends JPanel{
BufferedImage canvas;
public A(){
//create image here
}
public move(){
available = false;
//move things around in here
available = true;
}
#Override
protected void paintComponent(Graphics g){
super.paintComponent(g);
if(available){
g.drawImage(this.canvas, 0, 0, null);
}
g.dispose();
}
}
class B{
public static void main(String[] args){
//construct the class A JPanel
while(some_variable){
class_A_JPanel.repaint();
}
}
}
This is very old topic which is fixed in modern Java. But you prefer old way then use old techniques. For example Double Buffering

Draw and move a circle in Java

I'm using Swing to create a small GUI in Java. All I am trying to get it to do is take an ArrayListof Circles and draw them. I've run into two problems:
1) I have to call my draw method repeatedly before it draws the circle. If I just call my draw method once nothing happens, I get a blank drawing. If I call it in a loop that runs for less than 30 milliseconds it only draws the first of two circles that I want to draw. Finally, if I call it for more than 30 milliseconds it draws both circles I am trying to draw.
and
2) When I move one of the circles, I get a "flicker" on the drawing.
I'm not too familiar with Swing programming. I've looked at sample code and watched a few videos - and what I have looks right to me. But I figure I must have messed something up, because it doesn't look like this in the videos I've watched.
Here is my GUI class:
package gui;
import draw.*;
import java.util.List;
import javax.swing.*;
public class GUI extends JFrame {
private CirclePainter drawingBoard = new CirclePainter();
public GUI()
{
setSize(500, 500);
this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
this.setVisible(true);
this.add(drawingBoard);
drawingBoard.setVisible(true);
}
public void draw(List<Circle> circles)
{
drawingBoard.paintComponent(drawingBoard.getGraphics(), circles);
}
}
my CirclePainter class
package gui;
import draw.Circle;
import javax.swing.*;
import java.awt.*;
import java.util.List;
class CirclePainter extends JPanel
{
public void paintComponent(Graphics graphics, List<Circle> circles)
{
super.paintComponent(graphics);
for(Circle circle : circles)
graphics.fillOval(circle.getX(), circle.getY(), circle.getRadius() * 2, circle.getRadius() * 2);
}
}
EDIT: redacted some code since this is for a school project. The remaining code should be enough for someone visiting in the future to still understand the question.
Never call paintComponent(...) directly as you're doing.
Instead suggest a draw by calling repaint() on a component when necessary.
Don't draw with a Graphics object obtained via a getGraphics() call on a component. Instead, draw with the Graphics object provided in the paintComponent method.
Avoid using while (true) loops in a Swing GUI as you risk tying up the Swing event thread and freezing the GUI. Use a Swing Timer for simple animations.
You probably don't even need a Swing Timer since your animation can be driven by your MouseListener/MouseMotionListener.
Most important -- do read the Swing painting and other tutorials, as most of this information can be found there. It looks like you're guessing how to do some of your coding and that's a dangerous thing to do when it comes to drawing or animating a GUI. You can find most tutorials in the Swing info link.
Consider using a Shape object to represent your Circle, such as an ellipse2D. The reason that this will help is that it has some very useful methods, including a contains(Point p) method that will help you determine if a mouse click lands inside of your circle.
You will want to decide where _x and _y represent the center point of your circle or not. If so, then you'll need to adjust your drawing some, by shifting it left and up by _radius amount.
Consider casting your Graphics object into a Graphics2D object in order to use its extra methods and properties.
One such property are the RenderingHings. Set your Graphics2D RenderingHints to allow for anti-aliasing to get rid of your image "jaggies". This can be done with: g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON); where g2 is your Graphics2D object.
Your paintComponent method is not a true paintComponent override and thus won't work correctly. It should be a protected method, not public, it should have one parameter, a Graphics object, and nto a second parameter, and you should place the #Override annotation above it.
For example, please have a look at this answer of mine to a similar problem.
An example of a paintComponent method that centers the circles on _x and _y and that uses rendering hints:
class CirclePainter extends JPanel implements Iterable<Circle> {
private static final int PREF_W = 500;
private static final int PREF_H = PREF_W;
private CircleList circleList = new CircleList();
#Override
protected void paintComponent(Graphics graphics) {
super.paintComponent(graphics);
Graphics2D g2 = (Graphics2D) graphics;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
for (Circle circle : circleList) {
// if x and y are the center points, then you must subtract the radius.
int x = circle.getX() - circle.getRadius();
int y = circle.getY() - circle.getRadius();
int width = circle.getRadius() * 2;
int height = width;
g2.fillOval(x, y, width, height);
}
}
Building on your code and the suggestions from Hovercraft Full Of Eels, a small step in the right direction could be taken with these modifications to the GUI and CirclePainter classes:
// GUI.draw
public void draw(List<Circle> circles)
{
// drawingBoard.paintComponent(drawingBoard.getGraphics(), circles);
drawingBoard.setCircles(circles);
drawingBoard.repaint();
}
class CirclePainter extends JPanel
{
// public void paintComponent(Graphics graphics, List<Circle> circles)
// {
// super.paintComponent(graphics);
// for(Circle circle : circles)
// graphics.fillOval(circle.getX(), circle.getY(), circle.getRadius() * 2, circle.getRadius() * 2);
// }
private List<Circle> circles;
public void setCircles(final List<Circle> circles) {
this.circles = circles;
}
#Override
protected void paintComponent(final Graphics graphics) {
super.paintComponent(graphics);
for (Circle circle : circles)
graphics.fillOval(circle.getX(), circle.getY(), circle.getRadius() * 2, circle.getRadius() * 2);
}
}
This way, you might not have fixed all the fundamental issues, but you get your program to work with only minor changes. And Swing is a very nice library that can be much fun to learn more about.

Java Drawing Graphics

I am making a game in Java and I have a canvas class, which has the game tick, and I draw the images on the canvas using
public void paint(Graphics g) {
// draw stuff here
}
I want to move all the drawing functions to my Engine class.
I have this method in my Engine:
#Override
public void render(Graphics scene) {
// draw stuff here
}
In my Canvas I didn't have to call the paint method, but in the Engine I would have to call the render method, but since it takes as an argument Graphics scene, I am kind of at a loss. How would I be able to draw components from my Engine class(using the render method) and not from the Canvas class.
The engine class does not extend any JComponent, but it does initialize the Canvas object
I am making a game in Java and I have a canvas class, which has the
game tick, and I draw the images on the canvas using
note
public void paint(Graphics g) { for awt.Canvas, awt.Panel
public void paintComponent(Graphics g) { for swing.JComponent, swing.JPanel
any painting could be done only for J/Component, good practicies couldn't be move this methods outside of J/Component declarations
I want to move all the drawing functions to my Engine class. I have
this method in my Engine:
is good idea to prepare all Object before paint/paintComponent is executed,
there to put all Objects to the array
inside paint/paintComponent only loop inside arrays of prepared Obects, invoked from Swing Timer, Mouse/Key events
all events for paiting, to AWT/Swing GUI must be done on Event Dispatch Thread
for todays GUI to use Swing JComponent, JPanel and override paintComponent
a few very good code examples are here, tagged by paintComponent
One problem is that there is no way for Engine to know that paint(g) is called, since the call is run on the canvas. So you will most likely need to modify Canvas.paint so that it calls the Engine. It's possible there is some funky listener you could add to Canvas but I think that's probably more complicated than you need.
One way that would work would be to pass an instance of Engine to the Canvas on construction:
public class Engine {
private Canvas canvas;
public Engine() {
Canvas = new Canvas(this);
}
public void render(Graphics g) {
// do stuff
}
}
public class Canvas extends JPanel {
private Engine engine;
public Canvas(Engine engine) {
this.engine = engine;
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
engine.render(g);
}
}

Java graphics trouble

I have a JComponent with a listener on it. On the JComponent, I draw a big image and the mouse listener adds small images where clicks occur (one big map on which I add some dots).
How can I programatically draw something outside the paintComponent method?
public void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
g2.drawImage(img1, 0, 0, this);
g2.finalize();
}
private MouseListener listener;
public void initListener() {
myCanvas = this;
listener = new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
myCanvas.getGraphics().drawImage(img,e.getX(),e.getY(), myCanvas);
}
};
addMouseListener(listener);
}
My problem is with this:
public void drawDot(int x, int y){
myCanvas.getGraphics().drawImage(img, x, y, myCanvas);
}
It doesn't do anything. I have tried repaint().
You can't do this. All drawing occurs in the paintComponent() method. What you should do is build a model that represents what you want to draw, and modify the model in your mouse listener. Then call repaint() to ask that this component be redrawn when the model is modified. Inside your paint() method render the full paint from the model. For example:
List<Point> pointsToDrawSmallerImage = new ArrayList<Point>();
...
listener = new MouseAdapter() {
public void mouseClicked(MouseEvent evt ) {
pointsToDrawSmallerImage.add( evt.getPoint() );
repaint();
}
}
...
public void paintComponent(Graphics g) {
g.clear(); // clear the canvas
for( Point p : pointsToDrawSmallerImage ) {
g.drawImage(img, p.x, p.y, myCanvas);
}
}
You have to manage the drawing inside the paintComponent method. Java Graphics is not stateful, you have to take care of what you actually need to draw whatever you want inside the method. Every time the paint method is called, everything must be drawn again, there is nothing that "stays" on the canvas while adding other components
This means that you should store a list of elements that the paint method will take care to draw, eg. ArrayList<Point> points, then in paint method you should iterate them:
for (Point p : points)
draw the point
so that you just add the point to the list with the listener and call repaint.
You can find guidelines for Swing/AWT drawing here..
A particual API has the behavior you would like to have though, it is called Cocos2D and it has a port for Android/Java that you can find here.
that is not how draw works, the draw method paints everything which is in the method itself on every repaint,
that means if you call a method to draw something once, it will only be drawed for one repaint cycle and that's it.
if you want something t be drawn on click you have to add it on on click to a collection and draw the whole collection in every paint cycle, so it will stay permanently.

Can't run paint method from main method

In the main method, I am trying to run this:
public static void main(String[] args)
{
game.paintBlocks(g);
}
And getting a "cannot be resolved to variable" error for the "g" parameter.
Elsewhere I have this, which calls on another method in another class (paint(g)) to paint a grid of blocks:
public void paintBlocks(Graphics g)
{
for (int r = 0; r<7; r++)
{
for (int c = 0; c<5; c++)
{
block[r][c].paint(g);
}
}
Do I need to tell it that "g" is in another class? I'm new to this and any help would be awesome!
Where do you want to paint to? I'm assuming you probably want to paint to a window on the screen, in which case you won't be calling paint* yourself, you'll let the Swing framework call it at the appropriate times. In this case, if game is a JFrame, then you just need to make it visible; or if game is some other type of component then you'll need to add it to a visible window. This is the pattern I normally use when I'm teaching basic graphics in Java:
public class MyGame extends JPanel {
public static void main() {
JFrame window = new JFrame("My Game");
window.add(new MyGame());
window.pack();
window.setLocationRelativeTo(null); // Centers the window on the screen
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setVisible();
}
public Dimension getPreferredSize() {
return new Dimension(800, 600);
}
protected void paintComponent(Graphics g) {
// Do my drawing here
}
}
If you want to paint to an off-screen image, then you'll need to create your own graphics context to pass to the paint* methods:
BufferedImage hello = new BufferedImage(game.getWidth(), game.getHeight(), BufferedImage.TYPE_INT_ARGB);
Graphics g = hello.getGraphics();
game.paintBlocks( g );
In the case of paintBlocks, g is a parameter that is being passed in to the method. In the case of main, g is referencing a variable that hasn't been created anywhere.
Graphics and Graphics2D are abstract classes, and aren't generally intended to be instantiated except by Swing. What Graphics and Graphics2D give you is a context for drawing on a component (like a JPanel or a BufferedImage).
Based on your description you probably want to draw blocks on a Swing component of some kind. (Though it's a little unclear, that would be a normal kind of thing to do.) What you would normally want to do if you are drawing the blocks on a JPanel, for example, is to create a class that extends JPanel and override the paintComponent() method. One way you might do that:
public class BlocksPanel extends JPanel {
// Normal class fields, etc.
// ...
// I would consider making this private, but this is your method from above:
public void paintBlocks(Graphics g) {
for (int r = 0; r<7; r++) {
for (int c = 0; c<5; c++) {
block[r][c].paint(g);
}
}
}
#Override
public void paintComponent(Graphics g) {
paintBlocks(Graphics g);
}
}
There is another example that might help you on page 9 of this document. The Java Tutorials for the Java 2D API may also help.
The variable g is undefined in the main context because you havent declared/initialised it. If you look at your paintBlocks(Graphics g) method, g is passed as a parameter, however the scope of that variable(g) is within the braces({}) of the method paintBlocks(Graphics g).
If you have a class called MyClass that extends a Component, say JPanel, you can do something like this:
class MyClass extends JPanel
{
public static void main(String[] args)
{
Graphics g = getGraphics(); //would return the graphics object for the JPanel
game.paintBlocks(g);
}
}
Its also good to note that the above method in some cases would be tagged as bad programming style. There is an alternative. You can make use of the paintComponent(Graphics g) method provided by the component.
Your main would then look like this:
public static void main(String[] args)
{
repaint(); //this repaints the component, calling the paintComponent method
}
Its also bad programming style to call paintComponent(Graphics g) yourself. You should allow your system to call that method and thats why you have the repaint() method. The system automatically invokes paintComponent(Graphics g) when you repaint.
From paintComponent(Graphics g) you can then do this:
public void paintComponent(Graphics g)
{
super.paintComponent(g); //repainting the panel,not necessary in some cases
game.paintBlocks(g); //passing the graphics object used by the component
}
Hope that helped!

Categories