Android Studio井字棋游戏获胜者显示异常技术求助
修复井字棋游戏的获胜者显示错误与状态栏问题
嘿,我仔细看了你的井字棋代码,找到了导致获胜者显示错误、甚至状态栏异常消失的核心问题,咱们来一步步修复它:
问题根源分析
- 获胜者判断逻辑完全错误:你当前通过
winningPosition[0]的索引值(比如0或1)来判定X/O获胜,这和实际的玩家标记(gameState里的0=X、1=O)完全不相关,自然会大部分场景判断错误。 - 游戏状态被错误重置:在检查获胜条件前,你写了
gameActive = true;,这会把已经结束的游戏状态强行恢复成可玩,导致游戏无法正确终止,还会干扰状态栏的显示。 - 缺少平局处理:当所有格子填满却无人获胜时,状态栏没有对应的提示,看起来就像“消失”了一样。
- 重复查找控件:每次点击都重新查找
statusTextView,虽然功能没问题,但可以优化成成员变量提升效率。
修复后的完整代码
MainActivity.java
package com.jashanubhi.tictactoeme; import androidx.appcompat.app.AppCompatActivity; import android.os.Bundle; import android.view.View; import android.widget.ImageView; import android.widget.TextView; public class MainActivity extends AppCompatActivity { int activePlayer = 0; boolean gameActive = true; int[] gameState = {2,2,2,2,2,2,2,2,2}; int[][] winningPositions = {{0,1,2}, {3,4,5}, {6,7,8}, {0,4,8}, {2,4,6}, {0,3,6}, {1,4,7}, {2,5,8}}; // 把status声明为成员变量,避免重复findViewById private TextView statusTextView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 初始化statusTextView statusTextView = findViewById(R.id.status); } public void playerTap(View view) { ImageView img = (ImageView) view; int tappedImage = Integer.parseInt(img.getTag().toString()); // 如果游戏已结束,点击就重置 if(!gameActive){ gameReset(view); return; // 重置后直接返回,避免后续逻辑执行 } // 只有空位才能被点击 if(gameState[tappedImage] == 2 && gameActive) { gameState[tappedImage] = activePlayer; img.setTranslationY(-1000f); if (activePlayer == 0) { img.setImageResource(R.drawable.x); activePlayer = 1; statusTextView.setText("O's Turn - Tap to Play"); } else { img.setImageResource(R.drawable.o); activePlayer = 0; statusTextView.setText("X's Turn - Tap to Play"); } img.animate().translationYBy(1000f).setDuration(300); } // 检查是否有获胜者 checkWinner(); // 检查是否平局 checkDraw(); } // 单独提取获胜检查逻辑 private void checkWinner() { for (int[] winningPosition : winningPositions) { int pos0 = gameState[winningPosition[0]]; int pos1 = gameState[winningPosition[1]]; int pos2 = gameState[winningPosition[2]]; // 三个位置都不为空,且值相同则获胜 if (pos0 == pos1 && pos1 == pos2 && pos0 != 2) { String winner = pos0 == 0 ? "X has won" : "O has won"; statusTextView.setText(winner); gameActive = false; return; // 找到获胜者后直接退出循环 } } } // 检查平局逻辑:所有格子都被填满且无人获胜 private void checkDraw() { if(gameActive){ boolean isDraw = true; for(int state : gameState){ if(state == 2){ isDraw = false; break; } } if(isDraw){ statusTextView.setText("It's a Draw!"); gameActive = false; } } } public void gameReset(View view){ activePlayer = 0; gameActive = true; for(int i = 0; i < gameState.length; i++){ gameState[i] = 2; } // 清空所有图片 int[] imageIds = {R.id.imageView0, R.id.imageView1, R.id.imageView2, R.id.imageView3, R.id.imageView4, R.id.imageView5, R.id.imageView6, R.id.imageView7, R.id.imageView8}; for(int id : imageIds){ ((ImageView)findViewById(id)).setImageResource(0); } statusTextView.setText("X's Turn - Tap to Play"); } }
布局XML(无需修改,保持原代码即可)
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <TextView android:id="@+id/textView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="32dp" android:text="@string/title" android:textSize="38dp" android:textStyle="bold" app:fontFamily="sans-serif-light" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" /> <ImageView android:id="@+id/imageView" android:layout_width="398dp" android:layout_height="398dp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/textView" app:srcCompat="@drawable/grid" /> <TextView android:id="@+id/status" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="X's Turn - Tap to Play" android:textSize="30sp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/imageView" /> <LinearLayout android:layout_width="398dp" android:layout_height="398dp" android:orientation="vertical" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.0" app:layout_constraintStart_toStartOf="@+id/imageView" app:layout_constraintTop_toBottomOf="@+id/textView"> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:layout_weight="1" android:orientation="horizontal"> <ImageView android:id="@+id/imageView0" android:layout_width="50dp" android:layout_height="match_parent" android:layout_weight="1" android:onClick="playerTap" android:padding="23sp" android:tag="0" /> <ImageView android:id="@+id/imageView1" android:layout_width="50dp" android:layout_height="match_parent" android:layout_weight="1" android:onClick="playerTap" android:padding="23sp" android:tag="1" /> <ImageView android:id="@+id/imageView2" android:layout_width="50dp" android:layout_height="match_parent" android:layout_weight="1" android:onClick="playerTap" android:padding="23sp" android:tag="2" /> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:layout_weight="1" android:orientation="horizontal"> <ImageView android:id="@+id/imageView3" android:layout_width="50dp" android:layout_height="match_parent" android:layout_weight="1" android:onClick="playerTap" android:padding="23sp" android:tag="3" /> <ImageView android:id="@+id/imageView4" android:layout_width="50dp" android:layout_height="match_parent" android:layout_weight="1" android:onClick="playerTap" android:padding="23sp" android:tag="4" /> <ImageView android:id="@+id/imageView5" android:layout_width="50dp" android:layout_height="match_parent" android:layout_weight="1" android:onClick="playerTap" android:padding="23sp" android:tag="5" /> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:layout_weight="1" android:orientation="horizontal"> <ImageView android:id="@+id/imageView6" android:layout_width="50dp" android:layout_height="match_parent" android:layout_weight="1" android:onClick="playerTap" android:padding="23sp" android:tag="6" /> <ImageView android:id="@+id/imageView7" android:layout_width="50dp" android:layout_height="match_parent" android:layout_weight="1" android:onClick="playerTap" android:padding="23sp" android:tag="7" /> <ImageView android:id="@+id/imageView8" android:layout_width="50dp" android:layout_height="match_parent" android:layout_weight="1" android:onClick="playerTap" android:padding="23sp" android:tag="8" /> </LinearLayout> </LinearLayout> </androidx.constraintlayout.widget.ConstraintLayout>
关键修改点说明
- 修正获胜者判断逻辑:现在通过
gameState[winningPosition[0]]的值来判断,0对应X,1对应O,完全符合你的玩家标记规则。 - 移除错误的gameActive重置:删掉了之前在检查获胜前的
gameActive = true;,确保游戏结束后状态保持为false,不再响应无效点击。 - 添加平局检测:当所有格子都被填满且没有获胜者时,状态栏会显示"It's a Draw!",解决了状态栏“消失”的问题。
- 优化控件查找:把
statusTextView声明为成员变量,在onCreate中初始化,避免每次点击都重复查找,提升性能。 - 重构代码结构:把获胜检查和平局检查单独提取成方法,让代码更清晰易读。
这样修改后,你的井字棋游戏就能正确显示获胜者,处理平局,状态栏也不会再异常消失啦!
内容的提问来源于stack exchange,提问作者Jashan Ubhi
相关产品推荐
相关产品推荐

