JPanels not being added to the JFrame - java

So I was building this very simple game and I've add all the elements (for the movement) but when I hit run it only shows me the JFrame and not the JPanel. I should mention that I am very new to Java and the code you see bellow might not be the cleanest (it's also not complete).
Main
public class Main {
public static void main(String[] args) {
GameFrame frame = new GameFrame();
}
}
GameFrame
public class GameFrame extends JFrame {
GamePanel panel;
GameFrame() {
panel = new GamePanel();
this.add(panel);
this.setTitle("Survival");
this.setResizable(false);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.pack();
this.setLocationRelativeTo(null);
this.setVisible(true);
}
}
Panel
public class GamePanel extends JPanel implements Runnable {
static final int GAME_WIDTH = 1000;
static final int GAME_HEIGHT = GAME_WIDTH * 9 / 16;
static final Dimension SCREEN_SIZE = new Dimension(GAME_WIDTH, GAME_HEIGHT);
static final int PLAYER_WIDTH = 40;
static final int PLAYER_HEIGHT = 40;
Thread gameThread;
Graphics graphics;
Player player;
int fireBallY = (int) (Math.random() * 563);
Fireballs fireball;
Image image;
int dimSky = 150;
GamePanel() {
newFireballs();
newPlayer();
this.setFocusable(true);
this.addKeyListener(new actionListener());
this.setPreferredSize(SCREEN_SIZE);
this.setBackground(Color.CYAN);
gameThread = new Thread(this);
gameThread.start();
}
private void newPlayer() {
player = new Player(200, 150, PLAYER_WIDTH, PLAYER_HEIGHT);
}
private void newFireballs() {
for (int i = 0; i < 5; i++) new Fireballs(800, fireBallY, PLAYER_WIDTH, PLAYER_HEIGHT);
}
public void paint(Graphics g) {
image = createImage(getWidth(), getHeight());
graphics = image.getGraphics();
draw(graphics);
g.drawImage(image, 0,0, this);
}
public void draw(Graphics g) {
player.draw(g);
}
public void move() {
player.moveX();
player.moveY();
}
public void collision() {}
public void run() {
//game loop
long lastTime = System.nanoTime();
double amountOfTicks = 60.0;
double ns = 1000000000 / amountOfTicks;
double delta = 0;
while (true) {
long now = System.nanoTime();
delta += (now - lastTime) / ns;
lastTime = now;
if (delta >= 1) {
move();
collision();
repaint();
delta--;
System.out.println("It Works!");
}
}
}
private class actionListener extends KeyAdapter {
public void keyPressed(KeyEvent e) {
player.KeyPressed(e);
}
public void keyReleased(KeyEvent e) {
player.KeyReleased(e);
}
}
}
Player
public class Player extends Rectangle {
int xVelocity;
int yVelocity;
int speed = 10;
public Player(int x, int y, int PLAYER_WIDTH, int PLAYER_HEIGHT) {
super(x,y, PLAYER_WIDTH, PLAYER_HEIGHT);
}
public void KeyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_W) {
setYDirection(-speed);
moveX();
moveY();
}
if (e.getKeyCode() == KeyEvent.VK_S) {
setYDirection(+speed);
moveX();
moveY();
}
if (e.getKeyCode() == KeyEvent.VK_D) {
setXDirection(+speed);
moveX();
moveY();
}
if (e.getKeyCode() == KeyEvent.VK_A) {
setXDirection(-speed);
moveX();
moveY();
}
}
public void KeyReleased(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_W) {
setYDirection(-10);
moveX();
moveY();
}
if (e.getKeyCode() == KeyEvent.VK_S) {
setYDirection(+1);
moveX();
moveY();
}
if (e.getKeyCode() == KeyEvent.VK_D) {
setXDirection(+1);
moveX();
moveY();
}
if (e.getKeyCode() == KeyEvent.VK_A) {
setXDirection(-1);
moveX();
moveY();
}
}
public void setXDirection(int xVelocity) {
x = x + xVelocity;
}
public void setYDirection(int yVelocity) {
y = y + yVelocity;
}
public void moveX() {
x = x + xVelocity;
}
public void moveY() {
y = y + yVelocity;
}
public void draw(Graphics g) {
g.setColor(Color.RED);
g.fillRect(x, y, width, height);
}
}
There are other classes but those are completely empty and I don't think they are the cause of my problem.

