一个视图如何对SurfaceView的方法调用做出反应?

huangapple go评论121阅读模式
英文:

How can a View react to a Method call of a SurfaceView?

问题

Sure, here's the translation of the provided content:

package Activities;

import android.os.Bundle;
import android.view.SurfaceView;
import android.widget.TextView;

import androidx.appcompat.app.AppCompatActivity;

import com.example.pacman.DBManager;
import Game.GameView;
import com.example.pacman.R;
import com.example.pacman.Score;

public class PlayActivity extends AppCompatActivity {
    private TextView playerNickname;
    TextView score;
    private TextView maxScore;
    private SurfaceView gameSurfaceView;
    private GameView gameView;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // Modified code
        setContentView(R.layout.activity_game);
        // We get text view that we will use
        playerNickname = (TextView) this.findViewById(R.id.tv_player);
        score = (TextView) this.findViewById(R.id.tv_current_score);
        maxScore = (TextView) this.findViewById(R.id.tv_current_max_score);
        gameSurfaceView = (GameView) this.findViewById(R.id.game_view);

        // Set text view initial values
        playerNickname.setText(getIntent().getExtras().getString("playerNickname"));
        score.setText("0");

        maxScore.setText("To modify");

        this.gameView = new GameView(gameSurfaceView.getContext());
        this.gameSurfaceView.getHolder().addCallback(this.gameView);
    }

    protected void onResume() {
        super.onResume();
        this.gameView.resume();
    }

    protected void onPause() {
        super.onPause();
        this.gameView.pause();
    }

    public void updateScore(int score) {
        this.score.setText("" + score);
    }

    public void onLose(double score) {
        // We try to save the score, if there is a previous register we write only if this score
        // is better than the one before
        DBManager manager;
        long raw;
        Score scoreToSave;
        manager = new DBManager(this);

        scoreToSave = new Score(this.playerNickname.toString(), score);
        if (manager.saveScore(scoreToSave) == -1) {
            // if I couldn't save the score
            if (manager.updateScore(scoreToSave) != -1) {
                // if my new score is better than the one previous
            } else {
                // if my new score is worse or equal than the one previous
            }
        }
    }
}
package Game;

import android.content.Context;
import android.graphics.Canvas;
import android.os.Build;
import android.util.AttributeSet;
import android.util.Log;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

import androidx.annotation.RequiresApi;

import Activities.PlayActivity;
import Game.Character_package.Ghost;
import Game.Character_package.Pacman;

public class GameView extends SurfaceView implements Runnable, SurfaceHolder.Callback, GestureDetector.OnGestureListener {
    // ... (rest of the code)
}
package Game;

import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.os.Build;
import android.util.Log;

import androidx.annotation.RequiresApi;

import com.example.pacman.R;

import org.jetbrains.annotations.NotNull;

import Game.Behavior.ChaseBehavior.*;
import Game.Character_package.Ghost;
import Game.Character_package.Pacman;
import Game.GameCountDown.*;

public class GameManager {
    // ... (rest of the code)
}

Please note that I've only included the code segments that you provided, without any additional content. If you have any specific questions or need further assistance, feel free to ask.

英文:

RESUME<br>
I'm programming a pacman, it is almost done but I'm having problems with the communication between the view which will show the score and the currect direction of the pacman, and the surface view which will draw the game.

