Dynamic graphic programming (Animation) - java

I am trying to code a simple animation like a moving circle. I have tried using getGraphics() and work with that but it's not dynamic and it's painted for just one time
So please help me and guide me to code a dynamic graphic program.
I mean for example defining a function and every time when it called, it draws a line on a label.

Here is how to make a growing rectangle:
public class MovingRectangle extends JPanel {
private Timer timer = new Timer(500, new ActionListener() {
public void actionPerformed(ActionEvent event) {
rectWidth += 100;
repaint();
}
};
private int rectWidth = 100;
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawRect(0, 0, 100. rectWidth);
}
public void start() {
timer.start();
}
public void stop() {
timer.stop();
}
public void reset() {
rectWidth = 100;
repaint();
}
}

you should override the paintComponent(Graphic g).
This method is called every time the repaint() is called, so you should periodic calling that method.
You should also set DoubleBuffering on true: setDoubleBuffered(true)
It will prevent possible flicker of your animation

Related

How can I stop a JComponent relocating to the center after using setVisible?

Currently, I am using the setVisible() method to hide and unhide my JComponent together with a timer schedule. However, since my JComponent is an image of which x and y locations I set in the beginning of the paintComponent method, every time setVisible is set to true again, it relocates the image to the center of the JPanel which I do not intend for.
Instead, I want the image to disappear/reappear in the moved location, so it does not get repainted in the beginning position.
//In class of my JFrame, designed for clicking on the image:
#Override
public void mouseClicked(MouseEvent e) {
img.setVisible(false);
TimerTask task = new TimerTask() {
#Override
public void run() {
img.setVisible(true);
}
};
timer.schedule(task, 2000);
}
//In class of my image:
private int x;
private int y;
#Override
public void addNotify() {
super.addNotify();
x = (this.getWidth() - img.getWidth(this)) / 2;
y = (this.getHeight() - img.getHeight(this)) / 2;
}
#Override protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(img, x, y, this);
}

How do I make a graphics change place randomly everytime I click on it

The code I made won't change the coordinates of the ball every time I click on it.
public class AimTrainerPanel extends JPanel implements MouseListener {
static final int WIDTH = 1300;
static final int HEIGHT = 750;
static final int SIZE = 10;
Random rand;
JLabel cd;
int x;
int y;
boolean running = false;
Timer timer;
AimTrainerPanel() {
rand = new Random();
this.setPreferredSize(new Dimension(WIDTH, HEIGHT));
this.setBackground(Color.black);
this.setFocusable(true);
this.setLayout(null);
this.addMouseListener(this);
startGame();
}
public void startGame() {
newDot();
running = true;
timer = new Timer();
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
draw(g);
}
public void draw(Graphics g) {
if (running) {
g.setColor(Color.white);
g.fillOval(x, y, SIZE, SIZE);
}
}
public void newDot() {
x = rand.nextInt((int)(WIDTH/SIZE)) * SIZE;
y = rand.nextInt((int)(HEIGHT/SIZE)) * SIZE;
}
#Override
public void mouseClicked(MouseEvent e) {
int mx = e.getX();
int my = e.getY();
if (mx >= x && mx <= x + 10) {
if (my >= y && my <= y + 10) {
newDot();
}
}
}
#Override
public void mousePressed(MouseEvent e) {
}
#Override
public void mouseReleased(MouseEvent e) {
}
#Override
public void mouseEntered(MouseEvent e) {
}
#Override
public void mouseExited(MouseEvent e) {
}
}
The newDot() method is suppose to create new coordinates every time it is called but the ball won't change places. I don't know if it's because I misswrote something or because my what I did doesn't change the coordinates or if I'm suppose to add something.
I'm not sure what your Timer is supposed to be doing, but it doesn't appear to be a Swing Timer, and since this is a Swing GUI I'd get rid of it.
Now to the crux of your problems:
You're using mouseClicked which isn't called if the mouse moves even slightly between mouse pressed and mouse released, and so often it is better to use mousePressed or mouseReleased methods and not mouseClicked
You don't call repaint() after changing the state of your program. Swing won't know that a repaint is needed unless you suggested, and so in your mouseListener or in code called by it, you should call this method after changing GUI state. Here you can call it at the end of the newDot(...) method or in the mouse listener after you call the same method.
Your if blocks within your mouse listener appear to be quite restrictive as to where they will allow the listener to respond to a mouse click -- is it too restrictive? I don't know since I'm not familiar with your requirements, but possibly.