Several issues:
If you are new to Swing, do not start off with too much complexity.
when you cannot see a JPanel on screen, my approach would be first to amend that. Only then add some complexity to the JPanel itself.
I have done that below by simply displaying a big red JPanel.
Is the reason you do not see anything because you did not set a JFrame.size(Dimension d)? I have added that in the construtor of the JFrame
Indeed, as #Frakcool and #camickr have pointed out in their comments, the canonic approach in Swing is overriding JPanel.paintComponent(Graphics g)
You should obey the thread landscape that Swing has prepared for you. That is indeed use SwingWorker threads for background tasks as #Frakcool commented.
And also use the EventDispatchingThread to handle events and startup. In the main method below, you see the call to SwingUtilities.invokeLater(new Runnable()).
The more complex your application gets, the more likely you will run into trouble if not obeying the EventDispatchingThread.
here is my - minimal - sample code containing examples for the points above. Within your game logic may be further work to be done, which I think is out of scope.
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class GameFrame extends JFrame {
GamePanel panel;
GameFrame() {
panel = new GamePanel();
this.add(panel);
this.setTitle("Survival");
this.pack();
/*
* might help to set a window size:
*/
setSize(800, 600);
this.setResizable(false);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setLocationRelativeTo(null);
this.setVisible(true);
}
private class GamePanel extends JPanel {
#Override
protected void paintComponent(Graphics g) {
// check if needed, eg for subcomponents
// super.paintComponent(g);
g.setColor(Color.red);
g.fillRect(0, 0, getWidth(), getHeight());
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new GameFrame();
}
});
}
}

Related

Cannot use MouseEvents in main

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());
}
}

Blank screen during the execution of a java application on the swing frame