The PlayActivity (which is an AppCompatActivity) has a GameView(which is a SurfaceView where the game is draw) and knows the GameManager(a class I've made that basically knows the pacman, the map, the ghosts, and everything). The PlayActivity also has a text view called scoreTv. I don't know how to update this text view.

The idea is that the scoreTv change its text value whenever the GameManager's methods addScore(int),eatPallet(int, int), eatBonus(int,int); eatSuperPallet(int,int) are invoked.

Here is the PlayActivity code

package Activities;
import android.os.Bundle;
import android.view.SurfaceView;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
import com.example.pacman.DBManager;
import Game.GameView;
import com.example.pacman.R;
import com.example.pacman.Score;
public class PlayActivity extends AppCompatActivity {
private TextView playerNickname;
TextView score;
private TextView maxScore;
private SurfaceView gameSurfaceView;
private GameView gameView;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//Modified code
setContentView(R.layout.activity_game);
//we get text view that we will use
playerNickname=(TextView) this.findViewById(R.id.tv_player);
score=(TextView) this.findViewById(R.id.tv_current_score);
maxScore=(TextView) this.findViewById(R.id.tv_current_max_score);
gameSurfaceView= (GameView) this.findViewById(R.id.game_view);
//set text view initial values
playerNickname.setText(getIntent().getExtras().getString(&quot;playerNickname&quot;));
score.setText(&quot;0&quot;);
maxScore.setText(&quot;To modify&quot;);
this.gameView=new GameView(gameSurfaceView.getContext());
this.gameSurfaceView.getHolder().addCallback(this.gameView);
}
protected void onResume(){
super.onResume();
this.gameView.resume();
}
protected void onPause(){
super.onPause();
this.gameView.pause();
}
public void updateScore(int score){
this.score.setText(&quot;&quot;+score);
}
public void onLose(double score){
//We try to save the score, if there is a previous register we write only if this score
//is better that the one before
DBManager manager;
long raw;
Score scoreToSave;
manager=new DBManager(this);
scoreToSave=new Score(this.playerNickname.toString(), score);
if(manager.saveScore(scoreToSave)==-1){
//if i couldn&#39;t save the score
if(manager.updateScore(scoreToSave)!=-1){
//if my new score is better than the one previous
}else{
//if my new score is worse or equal than the one previous
}
}
}
}

And here is the Game View code

