我正在Android工作室制作2D游戏,现在我已经在问题上待了几天。我想停止我的线程Gravity,这样我的玩家就可以跳。当玩家完成跳跃时,重力线程可以继续。
我在互联网上搜索了如何将wait()和notify()与同步块一起使用。但是当我尝试应用它时,我的重力不会停止。如果有人能告诉我如何以正确的方式使用它,我会非常高兴...
这是我在我的场景类中开始跳跃的代码。
public void recieveTouch(MotionEvent event) {
switch(event.getAction()){
case MotionEvent.ACTION_DOWN:
if(player.getPoint().y > 0) {
playerJump();
}
}
}
public void playerJump(){
playerJump = new Jump(player, this);
thread = new Thread(playerJump);
thread.setDaemon(true);
thread.start();
}
这是我的重力线程。
public class Gravity implements Runnable {
private Player player;
private GameScene gameScene;
public Gravity (Player player, GameScene gameScene){
this.player = player;
this.gameScene = gameScene;
}
@Override
public void run(){
while(true){
player.playerMoveDown(3);
gameScene.update();
try {
Thread.sleep(25);
}
catch (InterruptedException e){
e.printStackTrace();
}
}
}
这是我的跳线。
public class Jump implements Runnable {
private Player player;
private GameScene gameScene;
public Jump (Player player, GameScene gameScene){
this.player = player;
this.gameScene = gameScene;
}
@Override
public void run(){
int eindHoogte = player.getPoint().y - 60;
while (player.getPoint().y > eindHoogte) {
player.playerMoveUp(3);
gameScene.update();
try {
Thread.sleep(25);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
答案 0 :(得分:1)
假设您将同一个玩家对象传递给Jump和Gravity类,您可以在播放器上进行同步并保持跳转完成操作的标志。
这将确保在玩家执行跳跃操作时重力将等待跳跃操作,并且只有在玩家跳跃时才会再次继续
标志仅用于防止当另一个线程没有调用wait()时错过通过一个线程调用notify()方法发送的通知的情况
请参阅下面的示例代码
public class Jump implements Runnable {
private Player player;
private GameScene gameScene;
public Jump (Player player, GameScene gameScene){
this.player = player;
this.gameScene = gameScene;
}
@Override
public void run(){
int eindHoogte = player.getPoint().y - 60;
while (player.getPoint().y > eindHoogte) {
player.playerMoveUp(3);
gameScene.update();
try {
Thread.sleep(25);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
synchronized(player){
// acts as a signal to gravity thread to start processing the gravity operation
player.setJumpComplete(true);
}
}
}
public class Gravity implements Runnable {
private Player player;
private GameScene gameScene;
public Gravity (Player player, GameScene gameScene){
this.player = player;
this.gameScene = gameScene;
}
@Override
public void run(){
while(true){
synchronized (player) {
// if player has completed the jump then process the gravity operation else just wait for jump to complete
if(player.isJumpComplete()){
player.playerMoveDown(3);
gameScene.update();
// reset the jump flag and wait for the next jump operation to complete
player.setJumpComplete(false);
}
}
try {
Thread.sleep(25);
}
catch (InterruptedException e){
e.printStackTrace();
}
}
}
答案 1 :(得分:0)
让我给你一个通用答案,这不仅对这种情况有帮助,而且对于将来这可以帮助gou作为迷你指南。使用Java语言时,多线程的非常基本元素是
同步块
一个对象,lock
(为了方便起见,我们可以这样命名),你可以在其上应用synchronized块来获取监视器。
wait()
对象方法,lock
notify()
或notifyAll()
对象方法,lock
Thread
个对象,可能需要实现Runnable
intetface的类。
需要注意的事项如下。
您应该只对当前线程获取监视器的对象调用wait(),notify()或notifyAll()。
1.2 sleep()如果已获取锁定则不放弃锁定,而wait()放弃锁定。在锁定之后调用睡眠并不是强制性的,等待它是强制性的。
1.3 也更喜欢notifyAll()而不是notify(),因为notify可能只发出任何单个线程要唤醒并尝试获取锁定,而notifyAll()唤醒所有符合条件的waitng线程并允许获得锁定的竞争,因此通知有更好的机会获得所有线程的平等机会。
通常,线程执行一次进程并调用notifyAll()并等待(),直到再次通知为止。同样,如果它被中断,通常的方法是终止线程。在执行wait方法时,Thread会放弃监视器,因为它在调用notifyAll
方法之前调用了lock
对象上的wait
方法,因此所有其他有资格获取锁定监视器的线程都被唤醒。线程调度程序将监视器分配给其中一个线程,它同时执行一个命令,在锁定时调用notifyAll,然后调用wait on lock。现在第二个线程也进入等待状态以重新启动监视器,其他一些线程同时获取监视器,整个过程继续,直到我们不中断所有线程。
这样一个模型的例子你可以参考我为另一个问题写的答案
https://stackoverflow.com/a/42049397/504133
请确保在使用android时,不要从主GUI线程以外的任何其他线程修改主GUI,如果您希望这样做,请使用处理程序
答案 2 :(得分:0)
关于通知/等待的主题,上面的答案是合适的,所以我不会在这里添加任何内容,但我认为你可以用另一种方式解决你的问题,通过更像现实生活来建模。 重力是作用于玩家的外力,而重力线程修改玩家位置确实有意义,但跳跃并不是真的相同。跳跃是玩家自己做的事情,因此它是玩家对象的属性。
我会将设计重新设计为: - 为玩家提供一个动作属性,它是一个效果对象列表,一个是重力效果,一个是跳跃效果,一个是步行效果,每个都提供一些运动偏移,同时处于活动状态。 - 将Gravity线程转换为Motion线程,该线程从每个玩家效果中检索移动偏移,将其加起来然后移动玩家总数 - 跳转事件只需打开或关闭跳跃效果 - 除非玩家获得反重力套装或其他东西,否则不要使用重力效果
因为我在手机上输入了这个伪代码,所以
interface Effect {
method Point getMotion(duration);
method Boolean isCompleted();
}
class Jump implements Effect {
///...
}
class sceneObject {
synchronized List<Effect> movementEffects;
Point position;
void move(Point);
void addEffect(Effect);
void removeEfects(Class);
void Point getTotalMotion(duration) {
Point result;
for each effect in movementEffects {
result += effect. getMotion(this, duration);
if effect.isCompleted() {
removeEffect(effect)
}
}
return result;
}
void applyMotion(duration) {
move(getTotalMotion(duration))
}
}
class player extends SceneObject {
Effect gravity = new Gravity(3);
Player () {
addEffect(gravity);
}
void jump() {
addEffect(new Jump)
}
void walkLeft() {
stopWalking();
addEffect(new Walk(-3))
}
void stopWalking() {
removeEffects(Walk.class)
}
}
class EffectsThread {
void run() {
While (...) {
timeSinceLastIteration = ... ;
for each item in scene {
item.applyMotion(timeSinceLastIteration);
}
//sleep
}
}
}
然后你也只需要一个效果线程来运行,你永远不需要启动和停止它