I have the following three classes:
import java.awt.Graphics2D;
import java.awt.event.KeyEvent;
public class Racquet {
int x = 0;
int xa = 0;
private Game game;
public Racquet(Game game) {
this.game= game;
}
public void move() {
if (x + xa > 0 && x + xa < game.getWidth()-60)
x = x + xa;
}
public void paint(Graphics2D g) {
g.fillRect(x, 330, 60, 10);
}
public void keyReleased(KeyEvent e) {
xa = 0;
}
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_LEFT)
xa = -1;
if (e.getKeyCode() == KeyEvent.VK_RIGHT)
xa = 1;
}
}
import java.awt.Graphics2D;
public class Ball {
int x = 0;
int y = 0;
int xa = 1;
int ya = 1;
private Game game;
public Ball(Game game) {
this.game= game;
}
void move() {
if (x + xa < 0)
xa = 1;
if (x + xa > game.getWidth() - 30)
xa = -1;
if (y + ya < 0)
ya = 1;
if (y + ya > game.getHeight() - 30)
ya = -1;
x = x + xa;
y = y + ya;
}
public void paint(Graphics2D g) {
g.fillOval(x, y, 30, 30);
}
}
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
public class Game extends JPanel {
Ball ball = new Ball(this);
Racquet racquet = new Racquet(this);
public Game() {
addKeyListener(new KeyListener() {
#Override
public void keyTyped(KeyEvent e) {
}
#Override
public void keyReleased(KeyEvent e) {
racquet.keyReleased(e);
}
#Override
public void keyPressed(KeyEvent e) {
racquet.keyPressed(e);
}
});
setFocusable(true);
}
private void move() {
ball.move();
racquet.move();
}
#Override
public void paint(Graphics g) {
super.paint(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
ball.paint(g2d);
racquet.paint(g2d);
}
public static void main(String[] args) {
JFrame frame = new JFrame("Mini Tennis");
Game game = new Game();
frame.add(game);
frame.setSize(300, 400);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
while (true) {
game.move();
game.repaint();
for(long i=0;i<=100000*100;i++)
{
}
}
}
}
import javax.swing.*;
import java.awt.event.*;
class T extends JFrame implements ActionListener
{
public T()
{
setVisible(true);
setSize(300,300);
setLocationRelativeTo(null);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setLayout(null);
JButton b1=new JButton("Click me");
b1.setBounds(150,150,50,50);
b1.addActionListener(this);
add(b1);
}
public void actionPerformed(ActionEvent a)
{
Game ob=new Game();
ob.main(null);
}
public static void main(String args[])
{
T obj=new T();
}
}
When I execute the class T, I am supposed to get the Game but I don't know why I get the blank screen and not the game. I am new to Java so could someone help me out?
The reason that the T class doesn't work is that your code uses bad code to run the game loop, a while (true) loop that if called on the Swing event thread (as T does), will completely block the this thread, preventing it from performing its necessary functions including drawing the GUI.
The solution is to use a Swing Timer to drive your game loop, not a while (true) loop. To gain a better understanding of Swing threading issues, please read: Lesson: Concurrency in Swing

Java ImageIcon Animation Flashing

Form some reason when it switches Icon's the image flashes. I'm also having this problem even more when I try to create objects then try to make them move by passing the x and y through as parameters on the object. Any help would be great.
public class Main extends JFrame implements ActionListener, KeyListener{
static Main main;
Render render;
Timer timer;
static int x,y,count;
ImageIcon player1 = new ImageIcon("C:\\Users\\Kyle\\Documents\\NetBeansProjects\\Testing52\\src\\testing52\\Player1.png");
ImageIcon player2 = new ImageIcon("C:\\Users\\Kyle\\Documents\\NetBeansProjects\\Testing52\\src\\testing52\\Player2.png");
Main(){
render = new Render();
timer = new Timer(100,this);
setVisible(true);
setSize(500,500);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setResizable(false);
addKeyListener(this);
add(render);
timer.start();
}
public void render(Graphics g){
count += 1;
if(count < 20){
player1.paintIcon(this, g, x, y);
}
if(count > 20){
player2.paintIcon(this, g, x, y);
}
if(count > 40){
count = 0;
}
}
public static void main(String [] args){
main = new Main();
}
#Override
public void actionPerformed(ActionEvent e) {
System.out.println(count);
render.repaint();
}
#Override
public void keyTyped(KeyEvent e) {
}
#Override
public void keyPressed(KeyEvent e) {
int id = e.getKeyCode();
int speed = 4;
if(id == KeyEvent.VK_UP){
y -= speed;
}
if(id == KeyEvent.VK_DOWN){
y += speed;
}
if(id == KeyEvent.VK_LEFT){
x -= speed;
}
if(id == KeyEvent.VK_RIGHT){
x += speed;
}
}
#Override
public void keyReleased(KeyEvent e) {
}
}
Render class.
public class Render extends JPanel {
public void paintComponent(Graphics g){
super.paintComponent(g);
Main.main.render((Graphics)g);
}
}
Another thing that could make your animation smoother is if you called revalidate() in your action event after repaint().

Not seeing rectangle Player class in JFrame

I'm new to java and trying yo create a basic game and right now and trying to program the player class. However only the JFRame appears when i run the game. These are my thress classes and they show no errors.
import java.awt.Color;
import javax.swing.JFrame;
public class Game extends JFrame {
public
final static int WIDTH = 700, HEIGHT = 450;
public
GamePanel panel;
public Game() {
setSize(WIDTH, HEIGHT);
setTitle("Game");
setBackground(Color.WHITE);
setResizable(false);
setVisible(true);
setDefaultCloseOperation(EXIT_ON_CLOSE);
panel = new GamePanel(this);
add(panel);
}
public GamePanel getPanel() {
return panel;
}
public static void main(String[] args) {
new Game();
}
}
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.JPanel;
public class GamePanel extends JPanel implements ActionListener, KeyListener {
public
Game game;
public
Player player;
public GamePanel(Game game) {
setBackground(Color.GREEN);
this.game = game;
player = new Player(game, KeyEvent.VK_LEFT, KeyEvent.VK_RIGHT, game.getWidth() - 36);
addKeyListener(this);
setFocusable(true);
}
public
void update() {
player.update();
}
public void actionPerformed(ActionEvent e) {
update();
repaint();
}
public Player getPlayer(int playerNo) {
return player;
}
public void keyPressed(KeyEvent e) {
player.pressed(e.getKeyCode());
}
public void keyReleased(KeyEvent e) {
player.released(e.getKeyCode());
}
public void keyTyped(KeyEvent e) {
;
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
player.paint(g);
}
}
import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.Color;
public class Player {
public
static final int WIDTH = 50, HEIGHT = 50;
public
Game game;
public
int left, right;
public
int y;
public
int x, xa;
public Player(Game game, int left, int right, int x) {
this.game = game;
this.x = x;
y = game.getHeight() - 20;
this.left = left;
this.right = right;
this.y = y;
x = game.getWidth() - 36;
}
public void update() {
if (x > 0 && x < game.getWidth() - WIDTH - 36)
x += xa;
else if (x == 0)
x++;
else if (x == game.getWidth() - WIDTH - 36)
x--;
}
public void pressed(int keyCode) {
if (keyCode == left)
xa = -1;
else if (keyCode == right)
xa = 1;
}
public void released(int keyCode) {
if (keyCode == left || keyCode == right)
xa = 0;
}
public Rectangle getBounds() {
return new Rectangle(x, y, WIDTH, HEIGHT);
}
public void paint(Graphics g) {
g.fillRect(x, y, WIDTH, HEIGHT);
g.setColor(Color.ORANGE);
}
}
Take setVisible(true); and move it it to the last of the Game constructor. Also you should make sure you're working within the context of the EDT when building your UI's, see Initial Threads for more details
import java.awt.Color;
import java.awt.EventQueue;
import javax.swing.JFrame;
import static javax.swing.JFrame.EXIT_ON_CLOSE;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Game extends JFrame {
public final static int WIDTH = 700, HEIGHT = 450;
public GamePanel panel;
public Game() {
setTitle("Game");
setBackground(Color.WHITE);
setDefaultCloseOperation(EXIT_ON_CLOSE);
panel = new GamePanel(this);
add(panel);
setResizable(false);
setSize(WIDTH, HEIGHT);
setVisible(true);
}
public GamePanel getPanel() {
return panel;
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
new Game();
}
});
}
}
Basically, Swing's layout management is lazy, it won't try to update the container hierarchy until you tell it (revalidate) or it becomes realised or resized, this is a good thing, as the operation can be expensive.
Next, take a look at player = new Player(game, KeyEvent.VK_LEFT, KeyEvent.VK_RIGHT, game.getWidth() - 36);
You're setting the position of the player to be 36 pixels less than the components width, but when this is called, the width will be 0.
Basically, you need to allow the UI to "settle" before making this types of calls. This is actually not that easy. You could use a ComponentListener and monitor for the componentResized event, but a window can be resized a number of times when it's first initialized, to this end, you need to "wait" until the size is "settled", for example...
public Game() {
addComponentListener(new ComponentAdapter() {
private boolean initalised = false;
private Timer timer = new Timer(250, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
initalised = true;
panel.init();
timer.stop();
}
});
#Override
public void componentResized(ComponentEvent e) {
if (!initalised) {
timer.restart();
}
}
});
Then you would need to update GamePanel to provide an init method...
public class GamePanel extends JPanel implements ActionListener, KeyListener {
public Game game;
public Player player;
public GamePanel(Game game) {
setBackground(Color.GREEN);
this.game = game;
addKeyListener(this);
setFocusable(true);
}
public void init() {
player = new Player(game, KeyEvent.VK_LEFT, KeyEvent.VK_RIGHT, game.getWidth() - 36);
repaint();
}
//...
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
if (player != null) {
player.paint(g);
}
}
}
You have a wide range of "magic" numbers, which don't equate to what you're actually trying to do, for example...
player = new Player(game, KeyEvent.VK_LEFT, KeyEvent.VK_RIGHT, game.getWidth() - 36);
shouldn't that be game.getWidth() - Player.WIDTH?
And then in Player...
public Player(Game game, int left, int right, int x) {
this.game = game;
this.x = x;
y = game.getHeight() - 20;
//...
this.y = y;
x = game.getWidth() - 36;
}
You assign the parameter x to the field x, but then change it at the end of the constructor? Also, this.y = y makes no sense!?
Now, let's talk about what a bad idea setSize(WIDTH, HEIGHT);, which relates to why your player doesn't appear where you want it to...
Windows have decorations, so your viewable area will ALWAYS be smaller than the actual window size, what's worse, the size of the decorations are variable. Instead, you should use JFrame#pack to pack the window around it's contents and have the contents provide hints about big it wants to be.
Have a look at How can I set in the midst? for more details.
Instead of setting the size of the frame, you should be using pack...
public class Game extends JFrame {
public GamePanel panel;
public Game() {
addComponentListener(new ComponentAdapter() {
private boolean initalised = false;
private Timer timer = new Timer(250, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
initalised = true;
panel.init();
timer.stop();
}
});
#Override
public void componentResized(ComponentEvent e) {
if (!initalised) {
timer.restart();
}
}
});
setTitle("Game");
setBackground(Color.WHITE);
setDefaultCloseOperation(EXIT_ON_CLOSE);
panel = new GamePanel(this);
add(panel);
setResizable(false);
pack();
setVisible(true);
}
And allowing GamePanel to make decisions about how big it wants to be...
public static class GamePanel extends JPanel implements ActionListener, KeyListener {
public final static int WIDTH = 700, HEIGHT = 450;
public Game game;
public Player player;
public GamePanel(Game game) {
setBackground(Color.GREEN);
this.game = game;
addKeyListener(this);
setFocusable(true);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(WIDTH, HEIGHT);
}
This also means that instead of passing Game to your objects, you should be passing GamePanel to them and using its dimensions, for example...
public static class Player {
//...
public Player(GamePanel game, int left, int right, int x) {
this.game = game;
this.left = left;
this.right = right;
this.x = x;
y = game.getHeight() - HEIGHT;
}
You should also not be using KeyListener and instead should be using the Key Bindings API instead, which will solve the focus related issue and make it easier to configure the key strokes
Basically, you're missing some core understandings about how the Swing framework works, which is causing no end of issues, I'd take the time to learn more about how the framework works generally before diving into something as complex as game development
Runnable example...
Now, because I've basically butchered your code to get it to work...
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.JFrame;
import static javax.swing.JFrame.EXIT_ON_CLOSE;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Game extends JFrame {
public GamePanel panel;
public Game() {
addComponentListener(new ComponentAdapter() {
private boolean initalised = false;
private Timer timer = new Timer(250, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
initalised = true;
panel.init();
timer.stop();
}
});
#Override
public void componentResized(ComponentEvent e) {
if (!initalised) {
timer.restart();
}
}
});
setTitle("Game");
setBackground(Color.WHITE);
setDefaultCloseOperation(EXIT_ON_CLOSE);
panel = new GamePanel(this);
add(panel);
setResizable(false);
pack();
setVisible(true);
}
public GamePanel getPanel() {
return panel;
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
new Game();
}
});
}
public static class GamePanel extends JPanel implements ActionListener, KeyListener {
public final static int WIDTH = 700, HEIGHT = 450;
public Game game;
public Player player;
public GamePanel(Game game) {
setBackground(Color.GREEN);
this.game = game;
addKeyListener(this);
setFocusable(true);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(WIDTH, HEIGHT);
}
public void init() {
System.out.println("!!");
player = new Player(this, KeyEvent.VK_LEFT, KeyEvent.VK_RIGHT, getWidth() - 50);
repaint();
}
public void update() {
player.update();
}
public void actionPerformed(ActionEvent e) {
update();
repaint();
}
public Player getPlayer(int playerNo) {
return player;
}
public void keyPressed(KeyEvent e) {
player.pressed(e.getKeyCode());
}
public void keyReleased(KeyEvent e) {
player.released(e.getKeyCode());
}
public void keyTyped(KeyEvent e) {
;
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
if (player != null) {
player.paint(g);
}
}
}
public static class Player {
public static final int WIDTH = 50, HEIGHT = 50;
public GamePanel game;
public int left, right;
public int y;
public int x, xa;
public Player(GamePanel game, int left, int right, int x) {
this.game = game;
this.left = left;
this.right = right;
this.x = x;
y = game.getHeight() - HEIGHT;
}
public void update() {
if (x > 0 && x < game.getWidth() - WIDTH - 36) {
x += xa;
} else if (x == 0) {
x++;
} else if (x == game.getWidth() - WIDTH - 36) {
x--;
}
}
public void pressed(int keyCode) {
if (keyCode == left) {
xa = -1;
} else if (keyCode == right) {
xa = 1;
}
}
public void released(int keyCode) {
if (keyCode == left || keyCode == right) {
xa = 0;
}
}
public Rectangle getBounds() {
return new Rectangle(x, y, WIDTH, HEIGHT);
}
public void paint(Graphics g) {
System.out.println(x + "x" + y);
g.fillRect(x, y, WIDTH, HEIGHT);
g.setColor(Color.ORANGE);
}
}
}

