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

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

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

问题

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

  1. package Activities;
  2. import android.os.Bundle;
  3. import android.view.SurfaceView;
  4. import android.widget.TextView;
  5. import androidx.appcompat.app.AppCompatActivity;
  6. import com.example.pacman.DBManager;
  7. import Game.GameView;
  8. import com.example.pacman.R;
  9. import com.example.pacman.Score;
  10. public class PlayActivity extends AppCompatActivity {
  11. private TextView playerNickname;
  12. TextView score;
  13. private TextView maxScore;
  14. private SurfaceView gameSurfaceView;
  15. private GameView gameView;
  16. @Override
  17. public void onCreate(Bundle savedInstanceState) {
  18. super.onCreate(savedInstanceState);
  19. // Modified code
  20. setContentView(R.layout.activity_game);
  21. // We get text view that we will use
  22. playerNickname = (TextView) this.findViewById(R.id.tv_player);
  23. score = (TextView) this.findViewById(R.id.tv_current_score);
  24. maxScore = (TextView) this.findViewById(R.id.tv_current_max_score);
  25. gameSurfaceView = (GameView) this.findViewById(R.id.game_view);
  26. // Set text view initial values
  27. playerNickname.setText(getIntent().getExtras().getString("playerNickname"));
  28. score.setText("0");
  29. maxScore.setText("To modify");
  30. this.gameView = new GameView(gameSurfaceView.getContext());
  31. this.gameSurfaceView.getHolder().addCallback(this.gameView);
  32. }
  33. protected void onResume() {
  34. super.onResume();
  35. this.gameView.resume();
  36. }
  37. protected void onPause() {
  38. super.onPause();
  39. this.gameView.pause();
  40. }
  41. public void updateScore(int score) {
  42. this.score.setText("" + score);
  43. }
  44. public void onLose(double score) {
  45. // We try to save the score, if there is a previous register we write only if this score
  46. // is better than the one before
  47. DBManager manager;
  48. long raw;
  49. Score scoreToSave;
  50. manager = new DBManager(this);
  51. scoreToSave = new Score(this.playerNickname.toString(), score);
  52. if (manager.saveScore(scoreToSave) == -1) {
  53. // if I couldn't save the score
  54. if (manager.updateScore(scoreToSave) != -1) {
  55. // if my new score is better than the one previous
  56. } else {
  57. // if my new score is worse or equal than the one previous
  58. }
  59. }
  60. }
  61. }
  1. package Game;
  2. import android.content.Context;
  3. import android.graphics.Canvas;
  4. import android.os.Build;
  5. import android.util.AttributeSet;
  6. import android.util.Log;
  7. import android.view.GestureDetector;
  8. import android.view.MotionEvent;
  9. import android.view.SurfaceHolder;
  10. import android.view.SurfaceView;
  11. import androidx.annotation.RequiresApi;
  12. import Activities.PlayActivity;
  13. import Game.Character_package.Ghost;
  14. import Game.Character_package.Pacman;
  15. public class GameView extends SurfaceView implements Runnable, SurfaceHolder.Callback, GestureDetector.OnGestureListener {
  16. // ... (rest of the code)
  17. }
  1. package Game;
  2. import android.app.Activity;
  3. import android.content.Context;
  4. import android.graphics.Canvas;
  5. import android.os.Build;
  6. import android.util.Log;
  7. import androidx.annotation.RequiresApi;
  8. import com.example.pacman.R;
  9. import org.jetbrains.annotations.NotNull;
  10. import Game.Behavior.ChaseBehavior.*;
  11. import Game.Character_package.Ghost;
  12. import Game.Character_package.Pacman;
  13. import Game.GameCountDown.*;
  14. public class GameManager {
  15. // ... (rest of the code)
  16. }

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

  1. package Activities;
  2. import android.os.Bundle;
  3. import android.view.SurfaceView;
  4. import android.widget.TextView;
  5. import androidx.appcompat.app.AppCompatActivity;
  6. import com.example.pacman.DBManager;
  7. import Game.GameView;
  8. import com.example.pacman.R;
  9. import com.example.pacman.Score;
  10. public class PlayActivity extends AppCompatActivity {
  11. private TextView playerNickname;
  12. TextView score;
  13. private TextView maxScore;
  14. private SurfaceView gameSurfaceView;
  15. private GameView gameView;
  16. @Override
  17. public void onCreate(Bundle savedInstanceState) {
  18. super.onCreate(savedInstanceState);
  19. //Modified code
  20. setContentView(R.layout.activity_game);
  21. //we get text view that we will use
  22. playerNickname=(TextView) this.findViewById(R.id.tv_player);
  23. score=(TextView) this.findViewById(R.id.tv_current_score);
  24. maxScore=(TextView) this.findViewById(R.id.tv_current_max_score);
  25. gameSurfaceView= (GameView) this.findViewById(R.id.game_view);
  26. //set text view initial values
  27. playerNickname.setText(getIntent().getExtras().getString(&quot;playerNickname&quot;));
  28. score.setText(&quot;0&quot;);
  29. maxScore.setText(&quot;To modify&quot;);
  30. this.gameView=new GameView(gameSurfaceView.getContext());
  31. this.gameSurfaceView.getHolder().addCallback(this.gameView);
  32. }
  33. protected void onResume(){
  34. super.onResume();
  35. this.gameView.resume();
  36. }
  37. protected void onPause(){
  38. super.onPause();
  39. this.gameView.pause();
  40. }
  41. public void updateScore(int score){
  42. this.score.setText(&quot;&quot;+score);
  43. }
  44. public void onLose(double score){
  45. //We try to save the score, if there is a previous register we write only if this score
  46. //is better that the one before
  47. DBManager manager;
  48. long raw;
  49. Score scoreToSave;
  50. manager=new DBManager(this);
  51. scoreToSave=new Score(this.playerNickname.toString(), score);
  52. if(manager.saveScore(scoreToSave)==-1){
  53. //if i couldn&#39;t save the score
  54. if(manager.updateScore(scoreToSave)!=-1){
  55. //if my new score is better than the one previous
  56. }else{
  57. //if my new score is worse or equal than the one previous
  58. }
  59. }
  60. }
  61. }

