I am coding a little Asteroids game, but it seems to be lagging a little bit. I am using a swing.Timer in order to update my JFrame and display the graphics. I have two questions,
the first one being:
"Could the timer be the reason for the lags?" and the second one being:
"Is using a Timer the optimal way to handle game programming in Java, or is it not?"
When browsing the net, it seemed like everyone is using a Timer in order to handle animations, but I can't help but feel that it is a suboptimal way of doing this. Can someone pls explain this to me? Thank you in advance :)
Here is the code of my Timer, if it helps. First the Base class:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import javax.swing.*;
public class Base implements ActionListener {
// Attributes
protected static int cd = 3; // Length of Countdown in seconds
private int nrOfAsteroids = 10; // Amount of Asteroids spawned
protected static int fps = 60; // Frames-per-second
// Various variables and constants
protected static BufferedImage image;
protected static int height;
protected static int width;
protected static boolean colorMode = false;
// Variables needed for Key-register
protected static boolean isWpressed = false;
private boolean isQpressed = false;
private boolean isEpressed = false;
private boolean isSpacePressed = false;
private boolean stop = false; // TODO remove after game is finished
// Various complex-objects
private static Base b = new Base();
private Asteroid[] a = new Asteroid[nrOfAsteroids];
private JFrame frame;
private JButton start;
private JButton colorButton;
private JLabel dummy;
private JLabel gameLabel;
protected static JLabel screen = new JLabel();
private ImageIcon icon;
private Timer t;
private static Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
public static void main(String[] args) {
height = (int) (screenSize.height * 0.9);
width = (int) (screenSize.width * 0.9);
image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
screen.setSize(width, height);
b.frameSetup();
} // end main
private void frameSetup() {
// Frame Setup
frame = new JFrame("yaaasssss hemorrhoids");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setBackground(Color.BLACK);
frame.setBounds((int) (screenSize.width * 0.05), (int) (screenSize.height * 0.03), width, height);
frame.setLayout(new GridBagLayout());
// creating a "color" button
colorButton = new JButton("CLASSIC");
GridBagConstraints cb = new GridBagConstraints();
cb.weightx = 1;
cb.weighty = 1;
cb.gridx = 2;
cb.gridy = 0;
cb.anchor = GridBagConstraints.FIRST_LINE_END;
cb.insets = new Insets(10, 0, 0, 10);
colorButton.setPreferredSize(new Dimension(100, 30));
frame.add(colorButton, cb);
// creating a "ASTEROIDS" Label
gameLabel = new JLabel("ASSTEROIDS");
GridBagConstraints gl = new GridBagConstraints();
gl.weightx = 1;
gl.weighty = 1;
gl.gridwidth = 3;
gl.gridx = 0;
gl.gridy = 1;
gl.anchor = GridBagConstraints.CENTER;
gl.fill = GridBagConstraints.BOTH;
gameLabel.setPreferredSize(new Dimension(100, 30));
gameLabel.setFont(gameLabel.getFont().deriveFont(60.0f));
gameLabel.setForeground(Color.WHITE);
gameLabel.setHorizontalAlignment(SwingConstants.CENTER);
frame.add(gameLabel, gl);
// Dummy Component
dummy = new JLabel();
GridBagConstraints dc = new GridBagConstraints();
dummy.setPreferredSize(new Dimension(100, 30));
dc.weightx = 1;
dc.weighty = 1;
dc.gridx = 0;
dc.gridy = 0;
frame.add(dummy, dc);
// creating a "start" button
start = new JButton("START");
GridBagConstraints sb = new GridBagConstraints();
sb.weightx = 1;
sb.weighty = 1;
sb.gridx = 1;
sb.gridy = 2;
sb.anchor = GridBagConstraints.PAGE_START;
sb.insets = new Insets(15, 0, 0, 0);
start.setPreferredSize(new Dimension(100, 30));
frame.add(start, sb);
// Implementing a function to the buttons
start.addActionListener(this);
colorButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (colorButton.getText() == "CLASSIC") {
colorMode = true;
colorButton.setText("LSD-TRIP");
} else {
colorMode = false;
colorButton.setText("CLASSIC");
}
}
});
// Show Results
frame.setVisible(true);
}
private void addImage() {
// Implementing the Image
icon = new ImageIcon(image);
screen.setIcon(icon);
frame.add(screen);
}
protected void setWindowSize() {
width = frame.getBounds().width;
height = frame.getBounds().height;
screen.setSize(width, height);
}
#Override
public void actionPerformed(ActionEvent ae) {
// Cleaning the screen
frame.remove(start);
frame.remove(gameLabel);
frame.remove(colorButton);
frame.remove(dummy);
// Checking if Window has been resized, and acting according to it
setWindowSize();
// Creating the image
for (int i = 0; i < nrOfAsteroids; ++i) {
a[i] = new Asteroid();
}
gameStart();
}
private void gameStart() {
t = new Timer(1000/fps, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
clearScreen();
for (int i = 0; i < nrOfAsteroids; ++i) {
a[i].drawAsteroid();
}
// Managing Controlls
if (isWpressed) {}
if (isQpressed) { }
if (isEpressed) { }
if (isSpacePressed) { }
if (stop) { }
// Updating the screen
b.addImage();
}
});
t.setInitialDelay(0);
actions();
t.start();
}
private void actions() {
// Defining all the constants for more order when handling the actions
final int focus = JComponent.WHEN_IN_FOCUSED_WINDOW;
String move = "Movement started";
String noMove = "Movement stopped";
String shoot = "Shooting started";
String noShoot = "Shooting stopped";
String turnLeft = "Rotation left started";
String noTurnLeft = "Rotation left stopped";
String turnRight = "Rotation right started";
String noTurnRight = "Rotation right stopped";
String stopIt = "stop"; // TODO remove when game is finished
// Getting the input and trigger an ActionMap
screen.getInputMap(focus).put(KeyStroke.getKeyStroke("W"), move);
screen.getInputMap(focus).put(KeyStroke.getKeyStroke("released W"), noMove);
screen.getInputMap(focus).put(KeyStroke.getKeyStroke("SPACE"), shoot);
screen.getInputMap(focus).put(KeyStroke.getKeyStroke("released SPACE"), noShoot);
screen.getInputMap(focus).put(KeyStroke.getKeyStroke("Q"), turnLeft);
screen.getInputMap(focus).put(KeyStroke.getKeyStroke("released Q"), noTurnLeft);
screen.getInputMap(focus).put(KeyStroke.getKeyStroke("E"), turnRight);
screen.getInputMap(focus).put(KeyStroke.getKeyStroke("released E"), noTurnRight);
screen.getInputMap(focus).put(KeyStroke.getKeyStroke("S"), stopIt);
// Triggered ActionMaps perform an Action
screen.getActionMap().put(move, new AbstractAction() {
private static final long serialVersionUID = 1L;
#Override
public void actionPerformed(ActionEvent e) {
isWpressed = true;
} });
screen.getActionMap().put(noMove, new AbstractAction() {
private static final long serialVersionUID = 1L;
#Override
public void actionPerformed(ActionEvent e) {
isWpressed = false;
} });
screen.getActionMap().put(shoot, new AbstractAction() {
private static final long serialVersionUID = 1L;
#Override
public void actionPerformed(ActionEvent e) {
isSpacePressed = true;
} });
screen.getActionMap().put(noShoot, new AbstractAction() {
private static final long serialVersionUID = 1L;
#Override
public void actionPerformed(ActionEvent e) {
isSpacePressed = false;
} });
screen.getActionMap().put(turnLeft, new AbstractAction() {
private static final long serialVersionUID = 1L;
#Override
public void actionPerformed(ActionEvent e) {
isQpressed = true;
} });
screen.getActionMap().put(noTurnLeft, new AbstractAction() {
private static final long serialVersionUID = 1L;
#Override
public void actionPerformed(ActionEvent e) {
isQpressed = false;
} });
screen.getActionMap().put(turnRight, new AbstractAction() {
private static final long serialVersionUID = 1L;
#Override
public void actionPerformed(ActionEvent e) {
isEpressed = true;
} });
screen.getActionMap().put(noTurnRight, new AbstractAction() {
private static final long serialVersionUID = 1L;
#Override
public void actionPerformed(ActionEvent e) {
isEpressed = false;
} });
screen.getActionMap().put(stopIt, new AbstractAction() {
private static final long serialVersionUID = 1L;
#Override
public void actionPerformed(ActionEvent e) {
stop = true;
} });
} // end actions()
private void clearScreen() {
Graphics2D pen = image.createGraphics();
pen.clearRect(0, 0, Base.width, Base.height);
}
} // end class
Now the Asteroid class:
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Polygon;
public class Asteroid {
// Attributes
private int amountOfCornerPoints = 12;
private int size = 50;
private int rotationSpeed = 2;
private int movementSpeed = 3;
// Fields needed to construct the Asteroid
private Polygon asteroidShape;
private int xCenter = (int) (Math.random() * Base.width);
private int yCenter = (int) (Math.random() * Base.height);
private int[] y = new int[amountOfCornerPoints];
private int[] x = new int[amountOfCornerPoints];
private int[] random = new int[amountOfCornerPoints];
private int rmax = 20; //Das Maximum für r
private int rmin = -rmax; //Das Minimum für r
// Field needed to transport the Asteroid
private boolean transporting = false;
// Field needed to rotate the Asteroid
private int cornerAddition = 0;
// Fields needed to detect Collision
// Fields needed to determine the direction of the Asteroid
private int direction = (int) Math.round((Math.random()*7));
private int xMove = 0;
private int yMove = 0;
// Fields for determining the color of the Asteroid
private Color col;
private int red = 255;
private int green = 255;
private int blue = 255;
public Asteroid() {
// Activating colorMode
if (Base.colorMode == true) {
do {
red = (int) Math.round((Math.random()*127));
green = (int) Math.round((Math.random()*127));
blue = (int) Math.round((Math.random()*127));
} while (red < 64 && green < 64 && blue < 64); }
col = new Color(red, green, blue);
// Zufallszahlen Generator
for (int i = 0; i < random.length; ++i) {
random[i] = (int) (Math.random()*rmax + rmin); }
asteroidShape = new Polygon();
whichDirection();
}
protected void drawAsteroid() {
move();
rotate();
int degreeHolder;
int degrees;
for (int i = 0; i < amountOfCornerPoints; ++i) {
degreeHolder = i*(360/amountOfCornerPoints) + cornerAddition;
if (degreeHolder >= 360) {
degrees = degreeHolder - 360;
} else {
degrees = degreeHolder;
}
x[i] = getXvalue(size + random[i])[degrees];
y[i] = getYvalue(size + random[i])[degrees];
}
asteroidShape.invalidate();
asteroidShape = new Polygon(x, y, amountOfCornerPoints);
Graphics2D pen = Base.image.createGraphics();
pen.setColor(col);
pen.draw(asteroidShape);
pen.dispose();
}
private void rotate() {
cornerAddition += rotationSpeed;
if (cornerAddition >= 360)
cornerAddition = cornerAddition - 360;
}
private void move() {
detectTransport();
xCenter += xMove;
yCenter += yMove;
}
private void detectTransport() {
boolean transportImmunity = false;
if (xCenter <= -size || xCenter >= Base.width + size) {
if (transportImmunity == false)
transporting = !transporting;
transportImmunity = true;
transport();
}
if (yCenter <= -size || yCenter >= Base.height + size) {
if (transportImmunity == false)
transporting = !transporting;
transportImmunity = true;
transport();
}
}
private void transport() {
while (transporting) {
xCenter -= xMove;
yCenter -= yMove;
detectTransport();
}
}
private void whichDirection() {
switch (direction) {
case 0: // Gerade Oben
xMove = 0;
yMove = -movementSpeed;
break;
case 1: // Diagonal Oben-rechts
xMove = movementSpeed;
yMove = -movementSpeed;
break;
case 2: // Gerade rechts
xMove = movementSpeed;
yMove = 0;
break;
case 3: // Diagonal Unten-rechts
xMove = movementSpeed;
yMove = movementSpeed;
break;
case 4: // Gerade Unten
xMove = 0;
yMove = movementSpeed;
break;
case 5: // Diagonal Unten-links
xMove = -movementSpeed;
yMove = movementSpeed;
break;
case 6: // Gerade links
xMove = -movementSpeed;
yMove = 0;
break;
case 7: // Diagonal Oben-links
xMove = -movementSpeed;
yMove = -movementSpeed;
break;
}
} // end WhichDirection
private int[] getXvalue(int radius) {
int[] xPoint = new int[360];
for (int i = 0; i < 360; ++i) {
double xplus = Math.cos(Math.toRadians(i+1)) * radius;
xPoint[i] = (int) Math.round(xCenter + xplus); }
return xPoint;
}
private int[] getYvalue(int radius) {
int[] yPoint = new int[360];
for (int i = 0; i < 360; ++i) {
double yPlus = Math.sin(Math.toRadians(i+1)) * radius;
yPoint[i] = (int) Math.round(yCenter - yPlus); }
return yPoint;
}
}
PS.: My computer is most likely not the cause, since it can run a lot bigger games with at least 100fps
Edit: None of the other methods, as for example the rotate() method, is causing the lag, as I have already tried the entire code with only the most essential methods and the result was the same.
Edit2: Maybe its worth noting, that the lag actually is only barely noticeable. However, for a game as small as an Asteroids is, there really shouldn't be any lag, especially if it only runs on 60 fps.
Edit3: MRE is added
I would suggest an/fps-limiting approach instead because the lag that can happen in the game gets amplified by the strict time intervals of the Timer class. After you set the frame to be visible add the following code(or something like it):
long time = System.nanoTime();
while(!gameOver) {
long nTime = System.nanoTime();
float diff = (nTime - time) * 0.000000001f;
if(diff > 1.0f / fps) {
time = nTime;
// do rendering here and multiply any speeds or accelerations by diff
}
}
Related
So I'm making a game where the enemies follow the player and the player kills them. How do I make the enemies' ImageViews follow the player.
I have tried some if sentences but I actually have no idea. I also searched everywhere but I only find other people doing it with Swing and I get really confused with a lot of things. I use Javafx btw.
public class Main extends Application{
private static final int HEIGHT = 720;
private static final int WIDTH = 1280;
Scene scene;
BorderPane root, htpLayout;
VBox buttons, paragraphs, images;
Button startButton, htpButton, htpReturnButton, leaderboardButton, exitButton;
Text gameName, paragraph1, paragraph2, paragraph3;
Pane gameLayout;
ImageView background;
Game game = new Game();
Player player = new Player();
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage window) throws Exception {
root = new BorderPane();
background = new ImageView("stick mob slayer background.png");
background.fitWidthProperty().bind(window.widthProperty());
background.fitHeightProperty().bind(window.heightProperty());
root.getChildren().add(background);
htpLayout = new BorderPane();
buttons = new VBox(15);
scene = new Scene(root, WIDTH, HEIGHT);
scene.getStylesheets().add("mobslayer/style.css");
gameName = new Text("Mob Slayer Unlimited");
gameName.setFont(Font.font("Complex", 50));
gameName.setFill(Color.WHITE);
root.setAlignment(gameName, Pos.CENTER_LEFT);
root.setTop(gameName);
startButton = new Button("Start Game");
startButton.setOnAction(e -> window.setScene(game.getScene()));
htpButton = new Button("How To Play");
htpButton.setOnAction(e -> scene.setRoot(htpLayout));
leaderboardButton = new Button("Leaderboard");
exitButton = new Button("Exit");
exitButton.setOnAction(e -> Platform.exit());
buttons.getChildren().addAll(startButton, htpButton, leaderboardButton, exitButton);
root.setCenter(buttons);
buttons.setAlignment(Pos.CENTER);
paragraphs = new VBox(30);
paragraph1 = new Text("Objektive\nNär spelet börjar kommer huvudkaraktären möta monster.\n"
+ "Ju längre in i spelet du kommer, ju fler och svårare monster dyker upp.\n"
+ "Ditt mål är att överleva så länge som möjligt.");
paragraph1.setFont(Font.font("Dubai", 13));
paragraph1.setFill(Color.BLACK);
paragraph2 = new Text("Movement\nAlla monster dras imot dig, så du måste akta dig.\n"
+ "Detta gör du med hjälp av piltangenterna.");
paragraph2.setFont(Font.font("Dubai", 13));
paragraph2.setFill(Color.BLACK);
paragraph3 = new Text("Special Effects\nDu kan också attackera tillbaka med en lätt attack(c)\n"
+ "eller med en specialattack(space) som dödar alla monster på skärmen.\n"
+ "Du kan dasha(x) för att röra dig snabbare åt ett håll.");
paragraph3.setFont(Font.font("Dubai", 13));
paragraph3.setFill(Color.BLACK);
paragraphs.getChildren().addAll(paragraph1, paragraph2, paragraph3);
htpReturnButton = new Button("Return");
htpReturnButton.setOnAction(e->scene.setRoot(root));
htpLayout.setBottom(htpReturnButton);
htpLayout.setAlignment(htpReturnButton,Pos.TOP_CENTER);
images = new VBox(30);
// Image image1 = new Image(new FileInputStream("resources\\cod zombies.jpg"));
// final ImageView image11 = new ImageView(image1);
// image11.setFitHeight(100);
// image11.setFitWidth(100);
// image11.setPreserveRatio(true);
//
// Image image2 = new Image(new FileInputStream("resources\\arrowkeys.png")) ;
// final ImageView image22 = new ImageView(image2);
// image22.setFitHeight(100);
// image22.setFitWidth(100);
// image22.setPreserveRatio(true);
//
// Image image3 = new Image(new FileInputStream("resources\\keys.png")) ;
// final ImageView image33 = new ImageView(image3);
// image33.setFitHeight(100);
// image33.setFitWidth(100);
// image33.setPreserveRatio(true);
//
// images.getChildren().addAll(image11, image22, image33);
//
paragraphs.setAlignment(Pos.TOP_LEFT);
htpLayout.setLeft(paragraphs);
htpLayout.setRight(images);
window.setTitle("Mob Slayer Unlimited");
window.setScene(scene);
window.setResizable(false);
window.show();
}
}
public class Game {
private static final int HEIGHT = 720;
private static final int WIDTH = 1280;
private Scene scene;
Pane root;
Text health, stamina, wave, kills;
int waveCounter = 1, killCounter = 0;
Button restartButton, pauseButton;
Line limitUp;
Player player = new Player();
Enemies enemy = new Enemies();
public Game() {
health = new Text(50, 30, "HP: " + player.getHealth());
health.setFont(Font.font("BankGothic Lt BT", 30));
health.setFill(Color.WHITE);
stamina = new Text(50, 80, "STAMINA: " + player.getStamina());
stamina.setFont(Font.font("BankGothic Lt BT", 30));
stamina.setFill(Color.WHITE);
wave = new Text(1050, 30, "WAVE: " + waveCounter);
wave.setFont(Font.font("BankGothic Lt BT", 30));
wave.setFill(Color.WHITE);
kills = new Text(1050, 80, "KILLS: " + killCounter);
kills.setFont(Font.font("BankGothic Lt BT", 30));
kills.setFill(Color.WHITE);
restartButton = new Button("RESTART");
restartButton.setFont(Font.font("BankGothic Lt BT", 30));
restartButton.setOnAction(e -> restart());
restartButton.setLayoutX(350);
restartButton.setLayoutY(20);
pauseButton = new Button("PAUSE");
pauseButton.setFont(Font.font("BankGothic Lt BT", 30));
pauseButton.setOnAction(e -> restart());
pauseButton.setLayoutX(650);
pauseButton.setLayoutY(20);
limitUp = new Line(0, 100, 1280, 100);
limitUp.setStroke(Color.WHITE);
root = new Pane(player.getSlayer(), limitUp, player.getSlayerHitbox(), health, stamina, wave, kills, restartButton, pauseButton, enemy.getEnemy());
root.setStyle("-fx-background-color: black");
enemy.enemyMovement();
movePlayerTo(WIDTH / 2, HEIGHT / 2);
scene = new Scene(root, WIDTH, HEIGHT);
scene.setOnKeyPressed(new EventHandler<KeyEvent>() {
#Override
public void handle(KeyEvent event) {
switch (event.getCode()) {
case W: player.goUp = true; break;
case S: player.goDown = true; break;
case A: player.goLeft = true; break;
case D: player.goRight = true; break;
case K: player.running = true; break;
}
}
});
scene.setOnKeyReleased(new EventHandler<KeyEvent>() {
#Override
public void handle(KeyEvent event) {
switch (event.getCode()) {
case W: player.goUp = false; break;
case S: player.goDown = false; break;
case A: player.goLeft = false; break;
case D: player.goRight = false; break;
case K: player.running = false; break;
}
}
});
AnimationTimer timer = new AnimationTimer() {
#Override
public void handle(long now) {
int dx = 0, dy = 0;
if (player.goUp) dy -= 2;
if (player.goDown) dy += 2;
if (player.goRight) dx += 2;
if (player.goLeft) dx -= 2;
if (player.running) { dx *= 2; dy *= 2; }
enemy.enemyMovement();
movePlayerBy(dx, dy);
}
};
timer.start();
}
public Scene getScene() {
return scene;
}
// I took this methods for movement from Github
public void movePlayerBy(int dx, int dy) {
if (dx == 0 && dy == 0) return;
final double cx = player.getSlayer().getBoundsInLocal().getWidth() / 2;
final double cy = player.getSlayer().getBoundsInLocal().getHeight() / 2;
double x = cx + player.getSlayer().getLayoutX() + dx;
double y = cy + player.getSlayer().getLayoutY() + dy;
movePlayerTo(x, y);
}
public void movePlayerTo(double x, double y) {
final double cx = player.getSlayer().getBoundsInLocal().getWidth() / 2;
final double cy = player.getSlayer().getBoundsInLocal().getHeight() / 2;
if (x - cx >= 0 &&
x + cx <= WIDTH &&
y - cy >= 0 &&
y + cy <= HEIGHT) {
player.getSlayer().relocate(x - cx, y - cy);
player.getSlayerHitbox().relocate(x - cx + 37, y - cy + 35);
}
}
public class Player {
private int health;
private int damage;
private int stamina;
private Image slayerImage;
private ImageView slayer;
private Rectangle slayerHitbox;
boolean running, goUp, goDown, goRight, goLeft;
public Player () {
health = 5;
damage = 1;
stamina = 5;
slayerImage = new Image("stick mob slayer.png", 100, 100, true, true);
slayer = new ImageView(slayerImage);
slayerHitbox = new Rectangle(10, 50);
}
public int getDamage() {
return damage;
}
public void setDamage(int damage) {
this.damage = damage;
}
public int getHealth() {
return health;
}
public void setHealth(int health) {
this.health = health;
}
public int getStamina() {
return stamina;
}
public void setStamina(int stamina) {
this.stamina = stamina;
}
public ImageView getSlayer() {
return slayer;
}
public Rectangle getSlayerHitbox() {
slayerHitbox.setFill(Color.TRANSPARENT);
return slayerHitbox;
}
}
public class Enemies {
private int health;
private int speed;
private Image enemyImage;
private ImageView enemy;
private Rectangle enemyHitbox;
Player player = new Player();
public Enemies () {
health = 1;
speed = 1;
enemyImage = new Image("stick enemy.png", 100, 100, true, true);
enemy = new ImageView(enemyImage);
enemyHitbox = new Rectangle(10, 50);
}
public int getHealth() {
return health;
}
public void setHealth(int health) {
this.health = health;
}
public int getSpeed() {
return speed;
}
public void setSpeed(int speed) {
this.speed = speed;
}
public ImageView getEnemy () {
return enemy;
}
public Rectangle getEnemyHitbox() {
enemyHitbox.setFill(Color.YELLOW);
return enemyHitbox;
}
}
This is everything I have done so far. I would appreciate any help. If possible I would like to know how to make the enemies appear from random spots of the borders of the screen as well. Thanks in advance.
you should try first something more simple like implementing A* path search algo or some grid with some units on it before trying todo a game and having such questions
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 7 years ago.
Improve this question
For my binary tree program, I have been using JTextFields as nodes and I have managed to make it so when I click left button and select two of the JTextFields, it will draw a line between them. The problem is if I want to drag the JtextField around, I want the line to be following as well between two of the midpoints of the JTextField. I don't know if it's possible with using only paintComponent or not. I did try it but it's like a one off thing and it will leave a trail of all the previously drawn lines.
Here, is the code so far, there are other classes so some of the bits won't work. The code has been fiddled around a bit as well for testing.
public class BinaryTreeMainPnl extends JPanel {
public static Graphics g1;
public int Width = 75;
public int Height = 45;
public String tempNode1 = "";
public int tempNode1Pos = 0;
public int tempNode2Pos = 0;
public String tempNode2 = "";
public static boolean leftBtnSelected;
public static boolean rightBtnSelected;
private static int x1, y1 = 50;
private static int x2, y2 = 500;
JToggleButton leftBtn = new JToggleButton("Left");
JToggleButton rightBtn = new JToggleButton("Right");
JTextField[] myArray = new JTextField[60];
ArrayList<String> nodeNames = new ArrayList<String>();
JFrame MainFrame;
JTextField txtFld1 = new JTextField("Enter Questions here");
JButton btn1 = new JButton("Submit");
public BinaryTreeMainPnl(JFrame frame) {
super();
setSize(800, 700);
MainFrame = frame;
readInput();
leftBtn.setFont(new Font("Arial", Font.BOLD, 15));
leftBtn.setForeground(Color.blue);
leftBtn.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
rightBtn.setSelected(false);
leftBtnSelected = leftBtn.getModel().isSelected();
rightBtnSelected = false;
System.out.println(leftBtnSelected);
System.out.println(rightBtnSelected);
}
});
add(leftBtn);
rightBtn.setFont(new Font("Arial", Font.BOLD, 15));
rightBtn.setForeground(Color.green);
rightBtn.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
leftBtn.setSelected(false);
rightBtnSelected = rightBtn.getModel().isSelected();
leftBtnSelected = false;
System.out.println(leftBtnSelected);
System.out.println(rightBtnSelected);
}
});
add(rightBtn);
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
updateLine(g);
}
public void readInput() {
btn1.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
identifyNodeNames(txtFld1.getText());
displayNodes(nodeNames);
new TreeSorting().treeSort(nodeNames);
}
});
this.add(txtFld1);
this.add(btn1);
}
public void displayNodes(ArrayList<String> nodeNames) {
for (int i = 0; i < nodeNames.size(); i++) {
String currentSetText = nodeNames.get(i);
myArray[i] = new JTextField(currentSetText);
myArray[i].setEditable(false);
}
for (int i = 0; i < nodeNames.size(); i++) {
int I = i;
myArray[I].addMouseMotionListener(new MouseAdapter() {
#Override
public void mouseDragged(MouseEvent evt) {
int x = evt.getX() + myArray[I].getX();
int y = evt.getY() + myArray[I].getY();
myArray[I].setBounds(x, y, myArray[I].getWidth(), myArray[I].getWidth());
System.out.println(myArray[I] + "dragged");
}
});
myArray[I].addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent evt) {
if (leftBtnSelected) {
if (tempNode1.equals("")) {
tempNode1 = myArray[I].getText();
System.out.println(tempNode1 + "clicked");
} else {
tempNode2 = myArray[I].getText();
System.out.println(tempNode2 + "Clicked as well");
leftBtn.setSelected(false);
leftBtnSelected = false;
x1 = 40;
y1 = 40;
x2 = 400;
y2 = 400;
updateLine(g1);
System.out.println("asdasd");
}
}
if (rightBtnSelected) {
}
}
public void moveComponent(MouseEvent evt) {
}
});
System.out.println("I " + I);
System.out.println(myArray[I].getText());
add(myArray[I]);
}
MainFrame.revalidate();
}
public int findMidPoint(JTextField temp) {
Point p = temp.getLocation();
Dimension d = temp.getSize();
return p.x + (d.width) / 2;
}
int coun = 0;
public void updateLine(Graphics g) {
g.drawLine(x1, x2, y1, y2);
x1 = x1 + 10;
y1 = y1 + 10;
y2 = y2 + 10;
x2 = x2 + 10;
System.out.println("Line Updated" + coun);
coun++;
}
public void identifyNodeNames(String answer) {
int arrayCounter = 0;
int lastNodePosition = 0;
for (int i = 0; i < answer.length(); i++) {
char c = answer.charAt(i);
if (c == ',') {
nodeNames.add(arrayCounter, answer.substring(lastNodePosition, i + 1).replaceAll(",", "").replaceAll(" ", ""));
lastNodePosition = i + 1;
arrayCounter++;
}
if (i == answer.length() - 1) {
nodeNames.add(arrayCounter, answer.substring(lastNodePosition, answer.length()).replaceAll(" ", ""));
}
}
}
}
import java.util.ArrayList;
public class TreeSorting {
public static int arrayLength;
String[][] Child;
String root = "";
boolean nodeSorted = false;
int parentCounter = 1;
public void treeSort(ArrayList<String> passedQuestions) {
// declaring nodes
arrayLength = passedQuestions.size();
System.out.println(arrayLength + "ARRAY LENGTH");
Child = new String[arrayLength][3];
for (int i = 0; i < arrayLength; i++) {
Child[i][0] = passedQuestions.get(i);
}
//initially calling the mainprocess with parentCounter 1;
root = Child[0][0];
mainProcess(1);
}
public void mainProcess(int parentCounter) {
if (parentCounter < Child.length) {
System.out.println(parentCounter);
sortingTree(Child[parentCounter][0], root, 0); //where the next node is passed on the tree is sorted recursively
for (int i = 0; i < Child.length; i++) {
System.out.println(Child[i][0]);
System.out.println(Child[i][1] + "," + Child[i][2]);
}
}
}
public void sortingTree(String CurrentNode, String PreviousNode, int PreviousPosition) {
nodeSorted = false;// node is not sorted in the beginning
if (isAfter(CurrentNode.toLowerCase(), PreviousNode.toLowerCase())) {
System.out.println(Child[PreviousPosition][2]);
if (Child[PreviousPosition][2] == null) { //checks if the right of the node is empty, if found empty the node is placed there.
Child[PreviousPosition][2] = CurrentNode;
nodeSorted = true; // if the node finds a position in the array node is sorted.
} else {
sortingTree(CurrentNode, Child[PreviousPosition][2], getPositionInArray(Child[PreviousPosition][2]));
//if the array position was not empty, the loop will process again this time with the item found in the filled position.
}
} else if (Child[PreviousPosition][1] == null) { // if the left of the node is empty, the item will be placed there
Child[PreviousPosition][1] = CurrentNode;
nodeSorted = true;
} else {
sortingTree(CurrentNode, Child[PreviousPosition][1], getPositionInArray(Child[PreviousPosition][1]));
//if the array position was not empty, the loop will process again this time with the item found in the filled position.
}
if (nodeSorted) { // if the node finds a position in the array, the nodeCounter increments and the next node in the question is processed.
parentCounter++;
mainProcess(parentCounter);
}
}
public int getPositionInArray(String node) {
int position = 0;
loop:
for (int i = 0; i < Child.length; i++) {
if (Child[i][0].equals(node)) {
position = i;
break loop;
}
}
return position;
}
public boolean isAfter(String CurrentNode, String PreviousNode) {
int loopLength = determineLoopLength(CurrentNode, PreviousNode);
boolean result = false;
String tempCheck = "";
loop:
for (int i = 0; i < loopLength; i++) {
if ((int) CurrentNode.charAt(i) > (int) PreviousNode.charAt(i)) {
result = true;
break loop;
}
if ((int) CurrentNode.charAt(i) < (int) PreviousNode.charAt(i)) {
result = false;
break loop;
} else if (CurrentNode.charAt(i) == PreviousNode.charAt(i) && CurrentNode.length() > PreviousNode.length()) {
System.out.println("I'm here");
tempCheck = tempCheck + CurrentNode.charAt(i) + "";
if (i == loopLength - 1 && tempCheck.equals(PreviousNode)) {
result = true;
break loop;
}
}
}
return result;
}
public int determineLoopLength(String CurrentNode, String PreviousNode) {
int loopLength = 0;
if (CurrentNode.length() < PreviousNode.length()) {
loopLength = CurrentNode.length();
}
if (PreviousNode.length() < CurrentNode.length()) {
loopLength = PreviousNode.length();
} else {
loopLength = CurrentNode.length();
}
return loopLength;
}
}
WTF, been working on this,.....
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.*;
#SuppressWarnings("serial")
public class DragMyFields extends JPanel {
private static final int PREF_W = 1000;
private static final int PREF_H = 800;
private static final int COLS = 8;
private static final int DELTA_Y = 120;
private static final int MAX_DEPTH = 3;
private MySimpleTreeNode<JTextField> treeRoot = new MySimpleTreeNode<>();
private MyMouse myMouse = new MyMouse();
public DragMyFields() {
setLayout(null); // this is *** BAD ***
// much better would be to create a custom layout
JTextField field = new JTextField(COLS);
field.addMouseListener(myMouse);
field.addMouseMotionListener(myMouse);
field.setSize(field.getPreferredSize());
int x = (PREF_W - field.getPreferredSize().width) / 2;
int y = DELTA_Y;
field.setLocation(x, y);
add(field);
treeRoot.setNode(field);
recursiveCreateTree(treeRoot, MAX_DEPTH, x, y);
}
private void recursiveCreateTree(MySimpleTreeNode<JTextField> node, int depth, int x, int y) {
if (depth == 0) {
return;
}
JTextField leftField = new JTextField(COLS);
JTextField rightField = new JTextField(COLS);
MySimpleTreeNode<JTextField> leftNode = new MySimpleTreeNode<>(leftField);
MySimpleTreeNode<JTextField> rightNode = new MySimpleTreeNode<>(rightField);
node.setLeft(leftNode);
node.setRight(rightNode);
int multiplier = 4;
for (int i = 0; i < MAX_DEPTH - depth; i++) {
multiplier *= 2;
}
int xL = x - getPreferredSize().width / multiplier;
int xR = x + getPreferredSize().width / multiplier;
y += DELTA_Y;
leftField.setSize(leftField.getPreferredSize());
rightField.setSize(rightField.getPreferredSize());
leftField.setLocation(xL, y);
rightField.setLocation(xR, y);
leftField.addMouseListener(myMouse);
leftField.addMouseMotionListener(myMouse);
rightField.addMouseListener(myMouse);
rightField.addMouseMotionListener(myMouse);
add(leftField);
add(rightField);
recursiveCreateTree(leftNode, depth - 1, xL, y);
recursiveCreateTree(rightNode, depth - 1, xR, y);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
recursiveDraw(g, treeRoot);
}
private void recursiveDraw(Graphics g, MySimpleTreeNode<JTextField> node) {
MySimpleTreeNode<JTextField> left = node.getLeft();
MySimpleTreeNode<JTextField> right = node.getRight();
Point p = getNodeCenter(node);
if (left != null) {
Point p2 = getNodeCenter(left);
g.drawLine(p.x, p.y, p2.x, p2.y);
recursiveDraw(g, left);
}
if (right != null) {
Point p2 = getNodeCenter(right);
g.drawLine(p.x, p.y, p2.x, p2.y);
recursiveDraw(g, right);
}
}
private Point getNodeCenter(MySimpleTreeNode<JTextField> node) {
JTextField field = node.getNode();
Point location = field.getLocation();
Dimension size = field.getSize();
return new Point(location.x + size.width / 2, location.y + size.height / 2);
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
private class MyMouse extends MouseAdapter {
Component source = null;
private Point pressedP;
private Point pressedLoc;
private Point parentP;
#Override
public void mousePressed(MouseEvent e) {
if (e.getButton() != MouseEvent.BUTTON1) {
return;
}
source = e.getComponent();
parentP = source.getParent().getLocationOnScreen();
pressedLoc = source.getLocationOnScreen();
pressedP = e.getLocationOnScreen();
}
#Override
public void mouseReleased(MouseEvent e) {
moveComponent(e);
source = null;
pressedP = null;
pressedLoc = null;
}
#Override
public void mouseDragged(MouseEvent e) {
if (source == null) {
return;
}
moveComponent(e);
}
private void moveComponent(MouseEvent e) {
Point p = e.getLocationOnScreen();
int x = pressedLoc.x + p.x - pressedP.x - parentP.x;
int y = pressedLoc.y + p.y - pressedP.y - parentP.y;
Point newP = new Point(x, y);
source.setLocation(newP);
repaint();
}
}
private static void createAndShowGui() {
DragMyFields mainPanel = new DragMyFields();
JFrame frame = new JFrame("DragMyFields");
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(() -> {
createAndShowGui();
});
}
}
class MySimpleTreeNode<T> {
private T node;
private MySimpleTreeNode<T> left;
private MySimpleTreeNode<T> right;
public MySimpleTreeNode() {
// default constructor
}
public MySimpleTreeNode(T node) {
this.node = node;
}
public void setNode(T node) {
this.node = node;
}
public T getNode() {
return node;
}
public MySimpleTreeNode<T> getLeft() {
return left;
}
public void setLeft(MySimpleTreeNode<T> left) {
this.left = left;
}
public MySimpleTreeNode<T> getRight() {
return right;
}
public void setRight(MySimpleTreeNode<T> right) {
this.right = right;
}
}
I'm making a small game in Java using an extension of Swing's JPanel as my drawing surface.
I draw everything inside panel's paintComponent()
The game runs smoothly until I start moving my mouse. When I do I get huge FPS drops, especially if i move it very fast, making the game unplayable.
That happens even when I stop drawing the mouse cursor.
Is this normal when drawing on JComponent objects?
P.S. I couldn't find any registered MouseListener or MouseMotionListener objects on any of my components.
EDIT:
MCVE
import java.awt.*;
import java.awt.event.ActionEvent;
import javax.swing.*;
public class AnimationSlowDownOnMouse {
public static void main(String[] args) {
// TODO Auto-generated method stub
JFrame mainWindow = new JFrame("dotShoot");
mainWindow.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
mainWindow.setExtendedState(JFrame.MAXIMIZED_BOTH);
final GamePanel gp = new GamePanel();
gp.setPreferredSize(new Dimension(1920, 1080));
mainWindow.add(gp);
mainWindow.pack();
gp.init();
Thread gameThread = new Thread(new Runnable() {
#Override
public void run() {
final int maxTicksPerSecond = 100;
final int optimalTimePerTick = 1000 / maxTicksPerSecond;
final int maxFrameSkips = 5;
long tickCount = 0L;
float AvgIES = 0f;
//int FPS = 0;
int DCPS = 0;
int TPS = 0;
long timeStarted = System.currentTimeMillis();
long timeElapsed = 0L;
int tickReset = 0;
int drawCallsReset = 0;
long timeReset = timeStarted;
float interpolationReset = 0f;
long nextLoop = timeStarted;
int frameSkips = 0;
float interpolation;
while (true) {
synchronized (this) {
frameSkips = 0;
while (System.currentTimeMillis() > nextLoop && frameSkips < maxFrameSkips) {
gp.update(tickCount);
nextLoop += optimalTimePerTick;
tickCount++;
tickReset++;
frameSkips++;
}
interpolation = (float) (System.currentTimeMillis() + optimalTimePerTick - nextLoop) / (float) optimalTimePerTick;
gp.setInterpolation(interpolation);
gp.repaint();
interpolationReset += interpolation;
drawCallsReset++;
timeElapsed = System.currentTimeMillis() - timeStarted;
if (System.currentTimeMillis() - timeReset >= 1000) {
AvgIES = interpolationReset / (float) drawCallsReset;
interpolationReset = 0f;
TPS = tickReset;
tickReset = 0;
DCPS = drawCallsReset;
drawCallsReset = 0;
timeReset = System.currentTimeMillis();
}
}
}
}
});
gameThread.start();
mainWindow.setVisible(true);
gp.requestFocus();
}
}
class GamePanel extends JPanel {
/**
*
*/
private static final long serialVersionUID = 3110478596996378903L;
public GamePanel() {
this.getInputMap().put(KeyStroke.getKeyStroke("pressed A"), "pressed Key");
this.getInputMap().put(KeyStroke.getKeyStroke("released A"), "released Key");
this.getInputMap().put(KeyStroke.getKeyStroke("pressed D"), "pressed Key");
this.getInputMap().put(KeyStroke.getKeyStroke("released D"), "released Key");
this.getInputMap().put(KeyStroke.getKeyStroke("pressed W"), "pressed Key");
this.getInputMap().put(KeyStroke.getKeyStroke("released W"), "released Key");
this.getInputMap().put(KeyStroke.getKeyStroke("pressed S"), "pressed Key");
this.getInputMap().put(KeyStroke.getKeyStroke("released S"), "released Key");
this.getActionMap().put("pressed Key", new AbstractAction() {
private static final long serialVersionUID = 1296609706338138539L;
#Override
public void actionPerformed(ActionEvent arg0) {
if (!pks.contains(arg0.getActionCommand())) {
pks += arg0.getActionCommand() + ", ";
}
}
});
this.getActionMap().put("released Key", new AbstractAction() {
private static final long serialVersionUID = 4364732373538162119L;
#Override
public void actionPerformed(ActionEvent arg0) {
pks = pks.replace(arg0.getActionCommand() + ", ", "");
}
});
this.setBackground(new Color(0x6495ed));
}
public void init() {
}
private String pks = "";
public void update(long currentTick) {
}
private float interpolation = 0;
public void setInterpolation(float interpolation) {
this.interpolation = interpolation;
}
private int frames = 0;
private long timeForFPS = 0;
private int ActualFPS = 0;
public int getFPS() {
return ActualFPS;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.black);
g.drawString("FPS: " + ActualFPS, 0, 10);
frames++;
if (System.currentTimeMillis() - timeForFPS >= 1000) {
ActualFPS = frames;
frames = 0;
timeForFPS = System.currentTimeMillis();
}
}
}
EDIT 2:
http://tinypic.com/r/9bkf4k/8
http://tinypic.com/r/345m24i/8
As with the other comments, there is no problem with FPS when I tried the code above here in my computer. I also tried it on my virtual machine having one processor only. Still there is no dramatic drop of the FPS when the mouse is moving fast. Although the processor always shows 100% usage. Have you tried this with other computers? I suspect, you too won't see the FPS problem in there. So maybe the issue lies in your computer and not on your program code.
This question already has an answer here:
Implementing gravity in simple 2d game
(1 answer)
Closed 7 years ago.
I need to use a physics engine or something similar to achieve a downward parabolic jump in the game that I have. Right now, the up arrow will just cause the character to float, but I need him to jump.
Here is my code:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.EnumMap;
import java.util.Random;
import javax.imageio.ImageIO;
import javax.swing.*;
#SuppressWarnings("serial")
public class Level extends JPanel {
public static String chicken = "chicken.gif";
public static String chicken2 = "chicken2.gif";
private static final int PREF_W = 1440;
private static final int PREF_H = 500;
private static final int TIMER_DELAY = 20;
private static final String KEY_DOWN = "key down";
private static final String KEY_RELEASE = "key release";
public static final int TRANSLATE_SCALE = 3;
public static final String back = "back.gif";
public static final String corn = "corn.gif";
private EnumMap<Direction, Boolean> dirMap = new EnumMap<Level.Direction, Boolean>(
Direction.class);
private BufferedImage image = null;
private BufferedImage image2 = null;
private BufferedImage image3 = null;
private static int imgX = 20;
private static int imgY = 320;
private static Random rand = new Random();
private static int cImgX = rand.nextInt(1420) + 10;
private static int cImgY = 335;
private static int cornCounter = 0;
private static String Counter = Integer.toString(cornCounter);
private static final Font BG_STRING_FONT = new Font(Font.SANS_SERIF,
Font.BOLD, 32);
private int bgStringX;
public Level() {
for (Direction dir : Direction.values()) {
dirMap.put(dir, Boolean.FALSE);
}
try {
File bback = new File(back);
image2 = ImageIO.read(bback);
File ccorn = new File(corn);
image3 = ImageIO.read(ccorn);
File img = new File(chicken);
image = ImageIO.read(img);
} catch (IOException e) {
e.printStackTrace();
}
new Timer(TIMER_DELAY, new TimerListener()).start();
// here we set up our key bindings
int condition = JComponent.WHEN_IN_FOCUSED_WINDOW;
InputMap inputMap = getInputMap(condition);
ActionMap actionMap = getActionMap();
for (final Direction dir : Direction.values()) {
// for the key down key stroke
KeyStroke keyStroke = KeyStroke.getKeyStroke(dir.getKeyCode(), 0,
false);
inputMap.put(keyStroke, dir.name() + KEY_DOWN);
actionMap.put(dir.name() + KEY_DOWN, new AbstractAction() {
#Override
public void actionPerformed(ActionEvent arg0) {
dirMap.put(dir, true);
}
});
// for the key release key stroke
keyStroke = KeyStroke.getKeyStroke(dir.getKeyCode(), 0, true);
inputMap.put(keyStroke, dir.name() + KEY_RELEASE);
actionMap.put(dir.name() + KEY_RELEASE, new AbstractAction() {
#Override
public void actionPerformed(ActionEvent arg0) {
dirMap.put(dir, false);
}
});
}
FontMetrics fontMetrics = getFontMetrics(BG_STRING_FONT);
int w = fontMetrics.stringWidth(Counter);
bgStringX = (PREF_W - w) / 2;
}
#Override
public Dimension getPreferredSize() {
return new Dimension(PREF_W, PREF_H);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
if (image != null) {
g.drawImage(image2, 0, 0, this);
validate();
g.drawImage(image3, cImgX, cImgY, this);
validate();
g.drawImage(image, imgX, imgY, this);
validate();
}
g.setFont(BG_STRING_FONT);
g.setColor(Color.BLACK);
g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
g.drawString(Counter, bgStringX, 190);
}
private class TimerListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
for (Direction dir : Direction.values()) {
if (dirMap.get(dir)) {
imgX += dir.getX() * TRANSLATE_SCALE;
imgY += dir.getY() * TRANSLATE_SCALE;
//System.out.println(imgY);
if(imgX >= 188 && imgX <= 380) {
if(imgY <= 190 && imgY >= 199) {
imgY = 194;
}
}
if (imgX >= (cImgX - 10) && imgX <= (cImgX + 10)) {
cImgX = rand.nextInt(1420) + 10;
repaint();
validate();
cornCounter += 1;
Counter = Integer.toString(cornCounter);
//System.out.println(cornCounter);
repaint();
validate();
}
if(imgX <= -60) {
imgX = 1373;
repaint();
validate();
}
else if(imgX >= 1442) {
imgX = 1;
repaint();
validate();
}
if(imgY >= 320) {
imgY = 320;
}
else if(imgY <= 1) {
imgY = 1;
}
}
}
repaint();
};
}
enum Direction {
Up(KeyEvent.VK_UP, 0, -1),
Left(KeyEvent.VK_A, -1, 0), Right(KeyEvent.VK_D, 1, 0),
LeftA(KeyEvent.VK_LEFT, -1, 0), RightA(KeyEvent.VK_RIGHT, 1, 0),
Down(KeyEvent.VK_DOWN, 0, 1);
private int keyCode;
private int x;
private int y;
private Direction(int keyCode, int x, int y) {
this.keyCode = keyCode;
this.x = x;
this.y = y;
}
public int getKeyCode() {
return keyCode;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
}
private static void createAndShowGui() {
Level mainPanel = new Level();
JFrame frame = new JFrame("Cockadoodle Duty: Awakening");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
createAndShowGui();
}
});
}
}
That would be an overkill if you just want to achieve a simple jumping motion.
int vy = 0; //velocity of y
//.... heres your update code:
y += vy; //y is the yposition of your image or character
vy += GRAVITY; //GRAVITY is some arbitrary positive value
//...here's your onJump method:
vy = jumpSpeed; //jumpSpeed is some arbitrary negative value
I am new to Java. I started to learn by creating a bouncing ball GUI.
I have managed to do all i wanted to do with it except one thing. I can't get the ball to change its color whenever it bounces off the Frame Borders.
I know i can't use getGraphics for drawing but in this case i can also not use the paint Method as i already use it for the initial settings at the beginning of the Program. If i call the paint method from within the loop, it does change the color but all the JButtons in the North Side of the Layout mysteriously vanish.
The one Thing that makes the whole thing even more complicated for me is the fact that i am looping the ball bounce in a void run method of the Runnable Interface.
I couldn't figure out how to solve it elsewise.
You Guys can copy my code in your IDE. The one thing that doesn't work is that the ball remains black and doesn't changes it'S color. Everything else is running fine.
So Please help me figure out how i can change the ball's color whenever it bounces.
Thanks
Code:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class Ball extends JFrame implements Runnable, ActionListener {
private JButton start;
private JButton stop;
private JButton fast;
private JButton slow;
private JButton reset;
private int ball_x;
private int ball_y;
private int dx = 10;
private int dy = 20;
private int size = 50;
private boolean active;
private int i = 20;
private int R = 255;
private int G = 0;
private int B = 255;
private Color rgb;
private MyPanel screen;
private class MyPanel extends JPanel {
public void paintComponent(Graphics g) {
super.paintComponent(g);
ball_x = screen.getWidth() / 2 - 25;
ball_y = screen.getHeight() / 2 - 25;
i = 20;
g.setColor(rgb);
g.fillOval(ball_x, ball_y, size, size);
}
public void clr() {
if (R <= 10) {
R = 255;
}
R = R - 10;
if (G >= 255) {
G = 0;
}
G = G + 15;
if (B <= 20) {
B = 255;
}
B = B - 20;
}
}
public void start() {
active = true;
start.setText("Start");
start.setEnabled(false);
start.setText("Jumping...");
Thread th = new Thread(this); // Thread anlegen
th.start(); // Thread starten
}
public void stop() {
if (active) {
start.setText("Continue");
}
active = false;
start.setEnabled(true);
}
public void reset() {
active = false;
size = 50;
screen.repaint();
start.setText("Start");
start.setEnabled(true);
}
public void slow() {
i = i + 2;
if (i >= 60) {
i = 60;
}
}
public void fast() {
i = i - 2;
if (i <= 5) {
i = 5;
}
}
public void actionPerformed(ActionEvent ereignis) {
if (ereignis.getSource() == start) {
start();
}
if (ereignis.getActionCommand() == "G+") {
fast();
}
if (ereignis.getActionCommand() == "G-") {
slow();
}
if (ereignis.getActionCommand() == "Reset") {
reset();
}
if (ereignis.getActionCommand() == "Pause") {
stop();
}
}
public Ball() {
this.setTitle("Jumping Ball \u00a9 The One");
Container panel = new Container();
panel.setLayout(new BorderLayout());
JPanel subpanel = new JPanel();
//subpanel.setLayout(new GridLayout());
screen = new MyPanel();
this.setVisible(true);
this.setSize(1366, 768);
this.setContentPane(panel);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
start = new JButton("Start");
fast = new JButton("G+");
slow = new JButton("G-");
reset = new JButton("Reset");
stop = new JButton("Pause");
subpanel.add(start);
subpanel.add(fast);
subpanel.add(slow);
subpanel.add(reset);
subpanel.add(stop);
panel.add(subpanel, "North");
panel.add(screen, "Center");
start.addActionListener(this);
stop.addActionListener(this);
reset.addActionListener(this);
slow.addActionListener(this);
fast.addActionListener(this);
}
public void run() {
while (active) {
screen.getGraphics().clearRect(ball_x, ball_y, size, size);
if (ball_x > (screen.getWidth() - 30) || ball_x < 25) {
dx = -dx;
size = size + 3;
screen.clr();
}
if (ball_y > (screen.getHeight() - 30) || ball_y < 25) {
dy = -dy;
size = size + 3;
screen.clr();
}
ball_x = ball_x + dx;
ball_y = ball_y + dy;
rgb = new Color(R, G, B);
screen.getGraphics().setColor(rgb);
screen.getGraphics().fillOval(ball_x, ball_y, size, size);
try {
Thread.sleep(i);
} catch (InterruptedException x) {
x.printStackTrace();
}
}
}
public static void main(String[] args) {
Ball bouncer = new Ball();
} // End of Method Main
}
Thank You
While complete, your example has several critical problems:
It is incorrectly synchronized.
It calls setVisible() prematurely.
It relies on the frame's geometry, rather than an enclosed panel.
Instead, start with the example cited here using a Swing Timer. Note that the color changes with each repaint(), and a sound is played with each bounce. Add a member variable, bounced.
private boolean bounced;
When the ball bounces, set bounced = true in the actionPerformed() method of the Timer.
if (ballX - RADIUS < 0) {
…
bounced = true;
} else if (ballX + RADIUS > BOX_WIDTH) {
…
bounced = true;
}
In paintComponent(), change the color accordingly.
g.setColor(clut.peek());
if (bounced) {
clut.add(clut.remove());
bounced = false;
}
It may be easier to see the change with a smaller clut.
private static final float N = 16;
Well i got it to work but i don't think this is the best way to do it! I had to ditch Threads and go for Timer.
I have been reading everywhere that one shouldn't mix AWT and Swing but i don't see any other possibility than panel.setLayout(new BorderLayout()); or public void paintComponent(Graphics g)
This is obviously mixing AWT and Swing Components but i didn't find any pure Swing way to do it.
Anyways this is my entire Code:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class Ball extends JFrame implements ActionListener {
private JButton start;
private JButton stop;
private JButton fast;
private JButton slow;
private JButton reset;
private int ball_x;
private int ball_y;
private int dx = 10;
private int dy = 20;
private boolean active;
private int i = 30;
private int R = 255;
private int G = 255;
private int B = 0;
private Color rgb;
private Timer trigger = new Timer(i, this);
private MyPanel screen;
private class MyPanel extends JPanel {
public void paintComponent(Graphics g) {
super.paintComponent(g);
if (start.getText() == "Start") {
ball_x = screen.getWidth() / 2 - 50;
ball_y = screen.getHeight() / 2 - 50;
}
if (start.getText() == "Jumping...") {
g.clearRect(ball_x, ball_y, 100, 100);
}
ball_x = ball_x + dx;
ball_y = ball_y + dy;
rgb = new Color(R, G, B);
g.setColor(rgb);
g.fillOval(ball_x, ball_y, 100, 100);
if (ball_x > (screen.getWidth() - 100) || ball_x < 10) {
dx = -dx;
screen.clr();
}
if (ball_y > (screen.getHeight() - 100) || ball_y < 10) {
dy = -dy;
screen.clr();
}
}
public void clr() {
if (R <= 10) {
R = 255;
}
R = R - 10;
if (G <= 20) {
G = 255;
}
G = G - 20;
if (B >= 255) {
B = 0;
}
B = B + 15;
}
}
public void start() {
active = true;
start.setText("Start");
start.setEnabled(false);
start.setText("Jumping...");
trigger.start();
screen.repaint();
}
public void stop() {
if (active) {
start.setText("Continue");
}
active = false;
start.setEnabled(true);
trigger.stop();
}
public void reset() {
active = false;
start.setText("Start");
start.setEnabled(true);
i = 100;
trigger.stop();
screen.repaint();
}
public void slow() {
i = i + 10;
if (i >= 100) {
i = 100;
}
trigger.setDelay(i);
}
public void fast() {
i = i - 10;
if (i <= 10) {
i = 10;
}
trigger.setDelay(i);
}
public void actionPerformed(ActionEvent ereignis) {
if ((ereignis.getSource() == start) || (trigger.isRunning() == true)) {
start();
}
if (ereignis.getActionCommand() == "G+") {
fast();
}
if (ereignis.getActionCommand() == "G-") {
slow();
}
if (ereignis.getActionCommand() == "Reset") {
reset();
}
if (ereignis.getActionCommand() == "Pause") {
stop();
}
}
public Ball() {
this.setTitle("Jumping Ball \u00a9 The One");
JPanel panel = new JPanel();
panel.setLayout(new BorderLayout());
this.setContentPane(panel);
JPanel subpanel = new JPanel();
panel.add(subpanel, "North");
screen = new MyPanel();
screen.setBackground(Color.WHITE);
panel.add(screen, "Center");
start = new JButton("Start");
fast = new JButton("G+");
slow = new JButton("G-");
reset = new JButton("Reset");
stop = new JButton("Pause");
subpanel.add(start);
subpanel.add(fast);
subpanel.add(slow);
subpanel.add(reset);
subpanel.add(stop);
start.addActionListener(this);
stop.addActionListener(this);
reset.addActionListener(this);
slow.addActionListener(this);
fast.addActionListener(this);
this.setSize(1280, 720);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setVisible(true);
}
public static void main(String[] args) {
Ball fenster = new Ball();
} // Ende der Methode Main
}
I know this is not the professional way to do it but this is the best i could do and it does what i wanted it to do.
I will be more than happy if someone could point out some absolute no-go's in my Code.
Thanx