Shapes not moving on drawing panel java

i am trying to make a simple java game with a bat(paddle) and ball. So far i have painted the 2 objects onto the panel, however i cant get them to move. i have added key events for the bat and a move() method for the ball. Below are all my classes.
Game class:
public class Game extends JFrame {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new Game();
}});
}
MyDrawingPanel myDrawingPanel = new MyDrawingPanel(this);
MyUIPanel myUIPanel = new MyUIPanel(this);
public Game()
{
setSize(1160,660); // you may change frame and panel sizes
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Container cp = getContentPane();
cp.setLayout(new FlowLayout());
cp.add(myDrawingPanel);
cp.add(myUIPanel);
setVisible(true);
}
}
MyDrawingPanel class:
class MyDrawingPanel extends JPanel {
Game game;
Ball ball = new Ball(this);
Bat bat = new Bat(this);
public MyDrawingPanel(Game game)
{
this.game=game;
setPreferredSize(new Dimension(800,600));
setBackground(Color.RED);
requestFocus();
}
public void paint(Graphics g)
{
super.paint(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
ball.paint(g2d);
Graphics2D gBat = (Graphics2D) g;
bat.paint(gBat);
}
}
Ball class:
public class Ball {
int x = 0;
int y = 0;
int xa = 1;
int ya = 1;
private MyDrawingPanel myDrawingPanel;
public Ball(MyDrawingPanel myDrawingPanel) {
this.myDrawingPanel = myDrawingPanel;
}
public void move() {
if (x + xa < 0)
xa = 1;
if (x + xa > myDrawingPanel.getWidth() - 30)
xa = -1;
if (y + ya < 0)
ya = 1;
if (y + ya > myDrawingPanel.getHeight() - 30)
ya = -1;
x = x + xa;
y = y + ya;
}
public void paint(Graphics2D g) {
g.fillOval(x, y, 30, 30);
}
}
Bat class:
public class Bat{
int x = 0;
int xa = 0;
private MyDrawingPanel myDrawingPanel;
public Bat(MyDrawingPanel myDrawingPanel)
{
this.myDrawingPanel = myDrawingPanel;
}
public void move(){
if(x + xa > 0 && x + xa <myDrawingPanel.getWidth()-60 )
x = x + xa;
}
public void paint(Graphics2D g)
{
g.setColor(Color.BLUE);
g.fillRoundRect(x, 500, 100, 20, 10, 10);
}
public void keyPressed(KeyEvent e)
{
if(e.getKeyCode() == KeyEvent.VK_LEFT)
xa = -1;
if(e.getKeyCode() == KeyEvent.VK_RIGHT)
xa = 1;
}
public void keyReleased(KeyEvent e)
{
xa = 0;
}
}
Methods such as keyPressed and keyReleased don't do anything without a KeyListener implementation. So currently, your methods are useless. What you should do have the DrawingPanel class implement the KeyListener, like this
public class DrawingPanel extends JPanel implements KeyListener {
...
}
The methods, keyPressed and keyReleased should be in that class. You'll also want setter methods for what ever variables are updated in the Bat class, like x and xa, is those are the variables that determine the movement of the Bat.
So in the keyPressed, which should be in the DrawingPanel class, it could look something like this
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_LEFT) {
bat.setXa(bat.getXa() - 1);
repaint();
}
if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
bat.setXa(1);
repaint();
}
}
Notice how I call repaint(). That's what you need to do after you move something.
This should get you started in the right direction
EDIT Forget the majority of the above answer.
Instead of using a KeyListener though I would recommeng using key binding. You may face focus problems using KeyListener. I implemented the keybinding for the DrawingPanel and it works fine. It'll give you some ideas to work with.
class MyDrawingPanel extends JPanel {
Game game;
Ball ball = new Ball(this);
Bat bat = new Bat(this);
public MyDrawingPanel(Game game) {
this.game = game;
setPreferredSize(new Dimension(800, 600));
setBackground(Color.RED);
requestFocus();
Action rightAction = new AbstractAction() {
public void actionPerformed(ActionEvent e) {
bat.x += 10;
repaint();
}
};
Action leftAction = new AbstractAction() {
public void actionPerformed(ActionEvent e) {
bat.x -= 10;
repaint();
}
};
InputMap inputMap = getInputMap(JPanel.WHEN_IN_FOCUSED_WINDOW);
ActionMap actionMap = getActionMap();
inputMap.put(KeyStroke.getKeyStroke("RIGHT"), "rightAction");
actionMap.put("rightAction", rightAction);
inputMap.put(KeyStroke.getKeyStroke("LEFT"), "leftAction");
actionMap.put("leftAction", leftAction);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
ball.paint(g2d);
Graphics2D gBat = (Graphics2D) g;
bat.paint(gBat);
}
}
See How to use key bindings

Categories

Resources