Java JFrame updates my screen slow untill I press a key - java

I am writing a simple game and I am working with java in JFrame. My output looks very bad untill I move the platform at the bottom, it looks like it have not enought update rate untill I press a button update and when I release the key it does the same thing. So this is the complete code with 2 classes:
public class BrickBreaker {
private static final String TITLE = "break ball";
private static final int X = 200, Y = 200, WIDTH = 700, HEIGHT = 600;
public static void main(String[] arg){
JFrame window = new JFrame();
GamePlay gp = new GamePlay();
window.setBounds(X,Y,WIDTH,HEIGHT);
window.setTitle(TITLE);
window.setResizable(false);
window.setVisible(true);
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.add(gp);
}
}
public class GamePlay extends JPanel implements KeyListener, ActionListener {
private boolean play = false;
private int score = 0, totalBricks = 21, delay = 10;
private int playerX = 310;
private int ballX = 120, ballY = 350, ballDirX = -1, ballDirY = -2;
private final Timer TIMER;
public GamePlay(){
addKeyListener(this);
setFocusable(true);
setFocusTraversalKeysEnabled(false);
TIMER = new Timer(delay, this);
TIMER.start();
}
public void paint(Graphics g){
//Background
g.setColor(Color.BLACK);
g.fillRect(1,1,700,592);
//Borders
g.setColor(Color.YELLOW);
g.fillRect(0,0,3,592);
g.fillRect(697,0,3,592);
g.fillRect(0,0,697,3);
//Paddle
g.setColor(Color.GREEN);
g.fillRect(playerX, 550, 100, 8);
//Ball
g.setColor(Color.YELLOW);
g.fillOval(ballX, ballY, 20, 20);
g.dispose();
}
#Override
public void actionPerformed(ActionEvent e) {
TIMER.start();
if (play){
TIMER.start();
ballX += ballDirX;
ballY += ballDirY;
if(ballX <= 0 || ballX >= 700){
ballDirX = - ballDirX;
}
if(ballY <= 0 || ballY >= 600){
ballDirY = -ballDirY;
}
}
repaint();
}
#Override
public void keyTyped(KeyEvent e) {}
#Override
public void keyReleased(KeyEvent e) {}
#Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_RIGHT){
if(playerX >= 590){
playerX = 590;
}else{
moveRight();
}
}else if(e.getKeyCode() == KeyEvent.VK_LEFT){
if(playerX <= 10){
playerX = 10;
}else{
moveLeft();
}
}
}
private void moveLeft() {
play = true;
playerX -= 20;
}
private void moveRight() {
play = true;
playerX += 20;
}
}
I want to know how to smooth the movement of the ball to be always at the rate of the keypressed state.