And here is the Game View code

  1. package Game;
  2. import android.content.Context;
  3. import android.graphics.Canvas;
  4. import android.graphics.Color;
  5. import android.os.Build;
  6. import android.util.AttributeSet;
  7. import android.util.Log;
  8. import android.view.GestureDetector;
  9. import android.view.MotionEvent;
  10. import android.view.SurfaceHolder;
  11. import android.view.SurfaceView;
  12. import android.widget.TextView;
  13. import androidx.annotation.RequiresApi;
  14. import Activities.PlayActivity;
  15. import Game.Character_package.Ghost;
  16. import Game.Character_package.Pacman;
  17. public class GameView extends SurfaceView implements Runnable, SurfaceHolder.Callback, GestureDetector.OnGestureListener {
  18. private static final float SWIPE_THRESHOLD = 2;
  19. private static final float SWIPE_VELOCITY = 2;
  20. private boolean GHOST_INICIALIZED=false;
  21. private GestureDetector gestureDetector;
  22. private GameManager gameManager;
  23. private Thread thread; //game thread
  24. private SurfaceHolder holder;
  25. private boolean canDraw = false;
  26. private int blockSize; // Ancho de la pantalla, ancho del bloque
  27. 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
  28. private int totalFrame = 4; // Cantidad total de animation frames por direccion
  29. private int currentArrowFrame = 0; // animation frame de arrow actual
  30. private long frameTicker; // tiempo desde que el ultimo frame fue dibujado
  31. //----------------------------------------------------------------------------------------------
  32. //Constructors
  33. public GameView(Context context) {
  34. super(context);
  35. this.constructorHelper(context);
  36. }
  37. public GameView(Context context, AttributeSet attrs) {
  38. super(context, attrs);
  39. this.constructorHelper(context);
  40. }
  41. public GameView(Context context, AttributeSet attrs, int defStyle) {
  42. super(context, attrs, defStyle);
  43. this.constructorHelper(context);
  44. }
  45. private void constructorHelper(Context context) {
  46. this.gestureDetector = new GestureDetector(this);
  47. this.setFocusable(true);
  48. this.holder = getHolder();
  49. this.holder.addCallback(this);
  50. this.frameTicker = (long) (1000.0f / totalFrame);
  51. this.gameManager=new GameManager(this);
  52. int screenWidth=getResources().getDisplayMetrics().widthPixels;
  53. this.blockSize = ((((screenWidth/this.gameManager.getGameMap().getMapWidth())/movementFluencyLevel)*movementFluencyLevel)/4)*4;
  54. this.holder.setFixedSize(blockSize*this.gameManager.getGameMap().getMapWidth(),blockSize*this.gameManager.getGameMap().getMapHeight());
  55. this.gameManager.getGameMap().loadBonusBitmaps(this);
  56. this.gameManager.setPacman(new Pacman(&quot;pacman&quot;,&quot;&quot;,this,this.movementFluencyLevel));
  57. Ghost.loadCommonBitmaps(this);
  58. }
  59. //----------------------------------------------------------------------------------------------
  60. //Getters and setters
  61. public int getBlockSize() {
  62. return blockSize;
  63. }
  64. public GameManager getGameManager() {
  65. return gameManager;
  66. }
  67. public int getMovementFluencyLevel(){return movementFluencyLevel;}
  68. //----------------------------------------------------------------------------------------------
  69. private synchronized void initGhost(){
  70. if(!GHOST_INICIALIZED){
  71. GHOST_INICIALIZED=true;
  72. this.gameManager.initGhosts(this);
  73. }
  74. }
  75. @RequiresApi(api = Build.VERSION_CODES.N)
  76. @Override
  77. public void run() {
  78. long gameTime;
  79. Canvas canvas;
  80. while (!holder.getSurface().isValid()) {
  81. }
  82. this.initGhost();
  83. this.setFocusable(true);
  84. while (canDraw) {
  85. gameTime=System.currentTimeMillis();
  86. if(gameTime &gt; frameTicker + (totalFrame * 15)){
  87. canvas = holder.lockCanvas();
  88. if(canvas!=null){
  89. if(this.updateFrame(gameTime,canvas)){
  90. try {
  91. Thread.sleep(3000);
  92. }catch (Exception e){}
  93. }
  94. holder.unlockCanvasAndPost(canvas);
  95. if(this.gameManager.checkWinLevel()){
  96. canDraw=false;
  97. this.gameManager.cancelThreads();
  98. try {
  99. Thread.sleep(2000);
  100. } catch (InterruptedException e) {}
  101. //animation
  102. Log.i(&quot;Game&quot;,&quot;You win&quot;);
  103. }else if(!this.gameManager.getPacman().hasLifes()){
  104. //we lost
  105. canDraw=false;
  106. this.gameManager.cancelThreads();
  107. //animation
  108. Log.i(&quot;Game&quot;,&quot;You lose&quot;);
  109. }
  110. }
  111. }
  112. }
  113. }
  114. // Method to capture touchEvents
  115. @Override
  116. public boolean onTouchEvent(MotionEvent event) {
  117. //To swipe
  118. //https://www.youtube.com/watch?v=32rSs4tE-mc
  119. this.gestureDetector.onTouchEvent(event);
  120. super.onTouchEvent(event);
  121. return true;
  122. }
  123. //Chequea si se deberia actualizar el frame actual basado en el
  124. // tiempo que a transcurrido asi la animacion
  125. //no se ve muy rapida y mala
  126. @RequiresApi(api = Build.VERSION_CODES.N)
  127. private boolean updateFrame(long gameTime, Canvas canvas) {
  128. Pacman pacman;
  129. Ghost[] ghosts;
  130. boolean pacmanIsDeath;
  131. pacman=this.gameManager.getPacman();
  132. ghosts=this.gameManager.getGhosts();
  133. // Si el tiempo suficiente a transcurrido, pasar al siguiente frame
  134. frameTicker = gameTime;
  135. canvas.drawColor(Color.BLACK);
  136. this.gameManager.getGameMap().draw(canvas, Color.BLUE,this.blockSize,this.gameManager.getLevel());
  137. this.gameManager.moveGhosts(canvas,this.blockSize);
  138. pacmanIsDeath=pacman.move(this.gameManager,canvas);
  139. if(!pacmanIsDeath){
  140. // incrementar el frame
  141. pacman.changeFrame();
  142. for(int i=0; i&lt;ghosts.length;i++){
  143. ghosts[i].changeFrame();
  144. }
  145. currentArrowFrame++;
  146. currentArrowFrame%=7;
  147. }else{
  148. pacman.setNextDirection(&#39; &#39;);
  149. for(int i=0; i&lt;ghosts.length;i++){
  150. ghosts[i].respawn();
  151. }
  152. }
  153. return pacmanIsDeath;
  154. }
  155. //----------------------------------------------------------------------------------------------
  156. //Callback methods
  157. @RequiresApi(api = Build.VERSION_CODES.N)
  158. @Override
  159. public void surfaceCreated(SurfaceHolder holder) {
  160. canDraw = true;
  161. this.thread= new Thread(this);
  162. this.thread.start();
  163. }
  164. @Override
  165. public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
  166. }
  167. @Override
  168. public void surfaceDestroyed(SurfaceHolder holder) {
  169. }
  170. //----------------------------------------------------------------------------------------------
  171. public void resume() {
  172. this.canDraw = true;
  173. thread = new Thread(this);
  174. thread.start();
  175. }
  176. public void pause() {
  177. this.canDraw = false;
  178. while (true) {
  179. try {
  180. thread.join();
  181. return;
  182. } catch (InterruptedException e) {
  183. // retry
  184. }
  185. break;
  186. }
  187. this.thread=null;
  188. }
  189. @Override
  190. public boolean onDown(MotionEvent e) {
  191. return false;
  192. }
  193. @Override
  194. public void onShowPress(MotionEvent e) {
  195. }
  196. @Override
  197. public boolean onSingleTapUp(MotionEvent e) {
  198. return false;
  199. }
  200. @Override
  201. public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
  202. return false;
  203. }
  204. @Override
  205. public void onLongPress(MotionEvent e) {
  206. }
  207. @Override
  208. public boolean onFling(MotionEvent downEvent, MotionEvent moveEvent, float velocityX, float velocityY) {
  209. //To swipe
  210. //https://www.youtube.com/watch?v=32rSs4tE-mc
  211. float diffX, diffY;
  212. Pacman pacman;
  213. Log.i(&quot;Fling&quot;, &quot;detected&quot;);
  214. diffX = moveEvent.getX() - downEvent.getX();
  215. diffY = moveEvent.getY() - downEvent.getY();
  216. pacman=this.gameManager.getPacman();
  217. if (Math.abs(diffX) &gt; Math.abs(diffY)) {
  218. //right or left swipe
  219. if (Math.abs(diffX) &gt; SWIPE_THRESHOLD &amp;&amp; Math.abs(velocityX) &gt; SWIPE_VELOCITY) {
  220. if (diffX &gt; 0) {
  221. //right
  222. pacman.setNextDirection(&#39;r&#39;);
  223. } else {
  224. //left
  225. pacman.setNextDirection(&#39;l&#39;);
  226. }
  227. }
  228. } else {
  229. //up or down swipe
  230. if (Math.abs(diffY) &gt; SWIPE_THRESHOLD &amp;&amp; Math.abs(velocityY) &gt; SWIPE_VELOCITY) {
  231. if (diffY &gt; 0) {
  232. //down
  233. pacman.setNextDirection(&#39;d&#39;);
  234. } else {
  235. //up
  236. pacman.setNextDirection(&#39;u&#39;);
  237. }
  238. }
  239. }
  240. return true;
  241. }
  242. }

And finally the GameManager code

  1. package Game;
  2. import android.app.Activity;
  3. import android.content.Context;
  4. import android.graphics.Canvas;
  5. import android.os.Build;
  6. import android.util.Log;
  7. import android.widget.TextView;
  8. import androidx.annotation.RequiresApi;
  9. import com.example.pacman.R;
  10. import org.jetbrains.annotations.NotNull;
  11. import Game.Behavior.ChaseBehavior.*;
  12. import Game.Character_package.Ghost;
  13. import Game.Character_package.Pacman;
  14. import Game.GameCountDown.*;
  15. public class GameManager {
  16. private static final int TOTAL_LEVELS=256;
  17. private GameMap gameMap;
  18. private int level,bonusResetTime,score;
  19. private CountDownScareGhosts scareCountDown;
  20. private Pacman pacman;
  21. private Ghost[] ghosts;
  22. private boolean fruitHasBeenInTheLevel;
  23. public GameManager(GameView gameView){
  24. this.fruitHasBeenInTheLevel=false;
  25. this.score=0;
  26. this.gameMap=new GameMap();
  27. this.gameMap.loadMap1();
  28. this.level=1;
  29. this.ghosts=new Ghost[4];
  30. this.bonusResetTime = 5000;
  31. this.scareCountDown=null;
  32. }
  33. public void addScore(int s){
  34. this.score+=s;
  35. }
  36. public int getScore() {
  37. return this.score;
  38. }
  39. public int getLevel() {
  40. return this.level;
  41. }
  42. public GameMap getGameMap() {
  43. return this.gameMap;
  44. }
  45. public Ghost[] getGhosts(){
  46. return this.ghosts;
  47. }
  48. public Ghost getGhost(int i) {
  49. return this.ghosts[i];
  50. }
  51. public Pacman getPacman(){
  52. return this.pacman;
  53. }
  54. public void setPacman(Pacman pacman){
  55. this.pacman=pacman;
  56. }
  57. public void eatPallet(int posXMap, int posYMap){
  58. this.score+=10;
  59. //Log.i(&quot;Score&quot;, Double.toString(this.score).substring(0,Double.toString(this.score).indexOf(&#39;.&#39;)));
  60. this.gameMap.getMap()[posYMap][posXMap]=0;
  61. }
  62. public void eatBonus(int posXMap,int posYMap){
  63. this.score+=500;
  64. //Log.i(&quot;Score&quot;, Double.toString(this.score).substring(0,Double.toString(this.score).indexOf(&#39;.&#39;)));
  65. this.gameMap.getMap()[posYMap][posXMap]=0;
  66. }
  67. public void eatSuperPallet(int posXMap,int posYMap){
  68. this.score+=50;
  69. Log.i(&quot;Score&quot;, Double.toString(this.score).substring(0,Double.toString(this.score).indexOf(&#39;.&#39;)));
  70. this.gameMap.getMap()[posYMap][posXMap]=0;
  71. //Si hay un timer andando lo cancelo y ejecuto otro
  72. if (this.scareCountDown != null){
  73. this.scareCountDown.cancel();
  74. }
  75. this.scareCountDown = new CountDownScareGhosts(this.ghosts,this.gameMap.getMap());
  76. this.scareCountDown.start();
  77. }
  78. public void tryCreateBonus(){
  79. //only if pacman has eaten 20 pallets we should allow the fruit appear
  80. if(!this.fruitHasBeenInTheLevel &amp;&amp; this.gameMap.getEatenPallets()&gt;=20){
  81. //to not allow the fruit be again in the level
  82. this.fruitHasBeenInTheLevel=true;
  83. new CountdownBonusThread(this.gameMap,this.bonusResetTime).start();
  84. }
  85. }
  86. @RequiresApi(api = Build.VERSION_CODES.N)
  87. public void moveGhosts(Canvas canvas,int blocksize) {
  88. for (int i = 0; i &lt; ghosts.length; i++) {
  89. ghosts[i].move(this.gameMap.getMap(),this.pacman);
  90. ghosts[i].draw(canvas);
  91. }
  92. }
  93. public synchronized void initGhosts(@NotNull GameView gv) {
  94. int[][]spawnPositions,cornersPositions, notUpDownPositions,defaultTargets;
  95. int movementeFluency;
  96. defaultTargets=this.gameMap.getDefaultGhostTarget();
  97. notUpDownPositions=this.gameMap.getNotUpDownDecisionPositions();
  98. spawnPositions=this.gameMap.getGhostsSpawnPositions();
  99. cornersPositions=this.gameMap.getGhostsScatterTarget();
  100. movementeFluency=gv.getMovementFluencyLevel();
  101. //start position
  102. // 5 blinky spawn [13, 11]
  103. // 6 pinky spawn [15,11]
  104. // 7 inky spawn [13,16]
  105. // 8 clyde spawn [15,16]
  106. this.ghosts=new Ghost[4];
  107. 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]);
  108. 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]);
  109. 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]);
  110. 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]);
  111. try{
  112. Thread.sleep(200);
  113. }catch(Exception e){}
  114. for (int i=0;i&lt;ghosts.length;i++){
  115. ghosts[i].onLevelStart(1);
  116. }
  117. }
  118. public boolean checkWinLevel() {
  119. //player win the level if he has eaten all the pallet
  120. return this.gameMap.countPallets()==0;
  121. }
  122. public void onResume(){
  123. for (int i=0 ; i&lt;this.ghosts.length;i++){
  124. this.ghosts[i].cancelBehavoirThread();
  125. }
  126. if(this.scareCountDown!=null &amp;&amp; !this.scareCountDown.hasEnded()){
  127. this.scareCountDown.start();
  128. }
  129. }
  130. public void onPause(){
  131. for (int i=0 ; i&lt;this.ghosts.length;i++){
  132. this.ghosts[i].cancelBehavoirThread();
  133. }
  134. if(this.scareCountDown!=null &amp;&amp; !this.scareCountDown.hasEnded()){
  135. this.scareCountDown=this.scareCountDown.onPause();
  136. }
  137. }
  138. public void cancelThreads(){
  139. for (int i=0 ; i&lt;this.ghosts.length;i++){
  140. this.ghosts[i].cancelBehavoirThread();
  141. }
  142. if(this.scareCountDown!=null){
  143. this.scareCountDown.cancel();
  144. }
  145. }
  146. }

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

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

  1. public class PlayActivity extends AppCompatActivity {
  2. private TextView playerNickname;
  3. private TextView scoreTv;
  4. private TextView maxScore;
  5. private SurfaceView gameSurfaceView;
  6. private GameView gameView;
  7. private GameManager gameManager;
  8. private static Semaphore CHANGE_SCORE_MUTEX=new Semaphore(0,true);
  9. private static Semaphore CHANGE_DIRECTION_MUTEX=new Semaphore(0,true);
  10. private Thread changeScoreThread, changeDirectionThread;
  11. @Override
  12. public void onCreate(Bundle savedInstanceState) {
  13. super.onCreate(savedInstanceState);
  14. //Modified code
  15. setContentView(R.layout.activity_game);
  16. //we get text view that we will use
  17. playerNickname=(TextView) this.findViewById(R.id.tv_player);
  18. scoreTv=(TextView) this.findViewById(R.id.tv_current_score);
  19. maxScore=(TextView) this.findViewById(R.id.tv_current_max_score);
  20. gameSurfaceView= (GameView) this.findViewById(R.id.game_view);
  21. //set text view initial values
  22. playerNickname.setText(getIntent().getExtras().getString("playerNickname"));
  23. scoreTv.setText("0");
  24. maxScore.setText("To modify");
  25. this.gameView=new GameView(gameSurfaceView.getContext());
  26. this.gameManager=this.gameView.getGameManager();
  27. this.gameView.setSemaphores(CHANGE_SCORE_MUTEX,CHANGE_DIRECTION_MUTEX);
  28. this.gameSurfaceView.getHolder().addCallback(this.gameView);
  29. }
  30. protected void onResume(){
  31. super.onResume();
  32. this.gameView.resume();
  33. this.initChangerThreads();
  34. }
  35. public void updateScoreTv(int score){
  36. this.scoreTv.setText(""+score);
  37. }
  38. protected void onPause(){
  39. super.onPause();
  40. this.gameView.pause();
  41. //in order to stop the threads
  42. CHANGE_SCORE_MUTEX.release();
  43. CHANGE_DIRECTION_MUTEX.release();
  44. }
  45. // ... 其他部分的翻译 ...
  46. private void initChangerThreads() {
  47. this.changeScoreThread = new Thread(new Runnable() {
  48. public void run() {
  49. while (gameView.isDrawing()) {
  50. try {
  51. CHANGE_SCORE_MUTEX.acquire();
  52. runOnUiThread(new Runnable() {
  53. @Override
  54. public void run() {
  55. updateScoreTv(gameView.getGameManager().getScore());
  56. }
  57. });
  58. }catch (Exception e){}
  59. }
  60. }
  61. });
  62. this.changeScoreThread.start();
  63. }
  64. }
  1. public class GameManager {
  2. private static final int TOTAL_LEVELS=256;
  3. private static int SCORE=0;
  4. private GameMap gameMap;
  5. private int level,bonusResetTime;
  6. private CountDownScareGhosts scareCountDown;
  7. private Pacman pacman;
  8. private Ghost[] ghosts;
  9. private boolean fruitHasBeenInTheLevel;
  10. private static Semaphore CHANGE_SCORE_MUTEX;
  11. public GameManager(){
  12. this.fruitHasBeenInTheLevel=false;
  13. this.gameMap=new GameMap();
  14. this.gameMap.loadMap1();
  15. this.level=1;
  16. this.ghosts=new Ghost[4];
  17. this.bonusResetTime = 5000;
  18. this.scareCountDown=null;
  19. }
  20. public void setChangeScoreSemaphore(Semaphore changeScoreSemaphore) {
  21. CHANGE_SCORE_MUTEX = changeScoreSemaphore;
  22. }
  23. public void addScore(int s){
  24. SCORE+=s;
  25. CHANGE_SCORE_MUTEX.release();
  26. }
  27. public int getScore() {
  28. return SCORE;
  29. }
  30. // ... 其他部分的翻译 ...
  31. public void eatPallet(int posXMap, int posYMap){
  32. SCORE+=10;
  33. CHANGE_SCORE_MUTEX.release();
  34. this.gameMap.getMap()[posYMap][posXMap]=0;
  35. }
  36. // ... 其他部分的翻译 ...
  37. }

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