Having trouble making object move without flickering in Java

I have looked into Double Buffering and plan on implementing it eventually but as of right now I can't figure out how to use it or anything like it. I am trying to make pong so I plan on adding three objects total but for now I just want to get one object to work smoothly. I'm fairly new to graphics so I don't know entirely what I'm doing and I'm just trying to learn as I go.
Here is my code:
Pong:
public static void main(String[]args) {
JFrame window= new JFrame();
window.setTitle("Pong Game");
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setPreferredSize(new Dimension(800,500));
window.pack();
window.setVisible(true);
Ball ball= new Ball();
Paddle player= new Paddle();
window.getContentPane().add(ball);
for(;;) {
ball.move();
//window.setContentPane(ball);
window.setContentPane(player);
player.move();
}
}
Paddles:
double x, y, ymove;
boolean cpu;
public Paddle() {
x=5;
y=180;
ymove=.1;
}
//passing an integer through to make the computer paddle
public Paddle(int a) {
cpu= true;
x=761;
y=180;
ymove=.1;
}
public void paint(Graphics g) {
g.setColor(Color.blue);
g.fillRect((int)x, (int)y, 18, 120);
}
public void move() {
y+=ymove;
if(y>=500-160||y<=0) {
ymove*=-1;
}
}
Ball:
double x, y, xspeed, yspeed;
public Ball() {
x=200;
y=200;
xspeed=0;
yspeed=.1;
}
public void move() {
x+=xspeed;
y+=yspeed;
if(y>=440||y<=0) {
yspeed*=-1;
}
}
public void paint(Graphics g) {
g.setColor(Color.black);
g.fillOval((int)x, (int)y, 20, 20);
}
This Answer is a very very simplified explanation! I recommend checking out this linux journal, which explores something similia.
The main issue, which causes the "flickering" is, that the draw is done "to fast".
Take your main loop:
for(;;) {
ball.move();
window.setContentPane(ball);
window.setContentPane(player);
player.move();
}
This loop updates the positions of the ball and afterwards "adds it to the content pane". While it is drawn, the next image is already added and drawn. This is causing the flickering (again, note: this is very simplified).
The simplest solution to fix the "flickering" is, to let the Thread sleep after it has drawn and "wait" until the draw is finished.
boolean running = true;
int delay = 15; // adjust the delay
while(running) {
ball.move();
player.move();
window.setContentPane(ball);
window.setContentPane(player);
try {
Thread.sleep(delay);
} catch(InterruptedException e) {
// We were interrupted while waiting
// Something "woke us up". Stop the loop.
e.printStackTrace();
running = false;
}
}
This Thread.sleep method let's the current Thread "wait" for the specified time.
The delay can be adjusted to something more practical. You could for example calculate how many frames you want and sleep for that amount.
Another way would be to "time" the updates. This could be done with a timer. Since it is more or less deprecated, i implement it using the ScheduledExecutorService
int delay = 15; // adjust the delay
ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool();
scheduledExecutorService.scheduleAtFixedRate(new Runnable() {
public void run() {
ball.move();
player.move();
}
}, delay, TimeUnit.MILLISECONDS)
As of Java8, you might write this using a Lambda like this:
scheduledExecutorService.scheduleAtFixedRate(() -> {
ball.move();
player.move();
}, delay, TimeUnit.MILLISECONDS)
To stop it, you could now call:
scheduledExecutorService.shutdown();
However: There are more sophisticated solutions. One is, as you already noted, the double buffering. But there are also multiple different techniques, that compensate more difficult problems. They use something called page flipping.
The problem you are having is that you have split your paint methods,
if you make one class that is dedicated to doing the painting and you put all of your paints in one paint method it should work without flickering.
I would also recommend looking into making your paint calls run on a timer which lets you decide the refresh rate which usually leads to a smoother experience overall.
Here is an example of my graphics class in my latest game,
class GameGraphics extends JPanel implements ActionListener {
private Timer refreshHZTimer;
private int refreshHZ = 10;
private int frameID = 0;
public GameGraphics(int width, int height) {
setBounds(0,0, width, height);
setVisible(true);
refreshHZTimer = new Timer(refreshHZ, this);
refreshHZTimer.start();
}
#Override
public void actionPerformed(ActionEvent e) {
frameID++;
if (frameID % 100 == 1)
System.out.println("Painting FrameID: " + frameID);
repaint();
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
//Init graphics
Graphics2D g2 = (Graphics2D) g;
//Paint stuff here:
}
}
And add this code to your JFrame constructor:
GameGraphics gpu = new GameGraphics(width, height);
frame.add(gpu);

