尝试创建一个 Pong 游戏
Trying to create a Pong game
我正在尝试在 Java 中创建一个乒乓球游戏,但我在球物理方面遇到了一些麻烦。一切都非常完美,直到球变得太慢。我这样做是为了让球的速度每帧每帧降低 0.02 像素,但我不希望它变得太慢,所以我进行了检查以防止它在 x 和 y 速度低于 2 时减速。问题是一旦发生这种情况,如果 x 或 y 速度明显小于另一个,它就不会保持当前轨迹。它似乎变得平滑,几乎和直线一样,除了每隔几秒向上或向下移动 1 个像素。这是我的球 class:
import java.awt.Graphics2D;
import java.awt.Graphics;
import java.awt.Rectangle;
public class Ball {
private static int DIAMETER = 30;
double x = 0;
double y = 0;
double xVel = 5;
double yVel = 5;
double prevX = 0;
double prevY = 0;
double minSpeed = 2;
double maxSpeed = 10;
int drawX = 0;
int drawY = 0;
boolean tooSlow = false;
public game game;
public Ball(game game) {
this.game = game;
}
public void move()
{
prevX = xVel;
prevY = yVel;
if(xVel > maxSpeed)
xVel = maxSpeed;
if(yVel > maxSpeed)
yVel = maxSpeed;
if(Math.abs(xVel) < minSpeed && Math.abs(yVel) < minSpeed)
tooSlow = true;
else
tooSlow = false;
if(x + xVel < 0){
xVel *= -1;
}
if(x + xVel > 484 - DIAMETER){
xVel *= -1;
}
if(y + yVel < 0){
yVel *= -1;
}
if(y + yVel > 261 - DIAMETER){
yVel *= -1;
}
if(collision()){
if(game.paddle.paddleTop().intersects(getBounds())){
y += game.paddle.y - game.paddle.prevY;
yVel = -1 * Math.abs(yVel) + (game.paddle.y - game.paddle.prevY);
}
if(game.paddle.paddleBottom().intersects(getBounds())){
y += game.paddle.y - game.paddle.prevY;
yVel = Math.abs(yVel) + (game.paddle.y - game.paddle.prevY);
}
if(game.paddle.paddleRight().intersects(getBounds())){
x += game.paddle.x - game.paddle.prevX;
xVel = Math.abs(xVel) + (game.paddle.x - game.paddle.prevX);
yVel += (game.paddle.y - game.paddle.prevY) / 2;
}
if(game.paddle.paddleLeft().intersects(getBounds())){
x += game.paddle.x - game.paddle.prevX;
xVel = -1 * Math.abs(xVel) + (game.paddle.x - game.paddle.prevX);
yVel += (game.paddle.y - game.paddle.prevY) / 2;
}
}
x += xVel;
y += yVel;
if(!tooSlow)
slow();
drawX = (int)x;
drawY = (int)y;
}
public void slow()
{
xVel = (Math.abs(xVel) - 0.02) * Math.signum(xVel);
yVel = (Math.abs(yVel) - 0.02) * Math.signum(yVel);
}
public void paint(Graphics2D g) {
g.fillOval(drawX, drawY, 30, 30);
}
public Rectangle getBounds()
{
return new Rectangle(drawX, drawY, DIAMETER, DIAMETER);
}
public boolean collision()
{
return game.paddle.getBounds().intersects(getBounds());
}
}
这些是我在 运行 游戏中使用的其余部分(以防有帮助):
import java.awt.Rectangle;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionListener;
import java.awt.event.KeyListener;
import java.awt.event.KeyEvent;
import java.awt.event.ActionEvent;
public class Paddle {
int x = 50;
int y = 10;
int xVel = 0;
int yVel = 0;
int prevX = 50;
int prevY = 10;
int speed = 4;
private static final int WIDTH = 10;
private static final int HEIGHT = 80;
private game game;
public Paddle(game game)
{
this.game = game;
}
public void move()
{
prevX = x;
prevY = y;
if(y + yVel > 0 && y + yVel < 261 - HEIGHT){
y += yVel;
}
if(x + xVel > 0 && x + xVel < 484 - WIDTH){
x += xVel;
}
}
public void keyPressed(KeyEvent e)
{
if(e.getKeyCode() == KeyEvent.VK_UP){
yVel = -speed;
}
if(e.getKeyCode() == KeyEvent.VK_DOWN){
yVel = speed;
}
if(e.getKeyCode() == KeyEvent.VK_LEFT){
xVel = -speed;
}
if(e.getKeyCode() == KeyEvent.VK_RIGHT){
xVel = speed;
}
}
public void keyReleased(KeyEvent e)
{
yVel = 0;
xVel = 0;
}
public void paint(Graphics2D g)
{
g.fillRect(x, y, WIDTH, HEIGHT);
}
public Rectangle getBounds()
{
return new Rectangle(x, y, WIDTH, HEIGHT);
}
public Rectangle paddleTop()
{
return new Rectangle(x + WIDTH / 2, y, 1, 1);
}
public Rectangle paddleLeft()
{
return new Rectangle(x, y, 1, HEIGHT);
}
public Rectangle paddleRight()
{
return new Rectangle(x + WIDTH, y, 1, HEIGHT);
}
public Rectangle paddleBottom()
{
return new Rectangle(x + WIDTH / 2, y + HEIGHT, 1, 1);
}
public Rectangle test()
{
return new Rectangle(x, y, WIDTH, HEIGHT);
}
}
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Graphics;
import java.awt.event.ActionListener;
import java.awt.event.KeyListener;
import java.awt.event.KeyEvent;
import java.awt.event.ActionEvent;
import javax.swing.JPanel;
import javax.swing.Timer;
public class game extends JPanel implements ActionListener, KeyListener{
private Timer t;
Ball ball = new Ball(this);
Paddle paddle = new Paddle(this);
public game()
{
t = new Timer(15,this);
t.start();
addKeyListener(this);
setFocusable(true);
}
public void actionPerformed(ActionEvent e)
{
ball.move();
paddle.move();
repaint();
}
public void keyPressed(KeyEvent e)
{
paddle.keyPressed(e);
}
public void keyReleased(KeyEvent e)
{
paddle.keyReleased(e);
}
public void keyTyped(KeyEvent e) {}
public void paint(Graphics g)
{
super.paint(g);
Graphics2D g2d = (Graphics2D) g;
ball.paint(g2d);
paddle.paint(g2d);
}
}
import javax.swing.JFrame;
public class main {
public static void main(String[]args)
{
JFrame frame = new JFrame("MLG Pong");
game display = new game();
frame.add(display);
frame.setSize(500,300);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setResizable(false);
System.out.println(""+display.getHeight()+" "+display.getWidth());
}
}
对不起,我的编码很乱,我 Java 几个月前才学会的。
问题出在slow()
方法中:
public void slow()
{
xVel = (Math.abs(xVel) - 0.02) * Math.signum(xVel);
yVel = (Math.abs(yVel) - 0.02) * Math.signum(yVel);
}
你实际上是从速度向量中减去另一个方向的向量。刚开始方向变化很小,后来变大了。您总是从速度向量中减去 (+-0.02, +-0.02)。
一个简单的解决方法是:
public void slow()
{
xVel = xVel*0.99;
yVel = yVel*0.99;
}
但这会比小速度更快地降低大速度。
如果您不想要这种行为,则必须计算一个与速度矢量具有相同方向的恒定长度的小矢量,然后减去它。
例如:
public void slow()
{
double len = Math.sqrt(xVel*xVel + yVel*yVel);
double sx = xVel/len*0.02;
double sy = yVel/len*0.02;
xVel = xVel - sx;
yVel = yVel - sy;
}
减速计算有误。当速度很慢的时候abs(v)-0.02
是无意义的
对了,你的计算方式不好。您应该修改向量而不是直接修改它们的投影:
获取速度矢量:vv=(length,angle)
。然后根据需要修改长度,方法是减去一些常量或在每一帧上使用一个因子。然后 vx=length*cos(angle)
和 vy=length*sin(angle)
.
您不必分别检查x 和y 方向的速度。您必须计算球的速度(在飞行方向)并根据最小速度检查结果。
换行
if(Math.abs(xVel) < minSpeed && Math.abs(yVel) < minSpeed)
到
if(xVel*xVel + yVel*yVel < minSpeed * minSpeed)
我正在尝试在 Java 中创建一个乒乓球游戏,但我在球物理方面遇到了一些麻烦。一切都非常完美,直到球变得太慢。我这样做是为了让球的速度每帧每帧降低 0.02 像素,但我不希望它变得太慢,所以我进行了检查以防止它在 x 和 y 速度低于 2 时减速。问题是一旦发生这种情况,如果 x 或 y 速度明显小于另一个,它就不会保持当前轨迹。它似乎变得平滑,几乎和直线一样,除了每隔几秒向上或向下移动 1 个像素。这是我的球 class:
import java.awt.Graphics2D;
import java.awt.Graphics;
import java.awt.Rectangle;
public class Ball {
private static int DIAMETER = 30;
double x = 0;
double y = 0;
double xVel = 5;
double yVel = 5;
double prevX = 0;
double prevY = 0;
double minSpeed = 2;
double maxSpeed = 10;
int drawX = 0;
int drawY = 0;
boolean tooSlow = false;
public game game;
public Ball(game game) {
this.game = game;
}
public void move()
{
prevX = xVel;
prevY = yVel;
if(xVel > maxSpeed)
xVel = maxSpeed;
if(yVel > maxSpeed)
yVel = maxSpeed;
if(Math.abs(xVel) < minSpeed && Math.abs(yVel) < minSpeed)
tooSlow = true;
else
tooSlow = false;
if(x + xVel < 0){
xVel *= -1;
}
if(x + xVel > 484 - DIAMETER){
xVel *= -1;
}
if(y + yVel < 0){
yVel *= -1;
}
if(y + yVel > 261 - DIAMETER){
yVel *= -1;
}
if(collision()){
if(game.paddle.paddleTop().intersects(getBounds())){
y += game.paddle.y - game.paddle.prevY;
yVel = -1 * Math.abs(yVel) + (game.paddle.y - game.paddle.prevY);
}
if(game.paddle.paddleBottom().intersects(getBounds())){
y += game.paddle.y - game.paddle.prevY;
yVel = Math.abs(yVel) + (game.paddle.y - game.paddle.prevY);
}
if(game.paddle.paddleRight().intersects(getBounds())){
x += game.paddle.x - game.paddle.prevX;
xVel = Math.abs(xVel) + (game.paddle.x - game.paddle.prevX);
yVel += (game.paddle.y - game.paddle.prevY) / 2;
}
if(game.paddle.paddleLeft().intersects(getBounds())){
x += game.paddle.x - game.paddle.prevX;
xVel = -1 * Math.abs(xVel) + (game.paddle.x - game.paddle.prevX);
yVel += (game.paddle.y - game.paddle.prevY) / 2;
}
}
x += xVel;
y += yVel;
if(!tooSlow)
slow();
drawX = (int)x;
drawY = (int)y;
}
public void slow()
{
xVel = (Math.abs(xVel) - 0.02) * Math.signum(xVel);
yVel = (Math.abs(yVel) - 0.02) * Math.signum(yVel);
}
public void paint(Graphics2D g) {
g.fillOval(drawX, drawY, 30, 30);
}
public Rectangle getBounds()
{
return new Rectangle(drawX, drawY, DIAMETER, DIAMETER);
}
public boolean collision()
{
return game.paddle.getBounds().intersects(getBounds());
}
}
这些是我在 运行 游戏中使用的其余部分(以防有帮助):
import java.awt.Rectangle;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionListener;
import java.awt.event.KeyListener;
import java.awt.event.KeyEvent;
import java.awt.event.ActionEvent;
public class Paddle {
int x = 50;
int y = 10;
int xVel = 0;
int yVel = 0;
int prevX = 50;
int prevY = 10;
int speed = 4;
private static final int WIDTH = 10;
private static final int HEIGHT = 80;
private game game;
public Paddle(game game)
{
this.game = game;
}
public void move()
{
prevX = x;
prevY = y;
if(y + yVel > 0 && y + yVel < 261 - HEIGHT){
y += yVel;
}
if(x + xVel > 0 && x + xVel < 484 - WIDTH){
x += xVel;
}
}
public void keyPressed(KeyEvent e)
{
if(e.getKeyCode() == KeyEvent.VK_UP){
yVel = -speed;
}
if(e.getKeyCode() == KeyEvent.VK_DOWN){
yVel = speed;
}
if(e.getKeyCode() == KeyEvent.VK_LEFT){
xVel = -speed;
}
if(e.getKeyCode() == KeyEvent.VK_RIGHT){
xVel = speed;
}
}
public void keyReleased(KeyEvent e)
{
yVel = 0;
xVel = 0;
}
public void paint(Graphics2D g)
{
g.fillRect(x, y, WIDTH, HEIGHT);
}
public Rectangle getBounds()
{
return new Rectangle(x, y, WIDTH, HEIGHT);
}
public Rectangle paddleTop()
{
return new Rectangle(x + WIDTH / 2, y, 1, 1);
}
public Rectangle paddleLeft()
{
return new Rectangle(x, y, 1, HEIGHT);
}
public Rectangle paddleRight()
{
return new Rectangle(x + WIDTH, y, 1, HEIGHT);
}
public Rectangle paddleBottom()
{
return new Rectangle(x + WIDTH / 2, y + HEIGHT, 1, 1);
}
public Rectangle test()
{
return new Rectangle(x, y, WIDTH, HEIGHT);
}
}
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Graphics;
import java.awt.event.ActionListener;
import java.awt.event.KeyListener;
import java.awt.event.KeyEvent;
import java.awt.event.ActionEvent;
import javax.swing.JPanel;
import javax.swing.Timer;
public class game extends JPanel implements ActionListener, KeyListener{
private Timer t;
Ball ball = new Ball(this);
Paddle paddle = new Paddle(this);
public game()
{
t = new Timer(15,this);
t.start();
addKeyListener(this);
setFocusable(true);
}
public void actionPerformed(ActionEvent e)
{
ball.move();
paddle.move();
repaint();
}
public void keyPressed(KeyEvent e)
{
paddle.keyPressed(e);
}
public void keyReleased(KeyEvent e)
{
paddle.keyReleased(e);
}
public void keyTyped(KeyEvent e) {}
public void paint(Graphics g)
{
super.paint(g);
Graphics2D g2d = (Graphics2D) g;
ball.paint(g2d);
paddle.paint(g2d);
}
}
import javax.swing.JFrame;
public class main {
public static void main(String[]args)
{
JFrame frame = new JFrame("MLG Pong");
game display = new game();
frame.add(display);
frame.setSize(500,300);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setResizable(false);
System.out.println(""+display.getHeight()+" "+display.getWidth());
}
}
对不起,我的编码很乱,我 Java 几个月前才学会的。
问题出在slow()
方法中:
public void slow()
{
xVel = (Math.abs(xVel) - 0.02) * Math.signum(xVel);
yVel = (Math.abs(yVel) - 0.02) * Math.signum(yVel);
}
你实际上是从速度向量中减去另一个方向的向量。刚开始方向变化很小,后来变大了。您总是从速度向量中减去 (+-0.02, +-0.02)。
一个简单的解决方法是:
public void slow()
{
xVel = xVel*0.99;
yVel = yVel*0.99;
}
但这会比小速度更快地降低大速度。
如果您不想要这种行为,则必须计算一个与速度矢量具有相同方向的恒定长度的小矢量,然后减去它。
例如:
public void slow()
{
double len = Math.sqrt(xVel*xVel + yVel*yVel);
double sx = xVel/len*0.02;
double sy = yVel/len*0.02;
xVel = xVel - sx;
yVel = yVel - sy;
}
减速计算有误。当速度很慢的时候abs(v)-0.02
是无意义的
对了,你的计算方式不好。您应该修改向量而不是直接修改它们的投影:
获取速度矢量:vv=(length,angle)
。然后根据需要修改长度,方法是减去一些常量或在每一帧上使用一个因子。然后 vx=length*cos(angle)
和 vy=length*sin(angle)
.
您不必分别检查x 和y 方向的速度。您必须计算球的速度(在飞行方向)并根据最小速度检查结果。
换行
if(Math.abs(xVel) < minSpeed && Math.abs(yVel) < minSpeed)
到
if(xVel*xVel + yVel*yVel < minSpeed * minSpeed)