英文:

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

  1. public class PlayActivity extends AppCompatActivity {
  2. private TextView playerNickname;
  3. private TextView scoreTv;
  4. private TextView maxScore;
  5. private SurfaceView gameSurfaceView;
  6. private GameView gameView;
  7. private GameManager gameManager;
  8. private static Semaphore CHANGE_SCORE_MUTEX=new Semaphore(0,true);
  9. private static Semaphore CHANGE_DIRECTION_MUTEX=new Semaphore(0,true);
  10. private Thread changeScoreThread, changeDirectionThread;
  11. @Override
  12. public void onCreate(Bundle savedInstanceState) {
  13. super.onCreate(savedInstanceState);
  14. //Modified code
  15. setContentView(R.layout.activity_game);
  16. //we get text view that we will use
  17. playerNickname=(TextView) this.findViewById(R.id.tv_player);
  18. scoreTv=(TextView) this.findViewById(R.id.tv_current_score);
  19. maxScore=(TextView) this.findViewById(R.id.tv_current_max_score);
  20. gameSurfaceView= (GameView) this.findViewById(R.id.game_view);
  21. //set text view initial values
  22. playerNickname.setText(getIntent().getExtras().getString(&quot;playerNickname&quot;));
  23. scoreTv.setText(&quot;0&quot;);
  24. maxScore.setText(&quot;To modify&quot;);
  25. this.gameView=new GameView(gameSurfaceView.getContext());
  26. this.gameManager=this.gameView.getGameManager();
  27. this.gameView.setSemaphores(CHANGE_SCORE_MUTEX,CHANGE_DIRECTION_MUTEX);
  28. this.gameSurfaceView.getHolder().addCallback(this.gameView);
  29. }
  30. protected void onResume(){
  31. super.onResume();
  32. this.gameView.resume();
  33. this.initChangerThreads();
  34. }
  35. public void updateScoreTv(int score){
  36. this.scoreTv.setText(&quot;&quot;+score);
  37. }
  38. protected void onPause(){
  39. super.onPause();
  40. this.gameView.pause();
  41. //in order to stop the threads
  42. CHANGE_SCORE_MUTEX.release();
  43. CHANGE_DIRECTION_MUTEX.release();
  44. }
  45. public void onLose(double score){
  46. //We try to save the score, if there is a previous register we write only if this score
  47. //is better that the one before
  48. DBManager manager;
  49. long raw;
  50. Score scoreToSave;
  51. manager=new DBManager(this);
  52. scoreToSave=new Score(this.playerNickname.toString(), score);
  53. if(manager.saveScore(scoreToSave)==-1){
  54. //if i couldn&#39;t save the score
  55. if(manager.updateScore(scoreToSave)!=-1){
  56. //if my new score is better than the one previous
  57. }else{
  58. //if my new score is worse or equal than the one previous
  59. }
  60. }
  61. }
  62. private void initChangerThreads() {
  63. this.changeScoreThread = new Thread(new Runnable() {
  64. public void run() {
  65. while (gameView.isDrawing()) {
  66. //Log.i(&quot;Score &quot;,&quot;&quot;+gameManager.getScore());
  67. try {
  68. CHANGE_SCORE_MUTEX.acquire();
  69. runOnUiThread(new Runnable() {
  70. @Override
  71. public void run() {
  72. updateScoreTv(gameView.getGameManager().getScore());
  73. }
  74. });
  75. }catch (Exception e){}
  76. }
  77. }
  78. });
  79. this.changeScoreThread.start();
  80. }
  81. }