Object class isn't painting to screen

I am currently working on a small coding project and I've run into an issue. I've looked over my past work and I can't seem to figure out why this program wont call the paint method. Currently I'm just trying to draw a circle to the frame.
The following creates the window and the object class for the simple circle I'm trying to draw.
public class Main {
public static void main(String[] args) {
final int WIDTH = 700, HEIGHT = 900;
JFrame frame = new JFrame("Physics Demo");
JPanel content = new JPanel();
content.setLayout(new GridLayout(1, 0, 0, 0));
Character ball = new Character(WIDTH, HEIGHT);
Timer changeFrame = new Timer (100, ball);
frameSetup(frame, content, WIDTH, HEIGHT, ball, changeFrame);
}
public static void frameSetup(JFrame frame, JPanel content, int WIDTH, int HEIGHT, Character ball, Timer changeFrame){
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setContentPane(content);
content.add(ball);
frame.addKeyListener(ball);
frame.setPreferredSize(new Dimension(WIDTH, HEIGHT));
frame.setResizable(false);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
changeFrame.start();
}
}
The class below is the object class, when I run the program I get a response from the console. Character triggers once (as it should) and the actionPreformed method runs on loop with the timer. For some reason it doesn't run the paint class.
public class Character extends JPanel implements ActionListener, KeyListener{
/* Identify the Objects values and physics,
* Characters weight, size and properties are below.
*
*/
private static final long serialVersionUID = 1L;
final int characterRadius = 30;
final double characterWeight = 0.5;
int characterY, characterX;
boolean bouncy;
public Character(int WIDTH, int HEIGHT){
System.out.println("Character called upon... " + WIDTH);
}
public void characterObject(Graphics g, int WIDTH, int HEIGHT){
super.paint(g);
System.out.println("characterObject graphics called upon... " + WIDTH);
g.setColor(Color.BLUE);
g.fillOval(350, 450, characterRadius, characterRadius);
}
/*
* Ball does not have any player interactions
*/
#Override
public void keyPressed(KeyEvent buttonPressed) {
}
#Override
public void keyReleased(KeyEvent arg0) {
}
#Override
public void keyTyped(KeyEvent arg0) {
}
//******************************************
#Override
public void actionPerformed(ActionEvent arg0) {
System.out.println("actionPreformed called upon...");
repaint();
}
}
I've been doing trial and error for a while now and I can't seem to figure it out so I'm using this as a last resort.
I can supply more information if needed.
Why are you calling super.paint from characterObject? This is not how custom painting works. You don't control the painting process, the API does
You need to override one of the methods called when the API want's the component to be repainted. As a general recommendation, this would the paintComponent method, for example
public class Character extends JPanel implements ActionListener, KeyListener {
/* Identify the Objects values and physics,
* Characters weight, size and properties are below.
*
*/
private static final long serialVersionUID = 1L;
final int characterRadius = 30;
final double characterWeight = 0.5;
int characterY, characterX;
boolean bouncy;
public Character(int WIDTH, int HEIGHT) {
System.out.println("Character called upon... " + WIDTH);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g); //To change body of generated methods, choose Tools | Templates.
System.out.println("characterObject graphics called upon... " + WIDTH);
g.setColor(Color.BLUE);
g.fillOval(350, 450, characterRadius, characterRadius);
}
/*
* Ball does not have any player interactions
*/
#Override
public void keyPressed(KeyEvent buttonPressed) {
}
#Override
public void keyReleased(KeyEvent arg0) {
}
#Override
public void keyTyped(KeyEvent arg0) {
}
//******************************************
#Override
public void actionPerformed(ActionEvent arg0) {
System.out.println("actionPreformed called upon...");
repaint();
}
}
I would recommend having a read of Performing Custom Painting and Painting in Swing for more details about how painting actually works in Swing.
I'd also recommend having a look at How to use Key Bindings as a replacement for KeyListener, which will address you next obvious issue
You may also want to have a read of Java Coding Conventions, it will make it easier for other people to read your code and easier for you to read others.
You're passing the width and height to the Character constructor, but are ignoring them, I'd suggest you're going to need to assign those values to instance fields and use them within the paintComponent method
You should not call paint directly. It is called from the framework whenever repaint is needed. To force repaint just call 'repaint()'.
In case you call it from a timer you might need to put the call into the EDT that means the EventDispatchThread:
EventQueue.invokeLater(new Runnable()
{
#Override
public void run()
{
ball.repaint();
}
});
Oh and you really should override the paint method:
#Override
public void paint(Graphics g)
{
super.paint(g);
g.setColor(Color.BLUE);
g.fillOval(350, 450, characterRadius, characterRadius);
}

