Я пытаюсь воссоздать Понг и не могу заставить анимации работать так гладко, как хотелось бы. Иногда мяч делает движение там, где он замедляется, а затем очень быстро дергается. Где в моем коде я ошибаюсь? Кроме того, если вы могли бы просмотреть мой код, это будет оценено. Я просто пытаюсь поправиться.
Код для мяча
import java.awt.geom.Ellipse2D;
public class Ball extends Ellipse2D.Double{
//Ball movement variables
boolean movementX = true;
boolean movementY = true;
// Player one info
private int p1Number = 0;
private String p1Score = "0";
// Player two info
private int p2Number = 0;
private String p2Score = "0";
// Constructor
public Ball(double x, double y){
this.x = x;
this.y = y;
height = 20;
width = 20;
}
//function created to move the puck based on the position of the Puck, and the Players
public void MovePuck(double PlayerX, double PlayerY, double PlayerTwoX, double PlayerTwoY) {
// automatically move the X values
if (movementX) {
x+=5;
if (x >= 580) {
movementX = false;
}
} else {
x-=5;
if (x <= 0) {
movementX = true;
}
}
// automatically move the Y values
if (movementY) {
y+=2;
if (y >= 380) {
movementY = false;
}
} else {
y-=2;
if (y <= 0) {
movementY = true;
}
}
// Make Puck Bounce Off Player One
if(x == PlayerX + 10 && y <= PlayerY + 50 && y >= PlayerY){
movementX = true;
}
// Make Puck Bounce off Player Two
if(x == PlayerTwoX - 10 && y <= PlayerTwoY + 50 && y >= PlayerTwoY){
movementX = false;
}
}
// function created to keep track of Player One's Score
public String p1Score(){
if(x == 580){
p1Number++;
}
p1Score = String.valueOf(p1Number);
return p1Score;
}
// function created to keep track of Player Two's Score
public String p2Score(){
if (x == 0) {
p2Number++;
}
p2Score = String.valueOf(p2Number);
return p2Score;
}
}
Код для мяча
import java.awt.geom.Rectangle2D;
public class Rectangle extends Rectangle2D.Double{
private boolean isMovingUp, isMovingDown;
public Rectangle(double x, double y){
this.x = x;
this.y = y;
width = 10;
height = 50;
}
public void movePlayerUP(){
y-=3;
}
public void movePlayerDown(){
y+=3;
}
public void setMovingDown(boolean movingDown) {
isMovingDown = movingDown;
}
public boolean isMovingDown() {
return isMovingDown;
}
public void setMovingUp(boolean movingUp) {
isMovingUp = movingUp;
}
public boolean isMovingUp() {
return isMovingUp;
}
@Override
public double getY() {return super.getY();}
public double getX(){return super.getX();}
}
И, наконец, доска с логикой. Главное просто вызывает это и запускает.
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.image.BufferedImage;
public class Board extends JPanel {
private BufferedImage background;
//player one information
private int p1X = 20;
private int p1Y = 150;
private Rectangle playerOne;
//player two information
private int p2X = 550;
private int p2Y = 150;
private Rectangle playerTwo;
// puck information
private int PuckX = 290;
private int PuckY = 190;
private Ball Puck;
public Board() {
// creating each player and puck
playerOne = new Rectangle(p1X, p1Y);
playerTwo = new Rectangle(p2X, p2Y);
Puck = new Ball(PuckX, PuckY);
setDoubleBuffered(true);
addKeyBinding(this, KeyEvent.VK_UP, "moveUpPressed", false, (evt) -> {
playerOne.setMovingUp(true);
});
addKeyBinding(this, KeyEvent.VK_UP, "moveUpReleased", true, (evt) -> {
playerOne.setMovingUp(false);
});
addKeyBinding(this, KeyEvent.VK_DOWN, "moveDownPressed", false, (evt) -> {
playerOne.setMovingDown(true);
});
addKeyBinding(this, KeyEvent.VK_DOWN, "moveDownReleased", true, (evt) -> {
playerOne.setMovingDown(false);
});
addKeyBinding(this, KeyEvent.VK_W, " moveP2UpPressed", false, (evt) -> {
playerTwo.setMovingUp(true);
});
addKeyBinding(this, KeyEvent.VK_W, " moveP2UpReleased", true, (evt) -> {
playerTwo.setMovingUp(false);
});
addKeyBinding(this, KeyEvent.VK_S, " moveP2DownPressed", false, (evt) -> {
playerTwo.setMovingDown(true);
});
addKeyBinding(this, KeyEvent.VK_S, " moveP2DownReleased", true, (evt) -> {
playerTwo.setMovingDown(false);
});
// Timer to represent frames per second and constantly check the status of each button pressed
Timer timer = new Timer(20, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
// Move puck
Puck.MovePuck(playerOne.getX(), playerOne.getY(), playerTwo.getX(), playerTwo.getY());
repaint();
//Only move if the player is pressing each button
//Player One Moving UP
if(playerOne.isMovingUp()){
playerOne.movePlayerUP();
}
//Player One Moving Down
if(playerOne.isMovingDown()){
playerOne.movePlayerDown();
}
//Player Two Moving Up
if(playerTwo.isMovingUp()){
playerTwo.movePlayerUP();
}
//Player Two Moving Down
if(playerTwo.isMovingDown()){
playerTwo.movePlayerDown();
}
}
});
//Start Timer
timer.start();
}
// Created a function that represents adding keybinding. Easier than re-writing a function each time
public void addKeyBinding(JComponent comp, int keyCode, String id, boolean movement, ActionListener ActionListener){
InputMap im = comp.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
ActionMap ap = comp.getActionMap();
im.put(KeyStroke.getKeyStroke(keyCode, 0 , movement), id);
ap.put(id, new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
ActionListener.actionPerformed(e);
repaint();
}
});
}
public void paintComponent(Graphics g) {
super.paintComponents(g);
setOpaque(false);
// setting background with image
background = new BufferedImage(600, 400, BufferedImage.TYPE_INT_RGB);
g.drawImage(background, 0, 0, this);
// drawing player one
g.setColor(Color.blue);
((Graphics2D) g).fill(playerOne);
// drawing player two
g.setColor(Color.red);
((Graphics2D) g).fill(playerTwo);
// drawing puck
g.setColor(Color.orange);
((Graphics2D) g).fill(Puck);
//Player One Score
g.setColor(Color.white);
g.setFont(new Font("Arial", Font.PLAIN, 20));
g.drawString(Puck.p1Score(), 100, 30);
//Player Two Score
g.setColor(Color.white);
g.setFont(new Font("Arial", Font.PLAIN, 20));
g.drawString(Puck.p2Score(), 450, 30);
g.dispose();
}
}