GameView: I've just added this method

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

GameManager

  1. public class GameManager {
  2. private static final int TOTAL_LEVELS=256;
  3. private static int SCORE=0;
  4. private GameMap gameMap;
  5. private int level,bonusResetTime;//,score;
  6. private CountDownScareGhosts scareCountDown;
  7. private Pacman pacman;
  8. private Ghost[] ghosts;
  9. private boolean fruitHasBeenInTheLevel;
  10. private static Semaphore CHANGE_SCORE_MUTEX;
  11. public GameManager(){
  12. this.fruitHasBeenInTheLevel=false;
  13. //this.score=0;
  14. this.gameMap=new GameMap();
  15. this.gameMap.loadMap1();
  16. this.level=1;
  17. this.ghosts=new Ghost[4];
  18. this.bonusResetTime = 5000;
  19. this.scareCountDown=null;
  20. }
  21. public void setChangeScoreSemaphore(Semaphore changeScoreSemaphore) {
  22. CHANGE_SCORE_MUTEX = changeScoreSemaphore;
  23. //if(this.changeScoreSemaphore==null){
  24. // Log.i(&quot;Change Score Semaphore&quot;,&quot;I&#39;m null&quot;);
  25. //}else{
  26. // Log.i(&quot;Change Score Semaphore&quot;,&quot;I&#39;m not null&quot;);
  27. //}
  28. }
  29. public void addScore(int s){
  30. //this.score+=s;
  31. SCORE+=s;
  32. CHANGE_SCORE_MUTEX.release();
  33. /*if(this.changeScoreSemaphore==null){
  34. Log.i(&quot;Change Score Semaphore&quot;,&quot;I&#39;m null&quot;);
  35. }else{
  36. Log.i(&quot;Change Score Semaphore&quot;,&quot;I&#39;m not null&quot;);
  37. }*/
  38. //this.changeScoreSemaphore.release();
  39. }
  40. public int getScore() {
  41. return SCORE;
  42. //return this.score;
  43. }
  44. public int getLevel() {
  45. return this.level;
  46. }
  47. public GameMap getGameMap() {
  48. return this.gameMap;
  49. }
  50. public Ghost[] getGhosts(){
  51. return this.ghosts;
  52. }
  53. public Pacman getPacman(){
  54. return this.pacman;
  55. }
  56. public void setPacman(Pacman pacman){
  57. this.pacman=pacman;
  58. }
  59. public void eatPallet(int posXMap, int posYMap){
  60. SCORE+=10;
  61. CHANGE_SCORE_MUTEX.release();
  62. //this.score+=10;
  63. Log.i(&quot;Score GM&quot;, &quot;&quot;+SCORE);
  64. //Log.i(&quot;Score GM&quot;, &quot;&quot;+this.score);
  65. this.gameMap.getMap()[posYMap][posXMap]=0;
  66. //this.changeScoreSemaphore.release();
  67. //if(this.changeScoreSemaphore==null){
  68. // Log.i(&quot;Change Score Semaphore&quot;,&quot;I&#39;m null&quot;);
  69. //}else{
  70. // Log.i(&quot;Change Score Semaphore&quot;,&quot;I&#39;m not null&quot;);
  71. //}
  72. }
  73. public void eatBonus(int posXMap,int posYMap){
  74. SCORE+=500;
  75. CHANGE_SCORE_MUTEX.release();
  76. //this.score+=500;
  77. //Log.i(&quot;Score&quot;, Double.toString(this.score).substring(0,Double.toString(this.score).indexOf(&#39;.&#39;)));
  78. this.gameMap.getMap()[posYMap][posXMap]=0;
  79. //this.changeScoreSemaphore.release();
  80. }
  81. public void eatSuperPallet(int posXMap,int posYMap){
  82. SCORE+=50;
  83. CHANGE_SCORE_MUTEX.release();
  84. //this.score+=50;
  85. this.gameMap.getMap()[posYMap][posXMap]=0;
  86. //Si hay un timer andando lo cancelo y ejecuto otro
  87. if (this.scareCountDown != null){
  88. this.scareCountDown.cancel();
  89. }
  90. this.scareCountDown = new CountDownScareGhosts(this.ghosts,this.gameMap.getMap());
  91. this.scareCountDown.start();
  92. //this.changeScoreSemaphore.release();
  93. }
  94. public void tryCreateBonus(){
  95. //only if pacman has eaten 20 pallets we should allow the fruit appear
  96. if(!this.fruitHasBeenInTheLevel &amp;&amp; this.gameMap.getEatenPallets()&gt;=20){
  97. //to not allow the fruit be again in the level
  98. this.fruitHasBeenInTheLevel=true;
  99. new CountdownBonusThread(this.gameMap,this.bonusResetTime).start();
  100. }
  101. }
  102. @RequiresApi(api = Build.VERSION_CODES.N)
  103. public void moveGhosts(Canvas canvas,int blocksize) {
  104. for (int i = 0; i &lt; ghosts.length; i++) {
  105. ghosts[i].move(this.gameMap.getMap(),this.pacman);
  106. ghosts[i].draw(canvas);
  107. }
  108. }
  109. public synchronized void initGhosts(int blocksize, Resources res, String packageName,int movementFluency) {
  110. int[][]spawnPositions,cornersPositions, notUpDownPositions,defaultTargets;
  111. defaultTargets=this.gameMap.getDefaultGhostTarget();
  112. notUpDownPositions=this.gameMap.getNotUpDownDecisionPositions();
  113. spawnPositions=this.gameMap.getGhostsSpawnPositions();
  114. cornersPositions=this.gameMap.getGhostsScatterTarget();
  115. //start position
  116. // 5 blinky spawn [13, 11]
  117. // 6 pinky spawn [15,11]
  118. // 7 inky spawn [13,16]
  119. // 8 clyde spawn [15,16]
  120. this.ghosts=new Ghost[4];
  121. 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);
  122. 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);
  123. 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);
  124. 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);
  125. try{
  126. Thread.sleep(200);
  127. }catch(Exception e){}
  128. for (int i=0;i&lt;ghosts.length;i++){
  129. ghosts[i].onLevelStart(1);
  130. }
  131. }
  132. public boolean checkWinLevel() {
  133. //player win the level if he has eaten all the pallet
  134. return this.gameMap.countPallets()==0;
  135. }
  136. public void onResume(){
  137. for (int i=0 ; i&lt;this.ghosts.length;i++){
  138. this.ghosts[i].cancelBehavoirThread();
  139. }
  140. if(this.scareCountDown!=null &amp;&amp; !this.scareCountDown.hasEnded()){
  141. this.scareCountDown.start();
  142. }
  143. }
  144. public void onPause(){
  145. for (int i=0 ; i&lt;this.ghosts.length;i++){
  146. this.ghosts[i].cancelBehavoirThread();
  147. }
  148. if(this.scareCountDown!=null &amp;&amp; !this.scareCountDown.hasEnded()){
  149. this.scareCountDown=this.scareCountDown.onPause();
  150. }
  151. }
  152. public void cancelThreads(){
  153. for (int i=0 ; i&lt;this.ghosts.length;i++){
  154. this.ghosts[i].cancelBehavoirThread();
  155. }
  156. if(this.scareCountDown!=null){
  157. this.scareCountDown.cancel();
  158. }
  159. }
  160. }

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:

确定