package Game;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.os.Build;
import android.util.AttributeSet;
import android.util.Log;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.widget.TextView;
import androidx.annotation.RequiresApi;
import Activities.PlayActivity;
import Game.Character_package.Ghost;
import Game.Character_package.Pacman;
public class GameView extends SurfaceView implements Runnable, SurfaceHolder.Callback, GestureDetector.OnGestureListener {
private static final float SWIPE_THRESHOLD = 2;
private static final float SWIPE_VELOCITY = 2;
private boolean GHOST_INICIALIZED=false;
private GestureDetector gestureDetector;
private GameManager gameManager;
private Thread thread; //game thread
private SurfaceHolder holder;
private boolean canDraw = false;
private int blockSize;                // Ancho de la pantalla, ancho del bloque
private static int movementFluencyLevel=8; //this movement should be a multiple of the blocksize and multiple of 4, if note the pacman will pass walls
private int totalFrame = 4;             // Cantidad total de animation frames por direccion
private int currentArrowFrame = 0;      // animation frame de arrow actual
private long frameTicker;               // tiempo desde que el ultimo frame fue dibujado
//----------------------------------------------------------------------------------------------
//Constructors
public GameView(Context context) {
super(context);
this.constructorHelper(context);
}
public GameView(Context context, AttributeSet attrs) {
super(context, attrs);
this.constructorHelper(context);
}
public GameView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
this.constructorHelper(context);
}
private void constructorHelper(Context context) {
this.gestureDetector = new GestureDetector(this);
this.setFocusable(true);
this.holder = getHolder();
this.holder.addCallback(this);
this.frameTicker = (long) (1000.0f / totalFrame);
this.gameManager=new GameManager(this);
int screenWidth=getResources().getDisplayMetrics().widthPixels;
this.blockSize = ((((screenWidth/this.gameManager.getGameMap().getMapWidth())/movementFluencyLevel)*movementFluencyLevel)/4)*4;
this.holder.setFixedSize(blockSize*this.gameManager.getGameMap().getMapWidth(),blockSize*this.gameManager.getGameMap().getMapHeight());
this.gameManager.getGameMap().loadBonusBitmaps(this);
this.gameManager.setPacman(new Pacman(&quot;pacman&quot;,&quot;&quot;,this,this.movementFluencyLevel));
Ghost.loadCommonBitmaps(this);
}
//----------------------------------------------------------------------------------------------
//Getters and setters
public int getBlockSize() {
return blockSize;
}
public GameManager getGameManager() {
return gameManager;
}
public int getMovementFluencyLevel(){return movementFluencyLevel;}
//----------------------------------------------------------------------------------------------
private synchronized void initGhost(){
if(!GHOST_INICIALIZED){
GHOST_INICIALIZED=true;
this.gameManager.initGhosts(this);
}
}
@RequiresApi(api = Build.VERSION_CODES.N)
@Override
public void run() {
long gameTime;
Canvas canvas;
while (!holder.getSurface().isValid()) {
}
this.initGhost();
this.setFocusable(true);
while (canDraw) {
gameTime=System.currentTimeMillis();
if(gameTime &gt; frameTicker + (totalFrame * 15)){
canvas = holder.lockCanvas();
if(canvas!=null){
if(this.updateFrame(gameTime,canvas)){
try {
Thread.sleep(3000);
}catch (Exception e){}
}
holder.unlockCanvasAndPost(canvas);
if(this.gameManager.checkWinLevel()){
canDraw=false;
this.gameManager.cancelThreads();
try {
Thread.sleep(2000);
} catch (InterruptedException e) {}
//animation
Log.i(&quot;Game&quot;,&quot;You win&quot;);
}else if(!this.gameManager.getPacman().hasLifes()){
//we lost
canDraw=false;
this.gameManager.cancelThreads();
//animation
Log.i(&quot;Game&quot;,&quot;You lose&quot;);
}
}
}
}
}
// Method to capture touchEvents
@Override
public boolean onTouchEvent(MotionEvent event) {
//To swipe
//https://www.youtube.com/watch?v=32rSs4tE-mc
this.gestureDetector.onTouchEvent(event);
super.onTouchEvent(event);
return true;
}
//Chequea si se deberia actualizar el frame actual basado en el
// tiempo que a transcurrido asi la animacion
//no se ve muy rapida y mala
@RequiresApi(api = Build.VERSION_CODES.N)
private boolean updateFrame(long gameTime, Canvas canvas) {
Pacman pacman;
Ghost[] ghosts;
boolean pacmanIsDeath;
pacman=this.gameManager.getPacman();
ghosts=this.gameManager.getGhosts();
// Si el tiempo suficiente a transcurrido, pasar al siguiente frame
frameTicker = gameTime;
canvas.drawColor(Color.BLACK);
this.gameManager.getGameMap().draw(canvas, Color.BLUE,this.blockSize,this.gameManager.getLevel());
this.gameManager.moveGhosts(canvas,this.blockSize);
pacmanIsDeath=pacman.move(this.gameManager,canvas);
if(!pacmanIsDeath){
// incrementar el frame
pacman.changeFrame();
for(int i=0; i&lt;ghosts.length;i++){
ghosts[i].changeFrame();
}
currentArrowFrame++;
currentArrowFrame%=7;
}else{
pacman.setNextDirection(&#39; &#39;);
for(int i=0; i&lt;ghosts.length;i++){
ghosts[i].respawn();
}
}
return pacmanIsDeath;
}
//----------------------------------------------------------------------------------------------
//Callback methods
@RequiresApi(api = Build.VERSION_CODES.N)
@Override
public void surfaceCreated(SurfaceHolder holder) {
canDraw = true;
this.thread= new Thread(this);
this.thread.start();
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
//----------------------------------------------------------------------------------------------
public void resume() {
this.canDraw = true;
thread = new Thread(this);
thread.start();
}
public void pause() {
this.canDraw = false;
while (true) {
try {
thread.join();
return;
} catch (InterruptedException e) {
// retry
}
break;
}
this.thread=null;
}
@Override
public boolean onDown(MotionEvent e) {
return false;
}
@Override
public void onShowPress(MotionEvent e) {
}
@Override
public boolean onSingleTapUp(MotionEvent e) {
return false;
}
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
return false;
}
@Override
public void onLongPress(MotionEvent e) {
}
@Override
public boolean onFling(MotionEvent downEvent, MotionEvent moveEvent, float velocityX, float velocityY) {
//To swipe
//https://www.youtube.com/watch?v=32rSs4tE-mc
float diffX, diffY;
Pacman pacman;
Log.i(&quot;Fling&quot;, &quot;detected&quot;);
diffX = moveEvent.getX() - downEvent.getX();
diffY = moveEvent.getY() - downEvent.getY();
pacman=this.gameManager.getPacman();
if (Math.abs(diffX) &gt; Math.abs(diffY)) {
//right or left swipe
if (Math.abs(diffX) &gt; SWIPE_THRESHOLD &amp;&amp; Math.abs(velocityX) &gt; SWIPE_VELOCITY) {
if (diffX &gt; 0) {
//right
pacman.setNextDirection(&#39;r&#39;);
} else {
//left
pacman.setNextDirection(&#39;l&#39;);
}
}
} else {
//up or down swipe
if (Math.abs(diffY) &gt; SWIPE_THRESHOLD &amp;&amp; Math.abs(velocityY) &gt; SWIPE_VELOCITY) {
if (diffY &gt; 0) {
//down
pacman.setNextDirection(&#39;d&#39;);
} else {
//up
pacman.setNextDirection(&#39;u&#39;);
}
}
}
return true;
}
}

And finally the GameManager code

package Game;
import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.os.Build;
import android.util.Log;
import android.widget.TextView;
import androidx.annotation.RequiresApi;
import com.example.pacman.R;
import org.jetbrains.annotations.NotNull;
import Game.Behavior.ChaseBehavior.*;
import Game.Character_package.Ghost;
import Game.Character_package.Pacman;
import Game.GameCountDown.*;
public class GameManager {
private static final int TOTAL_LEVELS=256;
private GameMap gameMap;
private int level,bonusResetTime,score;
private CountDownScareGhosts scareCountDown;
private Pacman pacman;
private Ghost[] ghosts;
private boolean fruitHasBeenInTheLevel;
public GameManager(GameView gameView){
this.fruitHasBeenInTheLevel=false;
this.score=0;
this.gameMap=new GameMap();
this.gameMap.loadMap1();
this.level=1;
this.ghosts=new Ghost[4];
this.bonusResetTime = 5000;
this.scareCountDown=null;
}
public void addScore(int s){
this.score+=s;
}
public int getScore() {
return this.score;
}
public int getLevel() {
return this.level;
}
public GameMap getGameMap() {
return this.gameMap;
}
public Ghost[] getGhosts(){
return this.ghosts;
}
public Ghost getGhost(int i) {
return this.ghosts[i];
}
public Pacman getPacman(){
return this.pacman;
}
public void setPacman(Pacman pacman){
this.pacman=pacman;
}
public void eatPallet(int posXMap, int posYMap){
this.score+=10;
//Log.i(&quot;Score&quot;, Double.toString(this.score).substring(0,Double.toString(this.score).indexOf(&#39;.&#39;)));
this.gameMap.getMap()[posYMap][posXMap]=0;
}
public void eatBonus(int posXMap,int posYMap){
this.score+=500;
//Log.i(&quot;Score&quot;, Double.toString(this.score).substring(0,Double.toString(this.score).indexOf(&#39;.&#39;)));
this.gameMap.getMap()[posYMap][posXMap]=0;
}
public void eatSuperPallet(int posXMap,int posYMap){
this.score+=50;
Log.i(&quot;Score&quot;, Double.toString(this.score).substring(0,Double.toString(this.score).indexOf(&#39;.&#39;)));
this.gameMap.getMap()[posYMap][posXMap]=0;
//Si hay un timer andando lo cancelo y ejecuto otro
if (this.scareCountDown != null){
this.scareCountDown.cancel();
}
this.scareCountDown = new CountDownScareGhosts(this.ghosts,this.gameMap.getMap());
this.scareCountDown.start();
}
public void tryCreateBonus(){
//only if pacman has eaten 20 pallets we should allow the fruit appear
if(!this.fruitHasBeenInTheLevel &amp;&amp; this.gameMap.getEatenPallets()&gt;=20){
//to not allow the fruit be again in the level
this.fruitHasBeenInTheLevel=true;
new CountdownBonusThread(this.gameMap,this.bonusResetTime).start();
}
}
@RequiresApi(api = Build.VERSION_CODES.N)
public void moveGhosts(Canvas canvas,int blocksize) {
for (int i = 0; i &lt; ghosts.length; i++) {
ghosts[i].move(this.gameMap.getMap(),this.pacman);
ghosts[i].draw(canvas);
}
}
public synchronized void initGhosts(@NotNull GameView gv) {
int[][]spawnPositions,cornersPositions, notUpDownPositions,defaultTargets;
int movementeFluency;
defaultTargets=this.gameMap.getDefaultGhostTarget();
notUpDownPositions=this.gameMap.getNotUpDownDecisionPositions();
spawnPositions=this.gameMap.getGhostsSpawnPositions();
cornersPositions=this.gameMap.getGhostsScatterTarget();
movementeFluency=gv.getMovementFluencyLevel();
//start position
// 5 blinky spawn [13, 11]
// 6 pinky spawn [15,11]
// 7 inky spawn [13,16]
// 8 clyde spawn [15,16]
this.ghosts=new Ghost[4];
ghosts[0] = new Ghost(&quot;blinky&quot;,gv,spawnPositions[0], cornersPositions[0] ,new BehaviorChaseAgressive(notUpDownPositions,movementeFluency,defaultTargets[0]),movementeFluency,notUpDownPositions,&#39;l&#39;,defaultTargets[0]);
ghosts[1] = new Ghost(&quot;pinky&quot;,gv,spawnPositions[1],cornersPositions[1],new BehaviorChaseAmbush(notUpDownPositions,movementeFluency,defaultTargets[1]),movementeFluency,notUpDownPositions,&#39;r&#39;,defaultTargets[1]);
ghosts[2] = new Ghost(&quot;inky&quot;,gv,spawnPositions[2],cornersPositions[2],new BehaviorChasePatrol(notUpDownPositions,this.ghosts[0],movementeFluency,defaultTargets[0]),movementeFluency,notUpDownPositions,&#39;l&#39;,defaultTargets[0]);
ghosts[3] = new Ghost(&quot;clyde&quot;,gv,spawnPositions[3],cornersPositions[3],new BehaviorChaseRandom(notUpDownPositions,cornersPositions[3],movementeFluency,defaultTargets[1]),movementeFluency,notUpDownPositions,&#39;r&#39;,defaultTargets[1]);
try{
Thread.sleep(200);
}catch(Exception e){}
for (int i=0;i&lt;ghosts.length;i++){
ghosts[i].onLevelStart(1);
}
}
public boolean checkWinLevel() {
//player win the level if he has eaten all the pallet
return this.gameMap.countPallets()==0;
}
public void onResume(){
for (int i=0 ; i&lt;this.ghosts.length;i++){
this.ghosts[i].cancelBehavoirThread();
}
if(this.scareCountDown!=null &amp;&amp; !this.scareCountDown.hasEnded()){
this.scareCountDown.start();
}
}
public void onPause(){
for (int i=0 ; i&lt;this.ghosts.length;i++){
this.ghosts[i].cancelBehavoirThread();
}
if(this.scareCountDown!=null &amp;&amp; !this.scareCountDown.hasEnded()){
this.scareCountDown=this.scareCountDown.onPause();
}
}
public void cancelThreads(){
for (int i=0 ; i&lt;this.ghosts.length;i++){
this.ghosts[i].cancelBehavoirThread();
}
if(this.scareCountDown!=null){
this.scareCountDown.cancel();
}
}
}

What I know so far is that I can't sent the scoreTv to the GameView, because the GameView can't change it due to not being in the same thread. I need the PlayActivity instance react whenever any of the methods I've told you before are called.

答案1

得分: 0

好的,以下是翻译好的部分:

public class PlayActivity extends AppCompatActivity {
    private TextView playerNickname;
    private TextView scoreTv;
    private TextView maxScore;
    private SurfaceView gameSurfaceView;
    private GameView gameView;
    private GameManager gameManager;
    private static Semaphore CHANGE_SCORE_MUTEX=new Semaphore(0,true);
    private static Semaphore CHANGE_DIRECTION_MUTEX=new Semaphore(0,true);
    private Thread changeScoreThread, changeDirectionThread;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        //Modified code
        setContentView(R.layout.activity_game);
        //we get text view that we will use
        playerNickname=(TextView) this.findViewById(R.id.tv_player);
        scoreTv=(TextView) this.findViewById(R.id.tv_current_score);
        maxScore=(TextView) this.findViewById(R.id.tv_current_max_score);
        gameSurfaceView= (GameView) this.findViewById(R.id.game_view);

        //set text view initial values

        playerNickname.setText(getIntent().getExtras().getString("playerNickname"));
        scoreTv.setText("0");

        maxScore.setText("To modify");

        this.gameView=new GameView(gameSurfaceView.getContext());
        this.gameManager=this.gameView.getGameManager();
        this.gameView.setSemaphores(CHANGE_SCORE_MUTEX,CHANGE_DIRECTION_MUTEX);
        this.gameSurfaceView.getHolder().addCallback(this.gameView);
    }    

    protected void onResume(){
        super.onResume();
        this.gameView.resume();
        this.initChangerThreads();
    }

    public void updateScoreTv(int score){
        this.scoreTv.setText(""+score);
    }

    protected void onPause(){
        super.onPause();
        this.gameView.pause();
        //in order to stop the threads
        CHANGE_SCORE_MUTEX.release();
        CHANGE_DIRECTION_MUTEX.release();
    }

    // ... 其他部分的翻译 ...

    private void initChangerThreads() {
        this.changeScoreThread = new Thread(new Runnable() {
            public void run() {
                while (gameView.isDrawing()) {
                    try {
                        CHANGE_SCORE_MUTEX.acquire();
                        runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                updateScoreTv(gameView.getGameManager().getScore());
                            }
                        });
                    }catch (Exception e){}
                 }
            }
        });
        this.changeScoreThread.start();
    }
}
public class GameManager {
    private static final int TOTAL_LEVELS=256;
    private static int SCORE=0;
    private GameMap gameMap;
    private int level,bonusResetTime;
    private CountDownScareGhosts scareCountDown;
    private Pacman pacman;
    private Ghost[] ghosts;
    private boolean fruitHasBeenInTheLevel;
    private static Semaphore CHANGE_SCORE_MUTEX;

    public GameManager(){
        this.fruitHasBeenInTheLevel=false;
        this.gameMap=new GameMap();
        this.gameMap.loadMap1();
        this.level=1;
        this.ghosts=new Ghost[4];
        this.bonusResetTime = 5000;
        this.scareCountDown=null;
    }

    public void setChangeScoreSemaphore(Semaphore changeScoreSemaphore) {
        CHANGE_SCORE_MUTEX = changeScoreSemaphore;
    }

    public void addScore(int s){
        SCORE+=s;
        CHANGE_SCORE_MUTEX.release();
    }

    public int getScore() {
        return SCORE;
    }

    // ... 其他部分的翻译 ...

    public void eatPallet(int posXMap, int posYMap){
        SCORE+=10;
        CHANGE_SCORE_MUTEX.release();
        this.gameMap.getMap()[posYMap][posXMap]=0;
    }

    // ... 其他部分的翻译 ...
}

如果你需要更多的翻译或帮助,请随时提问。

英文:

Well, I have found a solution, I don't like it, tough.
What have I done is the next:

  1. I have created a STATIC SEMAPHORE in the AppCompatActivity
  2. I pass it to the class GameManager as a STATIC SEMAPHORE too and I've changed the score in this class to static
  3. Finally I've run a thread in the PlayActivity with the method runOnUiThread to update the scoreTv, this thread will acquire a permit, this one will be relese whenever the SCORE is update in the GameManager to avoid the active wait

You may be asking why I remark STATIC. If I don't do this, I don't know why the reference of the GameManager get lost. If someone know the answer please post it.
Here a link to the git repo, and here the code of the classes

public class PlayActivity extends AppCompatActivity {
private TextView playerNickname;
private TextView scoreTv;
private TextView maxScore;
private SurfaceView gameSurfaceView;
private GameView gameView;
private GameManager gameManager;
private static Semaphore CHANGE_SCORE_MUTEX=new Semaphore(0,true);
private static Semaphore CHANGE_DIRECTION_MUTEX=new Semaphore(0,true);
private Thread changeScoreThread, changeDirectionThread;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//Modified code
setContentView(R.layout.activity_game);
//we get text view that we will use
playerNickname=(TextView) this.findViewById(R.id.tv_player);
scoreTv=(TextView) this.findViewById(R.id.tv_current_score);
maxScore=(TextView) this.findViewById(R.id.tv_current_max_score);
gameSurfaceView= (GameView) this.findViewById(R.id.game_view);
//set text view initial values
playerNickname.setText(getIntent().getExtras().getString(&quot;playerNickname&quot;));
scoreTv.setText(&quot;0&quot;);
maxScore.setText(&quot;To modify&quot;);
this.gameView=new GameView(gameSurfaceView.getContext());
this.gameManager=this.gameView.getGameManager();
this.gameView.setSemaphores(CHANGE_SCORE_MUTEX,CHANGE_DIRECTION_MUTEX);
this.gameSurfaceView.getHolder().addCallback(this.gameView);
}    
protected void onResume(){
super.onResume();
this.gameView.resume();
this.initChangerThreads();
}
public void updateScoreTv(int score){
this.scoreTv.setText(&quot;&quot;+score);
}
protected void onPause(){
super.onPause();
this.gameView.pause();
//in order to stop the threads
CHANGE_SCORE_MUTEX.release();
CHANGE_DIRECTION_MUTEX.release();
}
public void onLose(double score){
//We try to save the score, if there is a previous register we write only if this score
//is better that the one before
DBManager manager;
long raw;
Score scoreToSave;
manager=new DBManager(this);
scoreToSave=new Score(this.playerNickname.toString(), score);
if(manager.saveScore(scoreToSave)==-1){
//if i couldn&#39;t save the score
if(manager.updateScore(scoreToSave)!=-1){
//if my new score is better than the one previous
}else{
//if my new score is worse or equal than the one previous
}
}
}   
private void initChangerThreads() {
this.changeScoreThread = new Thread(new Runnable() {
public void run() {
while (gameView.isDrawing()) {
//Log.i(&quot;Score &quot;,&quot;&quot;+gameManager.getScore());
try {
CHANGE_SCORE_MUTEX.acquire();
runOnUiThread(new Runnable() {
@Override
public void run() {
updateScoreTv(gameView.getGameManager().getScore());
}
});
}catch (Exception e){}
}
}
});
this.changeScoreThread.start();
}
}

GameView: I've just added this method

public void setSemaphores(Semaphore changeScoreSemaphore, Semaphore changeDirectionSemaphore){
this.gameManager.setChangeScoreSemaphore(changeScoreSemaphore);
this.gameManager.getPacman().setChangeDirectionSemaphore(changeDirectionSemaphore);
Log.i(&quot;Semaphore&quot;, &quot;setted&quot;);
}

GameManager

public class GameManager {
private static final int TOTAL_LEVELS=256;
private static int SCORE=0;
private GameMap gameMap;
private int level,bonusResetTime;//,score;
private CountDownScareGhosts scareCountDown;
private Pacman pacman;
private Ghost[] ghosts;
private boolean fruitHasBeenInTheLevel;
private static Semaphore CHANGE_SCORE_MUTEX;
public GameManager(){
this.fruitHasBeenInTheLevel=false;
//this.score=0;
this.gameMap=new GameMap();
this.gameMap.loadMap1();
this.level=1;
this.ghosts=new Ghost[4];
this.bonusResetTime = 5000;
this.scareCountDown=null;
}
public void setChangeScoreSemaphore(Semaphore changeScoreSemaphore) {
CHANGE_SCORE_MUTEX = changeScoreSemaphore;
//if(this.changeScoreSemaphore==null){
//    Log.i(&quot;Change Score Semaphore&quot;,&quot;I&#39;m null&quot;);
//}else{
//    Log.i(&quot;Change Score Semaphore&quot;,&quot;I&#39;m not null&quot;);
//}
}
public void addScore(int s){
//this.score+=s;
SCORE+=s;
CHANGE_SCORE_MUTEX.release();
/*if(this.changeScoreSemaphore==null){
Log.i(&quot;Change Score Semaphore&quot;,&quot;I&#39;m null&quot;);
}else{
Log.i(&quot;Change Score Semaphore&quot;,&quot;I&#39;m not null&quot;);
}*/
//this.changeScoreSemaphore.release();
}
public int getScore() {
return SCORE;
//return this.score;
}
public int getLevel() {
return this.level;
}
public GameMap getGameMap() {
return this.gameMap;
}
public Ghost[] getGhosts(){
return this.ghosts;
}
public Pacman getPacman(){
return this.pacman;
}
public void setPacman(Pacman pacman){
this.pacman=pacman;
}
public void eatPallet(int posXMap, int posYMap){
SCORE+=10;
CHANGE_SCORE_MUTEX.release();
//this.score+=10;
Log.i(&quot;Score GM&quot;, &quot;&quot;+SCORE);
//Log.i(&quot;Score GM&quot;, &quot;&quot;+this.score);
this.gameMap.getMap()[posYMap][posXMap]=0;
//this.changeScoreSemaphore.release();
//if(this.changeScoreSemaphore==null){
//    Log.i(&quot;Change Score Semaphore&quot;,&quot;I&#39;m null&quot;);
//}else{
//    Log.i(&quot;Change Score Semaphore&quot;,&quot;I&#39;m not null&quot;);
//}
}
public void eatBonus(int posXMap,int posYMap){
SCORE+=500;
CHANGE_SCORE_MUTEX.release();
//this.score+=500;
//Log.i(&quot;Score&quot;, Double.toString(this.score).substring(0,Double.toString(this.score).indexOf(&#39;.&#39;)));
this.gameMap.getMap()[posYMap][posXMap]=0;
//this.changeScoreSemaphore.release();
}
public void eatSuperPallet(int posXMap,int posYMap){
SCORE+=50;
CHANGE_SCORE_MUTEX.release();
//this.score+=50;
this.gameMap.getMap()[posYMap][posXMap]=0;
//Si hay un timer andando lo cancelo y ejecuto otro
if (this.scareCountDown != null){
this.scareCountDown.cancel();
}
this.scareCountDown = new CountDownScareGhosts(this.ghosts,this.gameMap.getMap());
this.scareCountDown.start();
//this.changeScoreSemaphore.release();
}
public void tryCreateBonus(){
//only if pacman has eaten 20 pallets we should allow the fruit appear
if(!this.fruitHasBeenInTheLevel &amp;&amp; this.gameMap.getEatenPallets()&gt;=20){
//to not allow the fruit be again in the level
this.fruitHasBeenInTheLevel=true;
new CountdownBonusThread(this.gameMap,this.bonusResetTime).start();
}
}
@RequiresApi(api = Build.VERSION_CODES.N)
public void moveGhosts(Canvas canvas,int blocksize) {
for (int i = 0; i &lt; ghosts.length; i++) {
ghosts[i].move(this.gameMap.getMap(),this.pacman);
ghosts[i].draw(canvas);
}
}
public synchronized void initGhosts(int blocksize, Resources res, String packageName,int movementFluency) {
int[][]spawnPositions,cornersPositions, notUpDownPositions,defaultTargets;
defaultTargets=this.gameMap.getDefaultGhostTarget();
notUpDownPositions=this.gameMap.getNotUpDownDecisionPositions();
spawnPositions=this.gameMap.getGhostsSpawnPositions();
cornersPositions=this.gameMap.getGhostsScatterTarget();
//start position
// 5 blinky spawn [13, 11]
// 6 pinky spawn [15,11]
// 7 inky spawn [13,16]
// 8 clyde spawn [15,16]
this.ghosts=new Ghost[4];
ghosts[0] = new Ghost(&quot;blinky&quot;,spawnPositions[0], cornersPositions[0] ,new BehaviorChaseAgressive(notUpDownPositions,movementFluency,defaultTargets[0]),movementFluency,notUpDownPositions,&#39;l&#39;,defaultTargets[0],blocksize,res,packageName);
ghosts[1] = new Ghost(&quot;pinky&quot;,spawnPositions[1],cornersPositions[1],new BehaviorChaseAmbush(notUpDownPositions,movementFluency,defaultTargets[1]),movementFluency,notUpDownPositions,&#39;r&#39;,defaultTargets[1],blocksize,res,packageName);
ghosts[2] = new Ghost(&quot;inky&quot;,spawnPositions[2],cornersPositions[2],new BehaviorChasePatrol(notUpDownPositions,this.ghosts[0],movementFluency,defaultTargets[0]),movementFluency,notUpDownPositions,&#39;l&#39;,defaultTargets[0],blocksize,res,packageName);
ghosts[3] = new Ghost(&quot;clyde&quot;,spawnPositions[3],cornersPositions[3],new BehaviorChaseRandom(notUpDownPositions,cornersPositions[3],movementFluency,defaultTargets[1]),movementFluency,notUpDownPositions,&#39;r&#39;,defaultTargets[1],blocksize,res,packageName);
try{
Thread.sleep(200);
}catch(Exception e){}
for (int i=0;i&lt;ghosts.length;i++){
ghosts[i].onLevelStart(1);
}
}
public boolean checkWinLevel() {
//player win the level if he has eaten all the pallet
return this.gameMap.countPallets()==0;
}
public void onResume(){
for (int i=0 ; i&lt;this.ghosts.length;i++){
this.ghosts[i].cancelBehavoirThread();
}
if(this.scareCountDown!=null &amp;&amp; !this.scareCountDown.hasEnded()){
this.scareCountDown.start();
}
}
public void onPause(){
for (int i=0 ; i&lt;this.ghosts.length;i++){
this.ghosts[i].cancelBehavoirThread();
}
if(this.scareCountDown!=null &amp;&amp; !this.scareCountDown.hasEnded()){
this.scareCountDown=this.scareCountDown.onPause();
}
}
public void cancelThreads(){
for (int i=0 ; i&lt;this.ghosts.length;i++){
this.ghosts[i].cancelBehavoirThread();
}
if(this.scareCountDown!=null){
this.scareCountDown.cancel();
}
}
}

I haven't found a solution like this anywhere, I wish I've save you a lot of research time if you're currently having a problem like this 一个视图如何对SurfaceView的方法调用做出反应?

huangapple
  • 本文由 发表于 2020年8月16日 13:03:09
  • 转载请务必保留本文链接:https://go.coder-hub.com/63433339.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定