I'm trying to code a simple Pong and I have the background panel which contains a Bar panel. So of course I need to be able to place the bar on the size and move it vertically at request. Now I'm just trying to put it in a starting position. If I don't disable the layout the bar gets placed in the top center regardless of location setting, but if I disable the layout and set location it just doesn't show up. I'm not sure what I missing. Here is a code snippet if it can be relevant:
public PongPanel() {
setLayout(null);
setPreferredSize(SIZE);
setBackground(Color.BLACK);
player_one_bar = new Bar();
add(player_one_bar);
player_one_bar.setLocation(10, getSize().height/2-3);
}
If you set the layout manager as null you'll have to specify the exact coordinates of the panel, meaning something like -
setBounds(10, 10, 20, 100);
Will put the panel at location (10,10) with Width of 20 and Height of 100.
If by "bar" you mean Pong game paddle, then it shouldn't be a component at all but rather a logical entity that represents a position, which is visually represented by a sprite that gets drawn in the JPanel's paintComponent method.
For example:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
public class PongPaddle extends JPanel {
private static final int PREF_W = 800;
private static final int PREF_H = 500;
private static final int RECT_X = 20;
private static final int RECT_W = 10;
private static final int RECT_H = 60;
private static final int STARTING_Y = (PREF_H - RECT_H) / 2;
private static final int TIMER_DELAY = 15;
private static final int DELTA_PADDLE = 3;
private boolean paddle1GoingDown = true;
private boolean paddle2GoingDown = false;
private Rectangle paddle1 = new Rectangle(RECT_X, STARTING_Y, RECT_W, RECT_H);
private Rectangle paddle2 = new Rectangle(PREF_W - RECT_X - RECT_W,
STARTING_Y, RECT_W, RECT_H);
public PongPaddle() {
setBackground(Color.black);
new Timer(TIMER_DELAY, new TimerListener()).start();
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
private class TimerListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
int deltaPaddle1 = paddle1GoingDown ? 1 : -1;
deltaPaddle1 *= DELTA_PADDLE;
int x = paddle1.getLocation().x;
int y = paddle1.getLocation().y + deltaPaddle1;
if (y + RECT_H >= PREF_H) {
paddle1GoingDown = false;
}
if (y <= 0) {
paddle1GoingDown = true;
}
paddle1.setLocation(x, y);
int deltaPaddle2 = paddle2GoingDown ? 1 : -1;
deltaPaddle2 *= DELTA_PADDLE;
x = paddle2.getLocation().x;
y = paddle2.getLocation().y + deltaPaddle2;
if (y + RECT_H >= PREF_H) {
paddle2GoingDown = false;
}
if (y <= 0) {
paddle2GoingDown = true;
}
paddle2.setLocation(x, y);
repaint();
if (!PongPaddle.this.isShowing()) {
((Timer) e.getSource()).stop();
}
}
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setColor(Color.white);
if (paddle1 != null) {
g2.fill(paddle1);
}
if (paddle2 != null) {
g2.fill(paddle2);
}
}
private static void createAndShowGui() {
PongPaddle mainPanel = new PongPaddle();
JFrame frame = new JFrame("PongPaddle");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
Related
Im trying to code a simple 2D game. I have a Square that you can move with a/w/d. I got jumping working with a sort of gravity but now I cant get myself to land on a platform. I know how to detect collision between two things but even still idk what to do. My gravity always pulls me down until I reach groundLevel which is part of the problem. Here is my code so far. There's a lot of experimenting happing so its pretty messy.
import javax.swing.Timer;
import java.util.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.awt.geom.*;
/**
* Custom Graphics Example: Using key/button to move a line left or right.
*/
public class PlatformingGame extends JFrame implements ActionListener, KeyListener{
// Name-constants for the various dimensions
public static final int CANVAS_WIDTH = 800;
public static final int CANVAS_HEIGHT = 400;
public static final Color LINE_COLOR = Color.BLACK;
public static final Color CANVAS_BACKGROUND = Color.WHITE;
public int GRAVITY = 10;
public int TERMINAL_VELOCITY = 300;
public int vertical_speed = 0;
public int jumpSpeed;
public int groundLevel = CANVAS_HEIGHT;
int Shapes;
private DrawCanvas canvas; // the custom drawing canvas (extends JPanel)
public enum STATE {
PLAYING,
PAUSED,
ONGROUND,
INAIR
};
JButton btnStartRestat, btnExit;
Timer timer;
Rectangle2D.Double guy, platform, platform2;
Shape[] shapeArr = new Shape[10];
int dx, dy;
/** Constructor to set up the GUI */
ArrayList myKeys = new ArrayList<Character>();
public static STATE gameState = STATE.PAUSED;
//public static STATE playerState = STATE.ONGROUND;
public PlatformingGame() {
dx = 3;
dy = 3;
guy = new Rectangle2D.Double( CANVAS_WIDTH/2 - 20, CANVAS_HEIGHT, 30, 20);
platform2 = new Rectangle2D.Double( CANVAS_WIDTH/4, CANVAS_HEIGHT/2+130, 50, 10);
platform = new Rectangle2D.Double( CANVAS_WIDTH/3, CANVAS_HEIGHT/2+50, 50, 10);
timer = new Timer(10, this);
// Set up a panel for the buttons
JPanel btnPanel = new JPanel();
// btnPanel.setPreferredSize(new Dimension(CANVAS_WIDTH/2, CANVAS_HEIGHT));
btnPanel.setLayout(new FlowLayout());
btnStartRestat = new JButton("Start/Restart");
btnExit = new JButton("Exit");
btnPanel.add(btnStartRestat);
btnPanel.add(btnExit);
btnStartRestat.addActionListener(this);
btnExit.addActionListener(this);
// Set up a custom drawing JPanel
canvas = new DrawCanvas();
canvas.setPreferredSize(new Dimension(CANVAS_WIDTH, CANVAS_HEIGHT));
// Add both panels to this JFrame
Container cp = getContentPane();
cp.setLayout(new BorderLayout());
cp.add(canvas, BorderLayout.CENTER);
cp.add(btnPanel, BorderLayout.SOUTH);
// "this" JFrame fires KeyEvent
addKeyListener(this);
requestFocus(); // set the focus to JFrame to receive KeyEvent
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// Handle the CLOSE button
pack(); // pack all the components in the JFrame
setVisible(true); // show it
}
public void generateSpikes(){
Rectangle2D.Double spikes = null;
for (int i = 0; i < 10; i++) {
spikes = new Rectangle2D.Double (CANVAS_WIDTH - 300 + i*20 , CANVAS_HEIGHT - 30 , 20, 30);
shapeArr[i] = spikes;
}
}
public void actionPerformed(ActionEvent e)
{
if (e.getSource()==btnStartRestat)
{
generateSpikes();
dx = 3;
dy = 3;
guy = new Rectangle2D.Double( 100, CANVAS_HEIGHT - guy.height, 15, 30);
platform = new Rectangle2D.Double( CANVAS_WIDTH/3, CANVAS_HEIGHT/2+50, 50, 10);
platform2 = new Rectangle2D.Double( CANVAS_WIDTH/4, CANVAS_HEIGHT/2+130, 50, 10);
gameState = STATE.PLAYING;
}
else if (e.getSource()==btnExit)
{
// requestFocus(); // change the focus to JFrame to receive KeyEvent
}
else if (e.getSource()== timer){
if (isHitDetected(platform2, guy)){
// playerState = STATE.ONGROUND;
guy.y = platform2.y;
}
if (myKeys.contains('a')
&& (guy.x > 0)){
guy.x = guy.x - 5; }
if (myKeys.contains('d')
&& (guy.x < CANVAS_WIDTH - guy.width)){
guy.x = guy.x + 5; }
{
updateGuyPosition();
}
requestFocus();
canvas.repaint();
}
}
public void updateGuyPosition(){
double guyHeight = guy.height;
if (guy.x >= CANVAS_WIDTH - guy.width){
}
if(gameState == STATE.PLAYING) {
guy.y += jumpSpeed;
if (guy.y < groundLevel - guyHeight) {
// if(playerState == STATE.INAIR) {
jumpSpeed += 1;
}
// }
else {
// if(playerState == STATE.INAIR) {
//playerState = STATE.ONGROUND;
jumpSpeed = 0;
guy.y = groundLevel - guyHeight;
}
// }
if (myKeys.contains('w') == true && guy.y == groundLevel - guyHeight) {
jumpSpeed = -15;
// playerState = STATE.INAIR;
}
}
}
public static boolean isHitDetected(Shape shapeA, Shape shapeB) {
Area areaA = new Area(shapeA);
areaA.intersect(new Area(shapeB));
return !areaA.isEmpty();
}
public void keyPressed(KeyEvent evt) {
if (!myKeys.contains(evt.getKeyChar())){
myKeys.add(evt.getKeyChar());
}
}
public void keyReleased(KeyEvent evt) {
myKeys.remove(myKeys.indexOf(evt.getKeyChar()));
}
public void keyTyped(KeyEvent evt) {
}
/** The entry main() method */
public static void main(String[] args) {
PlatformingGame myProg = new PlatformingGame(); // Let the constructor do the job
myProg.timer.start();
}
/**
* DrawCanvas (inner class) is a JPanel used for custom drawing
*/
class DrawCanvas extends JPanel {
public void paintComponent(Graphics g) {
super.paintComponent(g);
setBackground(CANVAS_BACKGROUND);
g.setColor(LINE_COLOR);
Graphics2D g2d = (Graphics2D)g;
if(gameState == STATE.PLAYING) {
g2d.fill(guy);
g.setColor(Color.lightGray);
g2d.fill(platform);
g2d.fill(platform2);
for (int i = 0; i < 10; i++) {
g2d.fill(shapeArr[i]);
}
}
if(gameState == STATE.PAUSED) {
g.drawString("Game Paused", CANVAS_WIDTH/2, CANVAS_HEIGHT/2);
}
}
}
}
I am developing the peg game in java, and I have been stuck on getting a hole to change color when it is clicked on to indicate that it has been selected. I currently have 3 classes, all of which extend JPanel:
Display.java: creates the JFrame and renders the gameboard to the JFrame.
GameBoard.java: Holds the logic for rendering the gameboard.
Hole.java: Renders a hole and holds the logic for the MouseListener. When one clicks on a hole, it should turn blue to indicate that it is selected.
I am able to render the holes onto the gameboard, however, the MouseListener does not work; When I click on a hole, it does not turn blue.
Below are the three classes:
Display.java
import javax.swing.JFrame;
import javax.swing.JPanel;
import java.util.logging.*;
public class Display extends JPanel {
private static final long serialVersionUID = 1L;
private static String staticClassName = Display.class.getName();
private static Logger logger = Logger.getLogger(staticClassName);
private final static Logger LOGGER = Logger.getLogger(staticClassName);
private static String title;
private static int width;
private static int height;
private static JFrame frame;
private static JPanel mainPanel;
private static GameBoard gameBoard;
public Display(String title, int width, int height){
logger.info(staticClassName +".Constructor: Constructing Display");
Display.title = title;
Display.width = width;
Display.height = height;
logger.info(staticClassName +".Constructor: Display constructed.");
initDisplay();
}
private static void initDisplay() {
logger.info(staticClassName +".initDisplay(): Entering method");
try {
logger.info(staticClassName +".initDisplay(): About to create JFrame");
frame = new JFrame(title);
frame.setLocationByPlatform(true);
frame.setVisible(true);
frame.setSize(width, height);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
mainPanel = new JPanel();
logger.info(staticClassName +".initDisplay(): About to create GameBoard object");
gameBoard = new GameBoard();
mainPanel.add(gameBoard);
frame.getContentPane().add(mainPanel);
frame.pack();
} catch (Exception e) {
logger.info(staticClassName +".initDisplay(): Failed to render display: " + e);
}
logger.info(staticClassName +".initDisplay(): Exiting Method");
}
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
try {
LOGGER.setLevel(Level.INFO);
Display d = new Display("Peg Game", 800, 800);
} catch (Exception e) {
}
}
});
}
}
GameBoard.java
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.geom.Path2D;
import java.util.logging.Logger;
import javax.swing.JPanel;
public class GameBoard extends JPanel {
private static final long serialVersionUID = 1L;
private static String staticClassName = GameBoard.class.getName();
private static Logger logger = Logger.getLogger(staticClassName);
private static final int RGB1 = 223;
private static final int RGB2 = 191;
private static final int RGB3 = 159;
private static final int WIDTH = 800;
private static final int HEIGHT = WIDTH;
private Path2D path = new Path2D.Double();
private static Color boardColor = new Color(RGB1, RGB2, RGB3);
private int [] adjacentHoles1;
public GameBoard() {
logger.info(staticClassName +".Constructor: Constructing GameBoard");
double firstX = (WIDTH / 2.0) * (1 - 1 / Math.sqrt(3));
double firstY = 3.0 * HEIGHT / 4.0;
path.moveTo(firstX, firstY);
path.lineTo(WIDTH - firstX, firstY);
path.lineTo(WIDTH / 2.0, HEIGHT / 4.0);
path.closePath();
logger.info(staticClassName +".Constructor: GameBoard constructed");
}
#Override
protected void paintComponent(Graphics g) {
logger.info(staticClassName +".paintComponent(): Entering method");
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2.setPaint(boardColor);
g2.fill(path);
int xPos = 390;
int yPos = 310;
// I was rendering up to 15 holes, but took them out for purpose of
// shortening my example
for (int i = 0; i < 15; i ++ ) {
if (i == 0) {
// Declare the hole here
Hole hole = new Hole(i, xPos, yPos, adjacentHoles1);
// Render it here
hole.paintComponent(g2);
yPos += 50;
}
}
logger.info(staticClassName +".paintComponent(): Exiting method");
}
#Override
public Dimension getPreferredSize() {
logger.info(staticClassName +".getPreferredSize(): Entering method");
if (isPreferredSizeSet()) {
logger.info(staticClassName +".getPreferredSize(): isPreferredSizeSet() == true. Exiting method");
return super.getPreferredSize();
}
logger.info(staticClassName +".getPreferredSize(): isPreferredSizeSet() == false. Exiting method");
return new Dimension(WIDTH, HEIGHT);
}
}
Hole.java
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.util.logging.Logger;
import javax.swing.JPanel;
public class Hole extends JPanel {
private static final long serialVersionUID = 1235245435988434L;
private static String staticClassName = Hole.class.getName();
private static Logger logger = Logger.getLogger(staticClassName);
private int holeNumber;
private int xPos, yPos;
private final int HOLEWIDTH = 20;
private final int HOLEHEIGHT = HOLEWIDTH;
private static final int RGB1 = 0;
private static final int RGB2 = 0;
private static final int RGB3 = 0;
private static Color defaultCircleColor = new Color(RGB1, RGB2, RGB3);
private static Color selectedCircleColor = Color.BLUE;
private static Color circleColor = defaultCircleColor;
private int [] adjacentHoles;
public Hole (int holeNumber, int xPos, int yPos, int [] adjacentHoles) {
logger.info(staticClassName +".Constructor: Constructing Hole");
this.holeNumber = holeNumber;
this.xPos = xPos;
this.yPos = yPos;
this.adjacentHoles = adjacentHoles;
initComponents();
}
#Override
protected void paintComponent(Graphics g) {
logger.info(staticClassName +".paintComponent(): Entering method");
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2.setPaint(circleColor);
g2.fillOval(xPos,yPos,HOLEWIDTH,HOLEHEIGHT);
logger.info(staticClassName +".paintComponent(): Exiting method");
}
private void initComponents() {
addMouseListener(new java.awt.event.MouseAdapter() {
public void mouseClicked(java.awt.event.MouseEvent event) {
selectHole(event);
}});
}
public void selectHole(java.awt.event.MouseEvent event) {
logger.info(staticClassName +"------------------------------------------------");
logger.info(staticClassName +".selectHole(): Entering method");
if (circleColor == defaultCircleColor) {
circleColor = selectedCircleColor;
repaint();
}
else {
circleColor = defaultCircleColor;
repaint();
}
logger.info(staticClassName +".selectHole(): Exiting method");
logger.info(staticClassName +"------------------------------------------------");
}
#Override
public Dimension getPreferredSize() {
logger.info(staticClassName +".getPreferredSize(): Getting the preferred size of the circle.");
return new Dimension(800, 800);
}
}
As a side note, if you notice that I could be using better coding practices anywhere in my code, please let me know.
So, your basic problem is right here...
for (int i = 0; i < 15; i ++ ) {
if (i == 0) {
// Declare the hole here
Hole hole = new Hole(i, xPos, yPos, adjacentHoles1);
// Render it here
hole.paintComponent(g2);
yPos += 50;
}
}
Hole is component, you should never call any paint method of component, but, you component is also not "live", meaning that it can never receive ANY events.
What you should do instead, is attach the MouseListener to the GameBoard and test if the mouse was clicked at a place there is a hole.
The simplest solution is to make use of the "shapes" API and generate a list of "holes". This can then be simply iterated over to paint and check to see if the mouse was clicked within it.
I've not gone to a great deal of effort in determining the location of the holes, instead I've just laid them out in rows/cols, but you should get the basic idea of the intended solution
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Path2D;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Display extends JPanel {
private static final long serialVersionUID = 1L;
private static String staticClassName = Display.class.getName();
private static Logger logger = Logger.getLogger(staticClassName);
private final static Logger LOGGER = Logger.getLogger(staticClassName);
private static String title;
private static int width;
private static int height;
private static JFrame frame;
private static JPanel mainPanel;
private static GameBoard gameBoard;
public Display(String title, int width, int height) {
logger.info(staticClassName + ".Constructor: Constructing Display");
Display.title = title;
Display.width = width;
Display.height = height;
logger.info(staticClassName + ".Constructor: Display constructed.");
initDisplay();
}
private static void initDisplay() {
frame = new JFrame(title);
frame.setLocationByPlatform(true);
frame.setVisible(true);
frame.setSize(width, height);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
mainPanel = new JPanel();
gameBoard = new GameBoard();
mainPanel.add(gameBoard);
frame.getContentPane().add(mainPanel);
frame.pack();
}
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
try {
LOGGER.setLevel(Level.INFO);
Display d = new Display("Peg Game", 800, 800);
} catch (Exception e) {
}
}
});
}
public static class GameBoard extends JPanel {
private static final long serialVersionUID = 1L;
private static String staticClassName = GameBoard.class.getName();
private static Logger logger = Logger.getLogger(staticClassName);
private static final int RGB1 = 223;
private static final int RGB2 = 191;
private static final int RGB3 = 159;
private static final int WIDTH = 800;
private static final int HEIGHT = WIDTH;
private Path2D path = new Path2D.Double();
private static Color boardColor = new Color(RGB1, RGB2, RGB3);
private int[] adjacentHoles1;
private Shape[] holes;
private Shape selectedHole;
public GameBoard() {
logger.info(staticClassName + ".Constructor: Constructing GameBoard");
double firstX = (WIDTH / 2.0) * (1 - 1 / Math.sqrt(3));
double firstY = 3.0 * HEIGHT / 4.0;
path.moveTo(firstX, firstY);
path.lineTo(WIDTH - firstX, firstY);
path.lineTo(WIDTH / 2.0, HEIGHT / 4.0);
path.closePath();
logger.info(staticClassName + ".Constructor: GameBoard constructed");
holes = new Shape[15];
int yPos = 310;
int index = 0;
for (int row = 0; row < 3; row++) {
int xPos = 390;
for (int col = 0; col < 5; col++) {
holes[index] = new Ellipse2D.Double(xPos, yPos, 50, 50);
index++;
xPos += 50;
}
yPos += 50;
}
addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
selectedHole = null;
for (Shape hole : holes) {
if (hole.contains(e.getPoint())) {
selectedHole = hole;
break;
}
}
repaint();
}
});
}
#Override
protected void paintComponent(Graphics g) {
logger.info(staticClassName + ".paintComponent(): Entering method");
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2.setPaint(boardColor);
g2.fill(path);
g2.setColor(Color.BLACK);
for (Shape hole : holes) {
g2.fill(hole);
}
if (selectedHole != null) {
g2.setColor(Color.RED);
g2.fill(selectedHole);
}
logger.info(staticClassName + ".paintComponent(): Exiting method");
}
#Override
public Dimension getPreferredSize() {
logger.info(staticClassName + ".getPreferredSize(): Entering method");
if (isPreferredSizeSet()) {
logger.info(staticClassName + ".getPreferredSize(): isPreferredSizeSet() == true. Exiting method");
return super.getPreferredSize();
}
logger.info(staticClassName + ".getPreferredSize(): isPreferredSizeSet() == false. Exiting method");
return new Dimension(WIDTH, HEIGHT);
}
}
}
What I'm trying to do
Making a Pong game where the Y axis gets the value from my cursor according to the application
What did I tried
private void pallet() {
ycur=(int)MouseInfo.getPointerInfo().getLocation().getY();
}
This way I get the Y value according to my monitor instead of the application.
I also tried to use the MouseEvent.getY(), but I get the error when trying to call this method from the main.
private void pallet() {
ycur=(int)MouseInfo.getPointerInfo().getLocation().getY();
}
This is how my code looks like, I think the problem lies in how I'm using my main and methods but I'm not sure.
public class MyFirst extends JPanel {
public int x = 500, y = 300, border = 30;
public boolean goingDown = true;
public int ycur, cursor;
public void moveBall() {
x++;
if (goingDown == true) {
y++;
} else if (goingDown == false) {
y--;
}
if (y == getHeight() - border) {
goingDown = false;
} else if (y == 0) {
goingDown = true;
}
}
#Override
public void paint(Graphics g) {
super.paint(g);
g.fillOval(x, y, 30, 30);
g.fillRect(30, ycur, 15, 100);
}
public static void main(String[] args) throws InterruptedException {
JFrame frame = new JFrame("Pong");
frame.pack();
frame.setSize(1000, 600);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
frame.setLocationRelativeTo(null);
MyFirst game = new MyFirst();
frame.add(game);
while (true) {
game.pallet(e);
game.moveBall();
game.repaint();
Thread.sleep(10);
}
}
public void pallet(MouseEvent e) {
ycur=e.getY();
}
}
Problems with your code:
As already mentioned, you're fighting against Swing's event-driven architecture. Instead of a while true loop, use listeners, including a MouseMotionListener ot track the changes in the mouse location, and an ActionListener tied to a Swing Timer to move the ball.
Avoid using Thread.sleep(...) in Swing GUI's except with great care as this can put the entire application to sleep.
Avoid putting too much logic within the main method. This method should be short, should create the key objects, connect them, set the program in motion and that's it.
Paint with the paintComponent method, not the paint method. It results in smoother animation with its double buffering.
For example:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.*;
#SuppressWarnings("serial")
public class MoveBallTest extends JPanel{
private static final int PREF_W = 1000;
private static final int PREF_H = 600;
private static final int TIMER_DELAY = 12;
private static final int SPRITE_WIDTH = 30;
private static final Color OVAL_SPRITE_COLOR = Color.RED;
private static final Color RECT_SPRITE_COLOR = Color.BLUE;
private static final int DELTAY_Y = 1;
private boolean goingDown = true;
private Timer timer = new Timer(TIMER_DELAY, this::timerActionPerformed);
private int ovalSpriteY;
private int rectSpriteY;
public MoveBallTest() {
timer.start();
MyMouse myMouse = new MyMouse();
addMouseMotionListener(myMouse);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(OVAL_SPRITE_COLOR);
g.fillOval(SPRITE_WIDTH, ovalSpriteY, SPRITE_WIDTH, SPRITE_WIDTH);
g.setColor(RECT_SPRITE_COLOR);
g.fillRect(SPRITE_WIDTH, rectSpriteY, SPRITE_WIDTH / 2, SPRITE_WIDTH * 3);
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
public void timerActionPerformed(ActionEvent e) {
if (ovalSpriteY <= 0) {
goingDown = true;
} else if (ovalSpriteY >= getHeight() - SPRITE_WIDTH) {
goingDown = false;
}
ovalSpriteY += goingDown ? DELTAY_Y : -DELTAY_Y;
repaint();
}
private class MyMouse extends MouseAdapter {
#Override
public void mouseMoved(MouseEvent e) {
rectSpriteY = e.getY();
}
}
private static void createAndShowGui() {
JFrame frame = new JFrame("MoveBallTest");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new MoveBallTest());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
I want to replace a panel by another one (all of them has transparent section).
The code is as followed:
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.GridLayout;
import java.awt.Image;
import java.util.Timer;
import java.util.TimerTask;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class PhotoFrame extends JFrame {
public class PhotosDisplayPanel extends JPanel {
private static final long serialVersionUID = 1L;
private String[] imgsLink = null;
private long delay = 1000;
private long period = 1000;
private int curIdx = 0;
private PhotoDisplayPanel currentPhoto = null;
public PhotosDisplayPanel(String[] imgsLink) {
super();
this.imgsLink = imgsLink;
setBackground(new Color(0, 0, 0, 0));
setLayout(new GridLayout(1, 1));
currentPhoto = new PhotoDisplayPanel(imgsLink[curIdx]);
add(currentPhoto);
}
public void start() {
if (imgsLink == null) {
return;
}
curIdx = -1;
Timer timer = new Timer();
timer.schedule(new TimerTask() {
#Override
public void run() {
curIdx++;
if (curIdx >= imgsLink.length) {
curIdx = 0;
}
displayNextImage();
}
}, delay, period);
}
protected void displayNextImage() {
if (currentPhoto != null) {
remove(currentPhoto);
}
revalidate();
repaint();
currentPhoto = new PhotoDisplayPanel(imgsLink[curIdx]);
add(currentPhoto);
revalidate();
repaint();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
}
}
public class PhotoDisplayPanel extends JPanel {
private static final long serialVersionUID = 1L;
private String imgLink;
public PhotoDisplayPanel(String imgLink) {
super();
this.imgLink = imgLink;
}
#Override
protected void paintComponent(Graphics g) {
if (imgLink != null && !imgLink.equals("")) {
System.out.println("Draw image");
// get dimension of the panel
int pWidth = getWidth();
int pHeight = getHeight();
g.setColor(new Color(255, 0, 0, 50));
g.fillRect(0, 0, pWidth, pHeight);
Image img = new ImageIcon(imgLink).getImage();
// Calculate positions and dimensions
int imgWidth = img.getWidth(this);
int imgHeight = img.getHeight(this);
int iwidth = 0;
int iheight = 0;
if (imgWidth / imgHeight > pWidth / pHeight) {
iwidth = pWidth;
iheight = imgHeight * pWidth / imgWidth;
} else {
iheight = pHeight;
iwidth = imgWidth * pHeight / imgHeight;
}
int ix = (pWidth - iwidth) / 2;
int iy = (pHeight - iheight) / 2;
// Fill the picture to the panel
g.drawImage(img, ix, iy, iwidth, iheight, this);
} else {
super.paintComponent(g);
}
}
}
private static final long serialVersionUID = 1L;
private static final int defaultWidth = 650;
private static final int defaultHeight = 400;
private int width = defaultWidth;
private int height = defaultHeight;
private PhotosDisplayPanel photoPanel; // is view panel which display
// input and output
private String[] imgsLink;
public PhotoFrame() {
initialize();
imgsLink = new String[] { "background.png", "screenShot.jpg" };
createControls();
}
private void createControls() {
setLayout(new GridLayout(0, 1));
photoPanel = new PhotosDisplayPanel(imgsLink);
add(photoPanel);
photoPanel.start();
}
private void initialize() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(width, height);
setTitle("PhotosFrame");
setAlwaysOnTop(false);
setBackground(Color.CYAN);
setLayout(new GridLayout(1, 1));
setContentPane(new JLabel(new ImageIcon("blue_sunset.jpg")));
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
new PhotoFrame().setVisible(true);
}
});
}
}
In which, currentPhoto is a panel with transparent background. However, the image of the old panel is not cleaned totally, I can see the old one under the new one. Is there any way to clear the image of old panel comprehensively?
Thanks
However, the image of the old panel is not cleaned totally,
Check out Backgrounds With Transparency for the probable cause and a couple of solutions.
Basically when using transparent backgrounds Swing does not know that is need to repaint the background so you need to force the repainting.
So right now when you press go it just moves across the screen, but I also want it to move its legs so its doing something and not just standing still. Any tips on how to do that? I know it would be moving the 2nd leg pointers back and forth but I'm not sure how to do that
Class Stick2 :
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class Stick2 extends JFrame implements ActionListener {
// Declares constants
public static final int FRAME_WIDTH = 500;
private static final int FRAME_HEIGHT = 500;
private static final int FRAME_X_ORIGIN = 150;
private static final int FRAME_Y_ORIGIN = 200;
private static final int BUTTON_WIDTH =80;
private static final int BUTTON_HEIGHT = 30;
JPanel buttonPanel, panel;
MovingBanner2 myBanner;
JButton startButton, stopButton;
Thread thrd;
public static void main(String[] args)
{
Stick2 frame = new Stick2();
frame.setVisible(true);
}
public Stick2(){
Container contentPane= getContentPane();
// Sets Frame
setSize(FRAME_WIDTH,FRAME_HEIGHT);
setResizable(false);
setTitle("Animation");
setLocation(FRAME_X_ORIGIN, FRAME_Y_ORIGIN);
// Sets layout manager
contentPane.setLayout(new BorderLayout(10,0));
buttonPanel = new JPanel();
JButton startButton = new JButton("Start");
startButton.setSize(BUTTON_WIDTH, BUTTON_HEIGHT);
buttonPanel.add(startButton);
startButton.addActionListener(this);
JButton stopButton = new JButton("Stop");
stopButton.setSize(BUTTON_WIDTH,BUTTON_HEIGHT);
buttonPanel.add(stopButton);
stopButton.addActionListener(this);
contentPane.add (buttonPanel, BorderLayout.SOUTH);
// Creates a balloon
myBanner = new MovingBanner2();
panel = myBanner;
panel.setBorder(BorderFactory.createLineBorder(Color.BLUE));
contentPane.add(panel, BorderLayout.CENTER);
}
public void actionPerformed (ActionEvent event){
JButton clickedButton = (JButton) event.getSource();
String buttonText = clickedButton.getText();
if (buttonText.equals("Stop")) {
myBanner.stopAnimation();
thrd = null;
}
else {
myBanner.startAnimation();
thrd = new Thread (myBanner);
thrd.start();
}
}
}
Class MovingBanner2:
class MovingBanner2 extends JPanel implements Runnable {
private int x;
private Boolean animate;
int bodyX = 250;
int bodyY1 = 160;
int bodyY2 = 210;
int armHeight = 190;
int armLength = bodyX + 30;
int armLength1 = bodyX - 30;
int legY = 340;
public MovingBanner2() {
x=10;
animate = true;
}
// Draws the String
public void paintComponent (Graphics g) {
super.paintComponent(g);
g.setColor(Color.RED);
//g.drawString("I love Java", x,50);
g.drawLine(bodyX + x, bodyY1, bodyX + x, bodyY2); //body
g.drawOval(bodyX + x - 15, bodyY1 - 40, 40, 40); //head
g.drawLine(armLength + x,armHeight, armLength1 + x, armHeight); //arms
g.drawLine(bodyX + x, bodyY2, bodyX + 20 + x,legY); //leg
g.drawLine(bodyX + x, bodyY2, bodyX - 20 + x, legY); //leg
}
public void run() {
while (animate) {
changeX();
repaint();
try {Thread.sleep(100); } catch(Exception e){};
}
}
public void changeX() {
if (x <= Stick2.FRAME_WIDTH - 240)
x++;
else x = 10;
}
public void stopAnimation() {
animate = false;
}
public void startAnimation() {
animate = true;
}
}
There are probably many answers to the question. The best I can come up with is basically to devise some kind of "cycle".
A cycle is a known period of time over which animation can run. In this example, it's 1 second.
You then need to provide a series of Animatable objects that are notified of a change to the cycle over time, which allows them to make changes accordingly. You can also ignore the cycle for those elements that don't need to cycle.
The intention is provide a single animation engine that can be responsible for updating the entire state in one go, rather then trying to use multiple threads/timers which may reduce the systems performance.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class TestAnimation06 {
public static void main(String[] args) {
new TestAnimation06();
}
public TestAnimation06() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public interface Animatable {
public void update(float progress);
}
public class AnimationEngine {
private List<Animatable> animations;
private int cycleTime = 1000;
private long startTime = -1;
public AnimationEngine() {
animations = new ArrayList<>(25);
Timer timer = new Timer(40, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (startTime < 0) {
startTime = System.currentTimeMillis();
}
long duration = System.currentTimeMillis() - startTime;
float progress = (float)duration / (float)cycleTime;
if (duration >= cycleTime) {
progress = 1f;
startTime = System.currentTimeMillis();
}
for (Animatable animatable : animations) {
animatable.update(progress);
}
}
});
timer.setRepeats(true);
timer.setCoalesce(true);
timer.start();
}
public void add(Animatable animatable) {
animations.add(animatable);
}
}
public class TestPane extends JPanel {
private AnimationEngine engine;
public TestPane() {
setLayout(null);
engine = new AnimationEngine();
Legs legs = new Legs();
Walker walker = new Walker(legs);
engine.add(legs);
engine.add(walker);
walker.setSize(walker.getPreferredSize());
add(walker);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.dispose();
}
}
public class Walker extends JPanel implements Animatable {
private int speed = 2;
public Walker(Legs legs) {
setLayout(new GridBagLayout());
add(legs);
}
#Override
public void update(float progress) {
Container parent = getParent();
int width = parent.getWidth();
int xPos = getX() + speed;
if (xPos <= 0) {
speed *= -1;
xPos = 0;
} else if (xPos + getWidth() >= width) {
speed *= -1;
xPos = width - getWidth();
}
System.out.println(xPos);
setLocation(xPos, (parent.getHeight() - getHeight()) / 2);
repaint();
}
}
public class Legs extends JPanel implements Animatable {
private float frameProgress;
public Legs() {
setOpaque(false);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(25, 50);
}
#Override
public void update(float progress) {
frameProgress = progress;
repaint();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
int width = getWidth();
int height = getHeight();
g.setColor(Color.BLACK);
g.drawLine(width / 2, 0, (int)(width * frameProgress), height);
g.drawLine(width / 2, 0, width - (int)(width * frameProgress), height);
}
}
}