我是Java的新手,我在Android Studio上制作了俄罗斯方块游戏。我试图做一个"暂停/开始"按钮,它不起作用。当我按下按钮PAUSE时,音乐和游戏停止(它按预期工作)。但是当我再次按下“开始”时,音乐会继续,但游戏不会恢复。
我做了一个功能"暂停" sleep()
内有while
,函数"重启"使用一个变为false的布尔值(这设置了while的条件)
这是我的代码:
private void pause() {
ps=true;
while(ps) {
try {
sleep(4000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private void restart() {
ps=false;
}
以下是我MainActivity
的一部分:
public void pauseButton (View view) {
if (ps == false) {
ps=true;
GameState.getInstance().setUserAction(UserAction.PAUSE);
mediaPlayer.pause();
} else {
ps=false;
GameState.getInstance().setUserAction(UserAction.START);
mediaPlayer.start();
}
}
这就是" Useraction.Pause / Start"正在做
case PAUSE:
pause();
break;
case START:
restart();
break;
如何让重启功能起作用?我需要制作"而#34;停止或者可能在此功能中停止睡眠,我不能...感谢您的帮助!
public class GameThread extends Thread{
private Shape shape;
private Set<Block> remainingBlockSet = new HashSet<>();
private boolean isRunning = true;
private long time;
private char[] shapeTypes={'O', 'I', 'J', 'L', 'Z', 'S','T'};
private boolean ps = true;
GameThread(){
//La première pièce du jeu apparait
spawnNewShape();
//Initialisation du temps
this.time = System.currentTimeMillis();
}
//----------------------------------------------------------------------------------------------
// METHODES DE GESTION DE LA THREAD
//----------------------------------------------------------------------------------------------
/**
*Boucle événementielle
*/
@Override
public void run() {
while (isRunning) {
//On bouge la pièce en fonction des demande utilisateur (bouton préssé)
processUserAction();
//La pièce tombe
processMoveDown();
//On enlève les lignes remplie
removeCompletedRows();
//On effectue le rendu graphique
RenderManager.getInstance().render(shape, remainingBlockSet);
}
}
/**
* Arret de la boucle événementielle
*/
void stopRunning(){
isRunning = false;
}
//----------------------------------------------------------------------------------------------
// METHODES DE GESTION DU JEU
//----------------------------------------------------------------------------------------------
/**
* Traitement des actions utilisateur
*/
private void processUserAction() {
//On recupère la dernière action
UserAction action = GameState.getInstance().getUserAction();
switch (action) {
case LEFT:
moveLeft();
break;
case RIGHT:
moveRight();
break;
case ROTATE:
rotate();
break;
case FALL:
fall();
break;
case PAUSE:
pause();
break;
case RESUME:
restart();
break;
}
//On définit la dernière action à nulle
GameState.getInstance().setUserAction(UserAction.NONE);
}
// met en pause le jeu
public void pause() {
ps = true;
while(ps) {
try {
sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
// permet de relancer le jeu
public void restart() {
ps=false;
}
private void fall(){
while(shape.canMoveDown(remainingBlockSet)){
shape.moveDown();
}
}
private void rotate(){
shape.rotate(remainingBlockSet);
}
/**
* Décale la pièce d'une case vers la gauche
*/
private void moveLeft(){
shape.moveLeft(remainingBlockSet);
}
/**
* Décale la pièce d'une case vers la droite
*/
private void moveRight(){
shape.moveRight(remainingBlockSet);
}
/**
* Décale la pièce d'une case vers le bas
*/
private void processMoveDown(){
//Si le laps de temps n'est pas écoulé on ne fait rien
long now = System.currentTimeMillis();
if(now-time < GameConstants.TIME_LAPS){
return;
}
//Sinon la pièce descend
if(shape.canMoveDown(remainingBlockSet)){
shape.moveDown();
}
else{
processShapeCollision();
}
//On redéfinit le temps comme le temps actuel
time = System.currentTimeMillis();
}
private void processShapeCollision(){
remainingBlockSet.addAll(shape.getBlockList());
spawnNewShape();
}
/**
* A partir d'un caractère choisis aléatoirement, cette methode
permet
de générer la pièce qui
* lui est associé.
*/
private void spawnNewShape(){
int x = (GameConstants.COLUMNS/2)-2;
int y = 0;
char shapeType = chooseRandomShape();
switch (shapeType){
case 'O':
this.shape = new OShape(x,y);
break;
case 'T':
this.shape = new TShape(x,y);
break;
case 'S':
this.shape = new SShape(x,y);
break;
case 'I':
this.shape = new IShape(x,y);
break;
case 'L':
this.shape = new LShape(x,y);
break;
case 'Z':
this.shape = new ZShape(x,y);
break;
case 'J':
this.shape = new JShape(x,y);
break;
default:
//imposible
break;
}
}
/**
* Cette methode génère aléatoirement un entier entre 0 et 7. Ce dernier permet ensuite de
* séléctioner le caractère de la pièce à faire appraitre.
* @return un caractère correspondant à la prochaine pièce à faire apparaitre.
*/
private char chooseRandomShape(){
int x = (int) (Math.random() * shapeTypes.length);
return shapeTypes[x];
}
private void removeCompletedRows() {
for(int y = GameConstants.ROWS-1; y>0; y--){
List<Block> line = getBlockLine(y);
if (isLineCompleted(line)){
//Log.i(TAG,"la ligne"+y+"est pleine :"+line);
removeLine(line);
moveDownAboveBlocks(y);
}
}
}
private List<Block> getBlockLine(int y) {
List<Block> line = new ArrayList<>();
for(Block block : remainingBlockSet){
if(y == block.getY()){
line.add(block);
}
}
return line;
}
private boolean isLineCompleted(List<Block> line) {
for(int x = 0; x< GameConstants.COLUMNS; x++){
boolean found = false;
for(Block block : line){
if (block.getX() == x){
found = true;
break;
}
}
if(!found) {
return false;
}
}
return true;
}
private void removeLine(List<Block> line){
remainingBlockSet.removeAll(line);
}
private void moveDownAboveBlocks(int y){
for(Block block : remainingBlockSet){
if (block.getY()<y){
block.moveDown();
}
}
}
}
答案 0 :(得分:1)
你没有明确说过,但我认为UI在不同的线程中工作,所以你可以按暂停/重启按钮而不被正在运行的'while'循环阻止
您的代码未显示您如何定义ps
变量 - 它是否不稳定?
我们可以看到这些代码是不同步的,因此不会放置任何内存障碍,在这种情况下(当ps不易变时)这个变量可能被运行while循环的线程“缓存”并且再也不会从内存重新读取
请确保它是易失性的 - 或者是AtomicBoolean,或者进行一些同步(除非暂停/启动中的所有操作都是幂等的,否则无论如何都不错)
请参阅此处了解更多详情: https://www.concretepage.com/java/thread-communication-using-volatile-in-java https://jorosjavajams.wordpress.com/volatile-vs-synchronized/
答案 1 :(得分:0)
你的问题可能是你“消耗”你暂停的线程几乎可以肯定是GUI线程(是的我说“gui”线程,因为只有一个,只要你拥有它,没有别的可以发生在GUI上)。永远不会推送第二个按钮,因为第一个按钮仍在使用线程。
每当您从系统收到任何通知时,只需采取非常快速的操作并立即将线程返回系统。 (例外情况是传递给“main”的线程,你可以永久保存)
除非你在gui线程上做整个游戏,否则循环也不会做任何事情来暂停你的游戏。换句话说,如果游戏在你的主线程上,锁定gui线程将不会阻止它。当他们按下暂停按钮时,没有按钮调用pause(),而是设置ps = true并返回。让你的游戏循环(实际运行游戏的线程)在每次迭代时检查ps标志,并且只要ps为真就阻塞(你正在做它的方式很好,它只需要在其他代码中)。
ps也应该绝对不稳定,但这绝不是问题......