painting from an external method

In my applet I have a method paint that paints on screen.
public void init() {
addMouseMotionListener(new MouseMotionAdapter() {
#Override
public void mouseMoved(MouseEvent evt) {
storeCoordinates(evt,Graphics g); // results in error
}
});
}
public void paint(Graphics g) {
// do something
}
public void storeCoordinates(MouseEvent evt , Graphics g) {
// from this method i want to modify the scene painted by paint
}
Now in another method I want to modify a bit of a scene that was painted by the paint method. How can I do this ? Like I want to draw blue lines using g.drawLine(.,.,.,.) from another method.
The above snippet generates an error saying ) expected ; expected , cannot find symbol variable Graphics when i call the function from mouseMoved
In response to edits:
So what I would do in this case is not use the graphics right there. Instead, I would do something like this... Keep a list of your points, and when you click, add the point to your list. Then when you draw, draw your points. (If you're only going to be drawing on click, you could just store the last point, draw a line between the current point and the last point, and set the last point to the current point. But this is more extensible.)
List<Point> points = new ArrayList<Points>();
public void init() {
addMouseMotionListener(new MouseMotionAdapter() {
#Override
public void mouseMoved(MouseEvent evt) {
storeCoordinates(evt); // graphics removed
}
});
}
public void paint(Graphics g) {
for(int i = 1; i < points.size(); i++) {
Point first = points.get(i - 1);
Point second = points.get(i);
g.setColor(Color.BLUE);
g.drawLine(first.getX(), first.getY(), second.getX(), second.getY());
}
}
public void storeCoordinates(MouseEvent evt) {
int x = evt.getX();
int y = evt.getY();
points.add(new Point(x,y));
}
.
Old Answer
Pass your graphics object as a parameter to that other method.
public void paint(Graphics g) {
externalPaint(g);
}
private void externalPaint(Graphics g) {
g.drawLine(1,2,3,4);
}
Now in another method I want to modify a scene on that was painted by the paint method. How can I do this?
Call Component.repaint(int,int,int,int) or JComponent.repaint(Rectangle).

Categories

Resources