First of all there is no need to start the Timer in the ActionListener. You already start the Timer in the constructor.
JFrame updates my screen slow untill I press a key
There is no animation at all when I run the code.
Lets do some basic debugging:
public void actionPerformed(ActionEvent e) {
System.out.println(Play); // basic debugging
What do you see?
Then what happens when you press an arrow key?
Why do you only set the play variable in the moveRight/moveLeft methods?

Related

Why I can't change a variable's value inside an if-then statement?

I've been trying to learn more about Java recently, so I followed an online guide on how to build a game in Java. Everything worked fine, but I wanted to add on more so I could make it my own. It's been going OK so far, but I've recently reached a personal impasse. Here's the code so far, including what I've added on my own (my question is at the bottom):
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class PongGame extends JComponent implements ActionListener, MouseMotionListener {
public static PongGame game = new PongGame();
private int ballX = 400;
private int ballY = 250;
private int paddleX = 0;
private int ballYSpeed = 2;
private int ballXSpeed = 2;
private static int time = 15;
public static Timer t = new Timer(time, game);
public static void main(String[] args) {
JFrame window = new JFrame("Pong Game by Ethan");
window.add(game);
window.pack();
window.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
window.setLocationRelativeTo(null);
window.setVisible(true);
t.start();
window.addMouseMotionListener(game);
}
public Dimension getPreferredSize() {
return new Dimension(800, 600);
}
#Override
protected void paintComponent(Graphics g) {
//draw the background
g.setColor(Color.WHITE);
g.fillRect(0, 0, 800, 600);
//draw the paddle
g.setColor(Color.BLACK);
g.fillRect(paddleX, 510, 150, 15);
//draw the ball
g.setColor(Color.BLACK);
g.fillOval(ballX, ballY, 25, 25);
}
#Override
public void actionPerformed(ActionEvent e) {
ballX = ballX + ballXSpeed;
ballY = ballY + ballYSpeed;
if (ballX >= paddleX && ballX <= paddleX + 150 && ballY >= 485) {
ballYSpeed = -2;
lessTime();
}
if (ballX >=775) {
ballXSpeed = -2;
}
if (ballX <= 0) {
ballXSpeed = 2;
}
if (ballY <= 0) {
ballYSpeed = 2;
}
if (ballY == 500) {
PongGame.infoBox("GAME OVER","");
t.stop();
System.exit(0);
}
repaint();
}
#Override
public void mouseDragged(MouseEvent e) {
}
#Override
public void mouseMoved(MouseEvent e) {
paddleX = e.getX() - 75;
repaint();
}
public static void infoBox(String infoMessage, String titleBar) {
JOptionPane.showMessageDialog(null, infoMessage, "Game Over" + titleBar, JOptionPane.INFORMATION_MESSAGE);
}
public static void lessTime() {
time--;
}
}
As you can see, I have a variable in there called time near the top which is used by Timer t right below it, and a method named lessTime at the bottom which just removes 1 from the time variable when called. I have it set to call the lessTime method in the first if statement when the ball bounces off of the paddle to increase the speed of the game (I'm working towards a hit counter), but it doesn't seem to increase the speed at all.
I've tried using --time;, time--;, and time = time - 1; all inside the lessTime method and by themselves in the if statement, but none of them remove any amount from the time variable. Can someone explain why the time variable isn't affected by either the method or alone inside the if statement, and also how I can fix it?
Thank you!
The problem you're encountering is because Java is a "pass-by-value" language. This means that when you pass your int time variable into the constructor you're using to instantiate your Timer t variable, you have actually passed in the value of int time (15), not the int timevariable itself. The result is that if you change the value of your int time variable by decrementing it (so that it's now 14), the value inside your Timer t variable is still 15.
The shortest solution I can think of to get around your impasse is to add a line of code to your lessTime() method, like so:
public static void lessTime() {
time--;
// set t to a new Timer with the new decremented time value.
t = new Timer(time, game);
}

Prevent User from holding key down in Eclipse

I am creating a track and field game and I need the player to tap the button to fill the meter up. When the player releases the key the meter goes down. Unfortunately, when I hold the button the meter fills up.
Code:
public class TapGame extends JPanel implements ActionListener, KeyListener{
Timer tm = new Timer(5,this);
int barHeight = 0, bar = 0;
boolean canPress = true;
public TapGame(){
tm.start();
addKeyListener(this);
setFocusable(true);
setFocusTraversalKeysEnabled(false);
}
public void paintComponent(Graphics g){
super.paintComponent(g);
g.setColor(Color.GREEN);
g.fillRect(0, 355, bar, 10);
g.setColor(Color.WHITE);
g.drawRect(0, 355, 100, 10);
}
public void actionPerformed(ActionEvent e){
bar+= barHeight;
bar -= 2;
if (bar < 0) bar = 0;
if (bar > 98) bar = 98;
repaint();
}
public void keyPressed(KeyEvent e){
int c = e.getKeyCode();
if (c == KeyEvent.VK_A){
if (canPress) {
barHeight = 4;
canPress = false;
}
else barHeight=0;
}
}
public void keyTyped(KeyEvent e){}
public void keyReleased(KeyEvent e){
canPress = true;
barHeight =0;
}
public static void main(String[] args){
TapGame t = new TapGame();
JFrame jf = new JFrame("Tap Mini Game Test");
jf.setSize(600,400);
jf.setLocationRelativeTo(null);
jf.setVisible(true);
jf.add(t);
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
It appears java calls those button presses multiple times. See here:
https://stackoverflow.com/questions/5199581/java-keylistener-keypressed-method-fires-too-fast

Java continue movement right away after key pressed?

Well when I am pressing any of the key arrows, the red box moves, yes it moves 10px and then stops for 1 second & continues moving, instead of move right away without stopping.
example of the occurring issue:
(source: gyazo.com)
Can you see how it stopped for 1 or 0.5 secs and continued?
How can I fix it?
I am using KeyEventDispatcher
My key detecting:
Whole src:
public class Game extends Frame {
private class Keyboard implements KeyEventDispatcher {
private Game game;
public Keyboard(Game game) {
this.game = game;
}
#Override
public boolean dispatchKeyEvent(KeyEvent e) {
if (e.getID() == KeyEvent.KEY_PRESSED) {
this.movement(e);
} else if (e.getID() == KeyEvent.KEY_RELEASED) {
} else if (e.getID() == KeyEvent.KEY_TYPED) {
}
return false;
}
public void movement(KeyEvent e) {
int keyCode = e.getKeyCode();
switch( keyCode ) {
case KeyEvent.VK_UP:
game.movePlayer(0, -10);
break;
case KeyEvent.VK_DOWN:
game.movePlayer(0, 10);
break;
case KeyEvent.VK_LEFT:
game.movePlayer(-10, 0);
break;
case KeyEvent.VK_RIGHT :
game.movePlayer(10, 0);
break;
}
}
}
private static final long serialVersionUID = 1L;
private int coordinateX = 1;
private int coordinateY = 1;
public int width = 300;
public int height = width / 16 * 9;
public int scale = 3;
public int mouseY = MouseInfo.getPointerInfo().getLocation().y;
public int mouseX = MouseInfo.getPointerInfo().getLocation().x;
private Player player = new Player(0, 0);
public Game() {
Dimension size = new Dimension(width * scale, height * scale);
setPreferredSize(size);
frame.setSize(width, height);
frame.setResizable(false);
frame.setTitle("First game");
JPanel j = new JPanel();
j.setVisible(true);
JLabel text = new JLabel("coords");
j.add(text);
frame.add(this);
frame.pack();
frame.add(j);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager();
manager.addKeyEventDispatcher(new Keyboard(this));
}
private void movePlayer(int x, int y) {
/**
* Main region area
*/
int pX = 0, pY = 0;
if (y == 0) { // x
if (player.getX() + x + 100 > frame.getContentPane().getWidth() || player.getX() + x < 0) {
if (player.getX() + x < 0) {
player.setX(0);
return;
}
if (player.getX() + x > 0) {
player.setX(frame.getContentPane().getWidth() - 100);
return;
}
return;
}
pX = x;
}
else if (x == 0) { // y
if (player.getY() + y + 100 > frame.getContentPane().getHeight() || player.getY() + y < 0) {
if (player.getY() + y < 0) {
player.setY(0);
return;
}
if (player.getY() + y > 0) {
player.setY(frame.getContentPane().getHeight() - 100);
return;
}
return;
}
pY = y;
}
player.updatePosition(pX, pY);
}
public void update() {
}
public void render() {
bs = getBufferStrategy();
if (bs == null) {
createBufferStrategy(3);
return;
}
g = bs.getDrawGraphics();
g.setColor(Color.BLACK);
g.fillRect(0, 0, getWidth(), getHeight());
g.setColor(Color.RED);
g.fillRect(player.getX(), player.getY(), 100, 100);
g.dispose();
bs.show();
}
}
Frame.java:
public class Frame extends Canvas {
public static final long serialVersionUID = 8L;
public static JFrame frame = new JFrame();
public static Threads thread;
public static Game game;
public Graphics g;
public BufferStrategy bs;
/**
* #param args
*/
public static void main(String[] args) {
thread = new Threads(new Game());
thread.start();
}
}
The problem is the repeat rate for KeyStrokes. This is controlled by the OS.
The solution is to use a Swing Timer to schedule the animation as soon as the key is pressed.
See Motion Using the Keyboard for more information and a complete working example.
Also, you should NOT be using a KeyListener but intead should be using KeyBindings.

Collision detection in mouseMoved method

I am creating a game in java. In it, you control a square that follows your mouse. I want to implement collision detection for the square so that it stops slightly within the JFrame and not at the edge. This is very easy when doing this with the arrow keys, but I can't figure it out with the mouseMoved method. Here is the code where the mouseMoved method is:
public void mouseMoved(MouseEvent e){
repaint();
if(e.getX() <= 0)
playerX = 0;
if(e.getX() >= 300)
playerX = 500;
if(e.getY() <= 0)
playerY = 0;
if(e.getY() >= 300)
playerY = 500;
else
playerX = e.getX()-25;
playerY = e.getY()-25;
repaint();
}
Here's the code where the square is created:
public void paintComponent(Graphics g) {
Rectangle player = new Rectangle(playerX, playerY, 50, 50);
g.setColor(Color.blue);
g.fillRect(player.x, player.y, player.width, player.height);
repaint();
}
I don't think you'll need this, but just in case, here's all the code for the GamePanel class, which serves as the panel for my JFrame in the Main class. If you need the Main class let me know but I doubt you will:
package main;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JPanel;
public class GamePanel extends JPanel implements Runnable{
//Global variables
//Double buffering
private Image dbImage;
private Graphics dbg;
//JPanel variables
static final int GWIDTH = 500, GHEIGHT = 500;
static final Dimension gameDim = new Dimension(GWIDTH, GHEIGHT);
//Game variable
private Thread game;
private volatile boolean running = false;
public boolean mouseClicked = false;
//Character variables
int playerX = 150, playerY = 150;
public class Mouse extends MouseAdapter{
public void mousePressed(MouseEvent e){
mouseClicked = true;
}
public void mouseReleased(MouseEvent e){
mouseClicked = false;
}
public void mouseMoved(MouseEvent e){
repaint();
if(e.getX() <= 0)
playerX = 0;
if(e.getX() >= 300)
playerX = 500;
if(e.getY() <= 0)
playerY = 0;
if(e.getY() >= 300)
playerY = 500;
else
playerX = e.getX()-25;
playerY = e.getY()-25;
repaint();
}
}
public GamePanel(){
addMouseMotionListener(new Mouse());
setPreferredSize(gameDim);
setBackground(Color.BLUE);
setFocusable(true);
requestFocus(true);
}
public void run(){
while(running){
}
}
public void addNotify(){
super.addNotify();
startGame();
}
private void startGame(){
if(game == null || !running){
game = new Thread(this);
game.start();
running = true;
}
}
public void stopGame(){
if(running){
running = false;
}
//Paint method
}
public void paint(Graphics g){
dbImage = createImage(getWidth(), getHeight());
dbg = dbImage.getGraphics();
paintComponent(dbg);
g.drawImage(dbImage, 0, 0, this);
}
public void paintComponent(Graphics g) {
Rectangle player = new Rectangle(playerX, playerY, 50, 50);
g.setColor(Color.blue);
g.fillRect(player.x, player.y, player.width, player.height);
repaint();
}
private void log(String s){
System.out.println(s);
}
}
Thank you for your help. Please let me know if you need anything.
Your movement code is a bit off. You set the x position only if the Y is not out of bounds and always replace the Y value. Can I suggest full blocks in future - they help avoiding problems like this.
playerX = e.getX()-25;
playerY = e.getY()-25;
if(e.getX() <= 0){
playerX = 0;
}
else if(e.getX() >= 300){
playerX = 500;
}
if(e.getY() <= 0){
playerY = 0;
}
else if(e.getY() >= 300){
playerY = 500;
}
This sets the position first and then corrects it if the player is out of the bounds.

Swing Timer with Graphics component

I want to creat a circle in on a panel which appears and dissapears every 2 seconds.
Here is that i have:
public class Board extends JPanel implements ActionListener {
private final int DELAY = 2000;
private Timer timer;
/*
* constructor
*/
public Board() {
setFocusable(true);
initGame();
}
/*
* initialize board
*/
public void initGame() {
timer = new Timer(DELAY, this);
timer.start();
}
public void paint(Graphics g) {
super.paint(g);
g.setColor(Color.gray);
// draw an oval starting at 20,20 with a width and height of 100 and
// fill it
g.drawOval(20, 20, 100, 100);
g.fillOval(20, 20, 100, 100);
g.dispose();
}
#Override
public void actionPerformed(ActionEvent e) {
repaint();
}
}
thank you guys. Now I wanna control my circle. But again something is wrong and it is not moving as I want.
here are new methods:
private boolean left = false;
private boolean right = true;
private boolean up = false;
private boolean down = false;
private Timer timer;
public int x = 20;
public int y = 20;
public int x2 = 100;
public int y2 = 100;
...
public void paint(Graphics g) {
super.paint(g);
if (drawCircle) {
g.setColor(Color.gray);
// draw an oval starting at 20,20 with a width and height of 100 and
// fill it
g.drawOval(x, y, x2, y2);
g.fillOval(x, y, x2, y2);
}
// removes native non-Java recourses
g.dispose();
}
public void move() {
if (left) {
x -= 5;
}
if (right) {
x += 5;
}
if (up) {
y -= 5;
}
if (down) {
y += 5;
}
}
#Override
public void actionPerformed(ActionEvent e) {
move();
repaint();
}
private class TAdapter extends KeyAdapter {
public void keyPressed(KeyEvent e) {
int key = e.getKeyCode();
if ((key == KeyEvent.VK_LEFT) && (!right)) {
left = true;
up = false;
down = false;
}
if ((key == KeyEvent.VK_RIGHT) && (!left)) {
right = true;
up = false;
down = false;
}
if ((key == KeyEvent.VK_UP) && (!down)) {
up = true;
right = false;
left = false;
}
if ((key == KeyEvent.VK_DOWN) && (!up)) {
down = true;
right = false;
left = false;
}
}
}
/****/
Solved , i just added
addKeyListener(new TAdapter());
to my Board constructor!
You just need to have your Timer modify some state. Try something like this:
private boolean drawCircle = false;
public void actionPerformed(ActionEvent e) {
drawCircle = !drawCircle;
repaint();
}
public void paintComponent(Graphics g) {
//...
if ( drawCircle ) {
g.setColor(Color.gray);
//...
}
}
Aren't you supposed to formulate the question... as a question?
Anyway, add a boolean to your class, toggle it on each action event, and paint the oval only if it is true.
Edit/Notes:
- Override paintComponent instead of paint
- Don't dispose of a Graphics you haven't created. Either drop the line, or use g.create() to make a copy. See http://java.sun.com/products/jfc/tsc/articles/swing2d/ for details.

Categories