现在,我正在制作一个大理石游戏,其中两个玩家尝试将他们的弹珠射入一个圆圈。圈中有更多弹珠的玩家获胜。
轮到它的玩家会在他们希望球移动的相反方向上点击并拖动(有点像吊索)。在我的Marble class
,中,有一个线程在释放鼠标时启动。大理石将移动并从墙壁反弹,慢慢达到零和X的Y和Y速度。
但是当发生这种情况时,我的线程会继续循环并通过计算机CPU进食。
你可以知道线程仍然在运行,因为即使球停止移动它也会继续打印速度。
我需要帮助尝试找出一种有效的方法来停止线程而不使用Thread类的stop()
方法。
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class Ball
{
float x, y, lastX, lastY;
int width, height;
float xVelocity, yVelocity;
float speed;
public Ball()
{
width = (int) (Math.random() * 50 + 10);
height = (int) (Math.random() * 50 + 10);
x = (float) (Math.random() * (Marble.gamePanel.getWidth() - width) + width/2);
y = (float) (Math.random() * (Marble.gamePanel.getHeight() - height) + height/2);
lastX = x;
lastY = y;
xVelocity = (float) Math.random() * speed*2 - speed;
yVelocity = (float) Math.random() * speed*2 - speed;
}
public void update()
{
lastX = x;
lastY = y;
x += xVelocity;
y += yVelocity;
if(x + width/2 >= Marble.gamePanel.getWidth())
{
xVelocity *= -0.75;
x = Marble.gamePanel.getWidth() - width/2;
}
else if (x - width/2 <= 0)
{
xVelocity *= -0.75;
x = width/2;
}
if (y + height/2 >= Marble.gamePanel.getHeight())
{
yVelocity *= -0.75;
y = Marble.gamePanel.getHeight() - height/2;
}
else if (y - height/2 <= 0)
{
yVelocity *= -0.75;
y = height/2;
}
}
}
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.List;
import java.util.ArrayList;
/**
* Write a description of class Marble here.
*
* @author (Ryan Lawes)
* @version (5-23-14)
*/
public class Marble extends JFrame implements MouseListener, MouseMotionListener
{
public static GamePanel gamePanel = new GamePanel();
private boolean running = false;
private int fps = 60;
private int frameCount = 0;
private int mouseXC;//X coordinate of where the mouse was clicked
private int mouseYC;//Y coordinate of where the mouse was clicked
private int mouseXR;//X coordinatte of where the mouse was released
private int mouseYR;//Y coordinatte of where the mouse was released
public Marble()
{
super("Fixed Timestep Game Loop Test");
Container cp = getContentPane();
cp.setLayout(new BorderLayout());
JPanel p = new JPanel();
p.setLayout(new GridLayout(1,2));
cp.add(gamePanel, BorderLayout.CENTER);
cp.add(p, BorderLayout.SOUTH);
setSize(500, 500);
addMouseListener(this);
addMouseMotionListener(this);
}
public static void main(String[]args)
{
Marble mrb = new Marble();
mrb.setVisible(true);
}
//Starts a new thread and runs the game loop in it.
public void runGameLoop()
{
Thread loop = new Thread()
{
public void run()
{
gameLoop();
}
};
loop.start();
}
//Only run this in another Thread!
private void gameLoop()
{
//This value would probably be stored elsewhere.
final double GAME_HERTZ = 30.0;
//Calculate how many ns each frame should take for our target game hertz.
final double TIME_BETWEEN_UPDATES = 1000000000 / GAME_HERTZ;
//At the very most we will update the game this many times before a new render.
//If you're worried about visual hitches more than perfect timing, set this to 1.
final int MAX_UPDATES_BEFORE_RENDER = 5;
//We will need the last update time.
double lastUpdateTime = System.nanoTime();
//Store the last time we rendered.
double lastRenderTime = System.nanoTime();
//If we are able to get as high as this FPS, don't render again.
final double TARGET_FPS = 60;
final double TARGET_TIME_BETWEEN_RENDERS = 1000000000 / TARGET_FPS;
//Simple way of finding FPS.
int lastSecondTime = (int) (lastUpdateTime / 1000000000);
while(running)
{
double now = System.nanoTime();
int updateCount = 0;
//Do as many game updates as we need to, potentially playing catchup.
while(now - lastUpdateTime > TIME_BETWEEN_UPDATES && updateCount < MAX_UPDATES_BEFORE_RENDER)
{
gamePanel.update();
lastUpdateTime += TIME_BETWEEN_UPDATES;
updateCount++;
}
//If for some reason an update takes forever, we don't want to do an insane number of catchups.
//If you were doing some sort of game that needed to keep EXACT time, you would get rid of this.
if(now - lastUpdateTime > TIME_BETWEEN_UPDATES)
{
lastUpdateTime = now - TIME_BETWEEN_UPDATES;
}
//Render. To do so, we need to calculate interpolation for a smooth render.
float interpolation = Math.min(1.0f, (float) ((now - lastUpdateTime) / TIME_BETWEEN_UPDATES));
drawGame(interpolation);
lastRenderTime = now;
//Update the frames we got.
int thisSecond = (int) (lastUpdateTime / 1000000000);
}
//////if(gamePanel.ballXVel == 0 && gamePanel.ballYVel == 0)
//////{
////// running = !running;
//////}
}
private void drawGame(float interpolation)
{
gamePanel.setInterpolation(interpolation);
gamePanel.repaint();
}
public void mouseClicked(MouseEvent e)
{
}
public void mousePressed(MouseEvent e)
{
/**
* I want to make it so you have to wait until the marble is done rolling before you can click again
*/
mouseXC = (int) e.getPoint().getX();
mouseYC = (int) e.getPoint().getY();
}
public void mouseReleased(MouseEvent e)
{
mouseXR = (int) e.getPoint().getX();
mouseYR = (int) e.getPoint().getY();
gamePanel.ballXVel = (mouseXC - mouseXR)/2;
gamePanel.ballYVel = (mouseYC - mouseYR)/2;
//////////while(gamePanel.ballXVel != 0 && gamePanel.ballYVel != 0)
//////////{
running = !running;
runGameLoop();
////////}
}
public void mouseEntered(MouseEvent e)
{
}
public void mouseExited(MouseEvent e)
{
}
public void mouseDragged(MouseEvent e)
{
}
public void mouseMoved(MouseEvent e)
{
}
}
import javax.swing.*;
import javax.swing.event.*;
import java.awt.*;
import java.awt.event.*;
public class GamePanel extends JPanel
{
float interpolation;
float ballX, ballY, lastBallX, lastBallY;
int ballWidth, ballHeight;
float ballXVel, ballYVel;
int lastDrawX, lastDrawY;
int ballSpeed = 10;
public GamePanel()
{
ballX = lastBallX = 100;
ballY = lastBallY = 100;
ballWidth = 25;
ballHeight = 25;
}
public void setInterpolation(float interp)
{
interpolation = interp;
}
public void update()
{
lastBallX = ballX;
lastBallY = ballY;
ballX += ballXVel;
ballY += ballYVel;
//Slowly decreases the ball's velocity
ballXVel *= 0.975;
ballYVel *= 0.975;
//Prints out the velocity
//////////if(ballXVel > 0.3 && ballYVel > 0.3)
//////////{
System.out.println(ballXVel);
System.out.println(ballYVel);
//////////}
//If the ball is at a slow enough velocity, it will stop moving alltogether
if(ballXVel > 0 && ballYVel > 0)//if x and y velocity are positive
{
if(ballXVel < 0.3 && ballYVel < 0.3)
{
ballXVel = 0;
ballYVel = 0;
}
}
if(ballXVel < 0 && ballYVel < 0)//if x and y velocity are negative
{
ballXVel *=-1;//Changes to a positive number so it is easier to check
ballYVel *=-1;//Changes to a positive number so it is easier to check
if(ballXVel < 0.3 && ballYVel < 0.3)
{
ballXVel = 0;
ballYVel = 0;
}
ballXVel *=-1;//Changes the velocity back if it doesn't get set to 0. Even if it does, 0*-1 is still 0
ballYVel *=-1;//Changes the velocity back if it doesn't get set to 0. Even if it does, 0*-1 is still 0
}
if(ballXVel < 0 && ballYVel > 0)//if x velocity is negative and y velocity is positive
{
ballXVel *=-1;//Changes to a positive number so it is easier to check
if(ballXVel < 0.3 && ballYVel < 0.3)
{
ballXVel = 0;
ballYVel = 0;
}
ballXVel *=-1;//Changes the velocity back if it doesn't get set to 0. Even if it does, 0*-1 is still 0
}
if(ballXVel > 0 && ballYVel < 0)//if x velocity is positive and y velocity is negative
{
ballYVel *=-1;//Changes to a positive number so it is easier to check
if(ballXVel < 0.3 && ballYVel < 0.3)
{
ballXVel = 0;
ballYVel = 0;
}
ballYVel *=-1;//Changes the velocity back if it doesn't get set to 0. Even if it does, 0*-1 is still 0
}
if(ballX + ballWidth/2 >= getWidth())
{
ballXVel *= -0.8;
ballX = getWidth() - ballWidth/2;
}
else if(ballX - ballWidth/2 <= 0)
{
ballXVel *= -0.8;
ballX = ballWidth/2;
}
if(ballY + ballHeight/2 >= getHeight())
{
ballYVel *= -0.8;
ballY = getHeight() - ballHeight/2;
}
else if(ballY - ballHeight/2 <= 0)
{
ballYVel *= -0.8;
ballY = ballHeight/2;
}
}
public void paintComponent(Graphics g)
{
//BS way of clearing out the old rectangle to save CPU.
g.setColor(getBackground());
g.fillRect(lastDrawX-1, lastDrawY-1, ballWidth+2, ballHeight+2);
g.setColor(Color.RED);
int drawX = (int) ((ballX - lastBallX) * interpolation + lastBallX - ballWidth/2);
int drawY = (int) ((ballY - lastBallY) * interpolation + lastBallY - ballHeight/2);
g.fillOval(drawX, drawY, ballWidth, ballHeight);
lastDrawX = drawX;
lastDrawY = drawY;
g.setColor(Color.BLACK);
}
}
答案 0 :(得分:1)
您评论过的代码:
//////if(gamePanel.ballXVel == 0 && gamePanel.ballYVel == 0)
//////{
////// running = !running;
//////}
将它放在while(running)
循环中,如:
float EPSILON = 0.00000001f;
if(Math.abs(gamePanel.ballXVel - 0.0f) < EPSILON && Math.abs(gamePanel.ballYVel - 0.0f) < EPSILON)
{
running = false;
}
你把它放在了while循环之外。解释器永远不会到达代码,因为running=true;
编辑:
我自己测试了解决方案,但它确实有效。见:
答案 1 :(得分:0)
我建议您更改gamePanel.update()
方法以返回boolean
值,以指示奇迹是否仍在移动。
然后,您可以使用该方法的结果在奇迹停止后突破循环。
在GamePanel#update()
之类的东西。
final float epsilon = 0.00001f;
return (Math.abs(ballXVel) < epsilon) && (Math.abs(ballXVel) < epsilon);
在Marble#gameLoop
之类的东西:
running = !gamePanel.update();