我尝试编写游戏Battleship(我是一个初学者),并且在进行各种活动之间切换时,计算机会在用户之后轮到他,而计算机最终会轮到他,但是我看不到他的屏幕出于某种原因停留在用户的屏幕(计算机的面板)上。
任何人都可以告诉我为什么吗? 该板由一个8x8的按钮网格组成。 单击MainActivity上的播放按钮后,程序将要求用户放置战舰,完成后单击开始按钮,活动将切换到ComputerSide。 计算机将其战舰随机放置在板上,然后要求用户选择目标。 选定目标并适当改变瓷砖的颜色后,活动将切换到UserSide,计算机将轮到该用户,此时我看不到活动的屏幕。
此外,它还在控制台中一直说正在跳过帧,而我读这是因为主线程做了太多的工作,但是我不知道在哪里做了太多的工作。
如果还有其他信息需要回答,请告诉我。
MainActivity:
class MainActivity : AppCompatActivity() {
private lateinit var playButton: Button
private lateinit var rulesButton: Button
private lateinit var aboutButton: Button
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
playButton = findViewById(R.id.btnPlay)
rulesButton = findViewById(R.id.btnRules)
aboutButton = findViewById(R.id.btnAbout)
}
fun playBtnClick(view: View) {
// GameActivity::class.java
val intent = Intent(this, UserSide::class.java)
this.startActivity(intent)
}
fun aboutBtnClick(view: View) {
val intent = Intent(this, AboutActivity::class.java)
this.startActivity(intent)
}
fun rulesBtnClick(view: View) {
val intent = Intent(this, RulesActivity::class.java)
this.startActivity(intent)
}
}
UserSide:
class UserSide : AppCompatActivity() {
/***************** Messages for the user ******************/
val occupiedMsg = { Toast.makeText(this, "Battleships overlapping, choose a different spot", Toast.LENGTH_SHORT).show() }
val noSpaceUpwardsMsg = { Toast.makeText(this, "Not enough space upwards, try again.", Toast.LENGTH_SHORT).show() }
val noSpaceDownwardsMsg = { Toast.makeText(this, "Not enough space downwards, try again.", Toast.LENGTH_SHORT).show() }
val noSpaceLeftMsg = { Toast.makeText(this, "Not enough space to the left, try again.", Toast.LENGTH_SHORT).show() }
val noSpaceRightMsg = { Toast.makeText(this, "Not enough space to the right, try again.", Toast.LENGTH_SHORT).show() }
val notReadyMsg = { Toast.makeText(this, "Not all battleships have been placed.", Toast.LENGTH_SHORT).show() }
val inSessionMsg = { Toast.makeText(this, "Game is in session.", Toast.LENGTH_SHORT).show() }
/***********************************************************************************************************************/
private val UPWARDS = 0
private val DOWNWARDS = 1
private val RIGHT = 2
private val LEFT = 3
private lateinit var instruction: TextView
private lateinit var grid: GridLayout
private lateinit var start: Button
private var tiles: ArrayList<Button> = arrayListOf()
private var battleships: ArrayList<Battleship> = arrayListOf()
private var userInput = -1
private var numOfTiles = 5 // Number of tiles of the current battleship to be placed.
private var placedShips = 0
private var inSession = false
/************************** CHECK FUNCTION verticalCheck **********************/
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_user_side)
start = findViewById(R.id.btnStart)
// Retrieving the instruction at the top.
instruction = findViewById(R.id.instruction)
// Retrieving the game board
grid = findViewById(R.id.gridLayout)
for(btn in grid) {
tiles.add(findViewById(btn.id))
}
// Initializing battleships array
for(num in 0 until 4) {
battleships.add(Battleship(numOfTiles - num))
}
// Adding a listener to all the tiles
for(btn in 1 until tiles.size + 1) {
tiles[btn - 1].setOnClickListener {
placeBattleship(btn)
Thread.sleep(100)
}
}
start.setOnClickListener { startGame() }
}
private fun placeBattleship(btnNum: Int) {
when(numOfTiles) {
// Placing 5 tile battleship
5 -> vertOrHor(btnNum)
// Placing 4 tile battleship
4 -> vertOrHor(btnNum)
// Placing 3 tile battleship
3 -> vertOrHor(btnNum)
// Placing 2 tile battleship
2 -> vertOrHor(btnNum)
}
}
private fun vertOrHor(btnNum: Int) {
// Creating a dialog message and listeners for its buttons.
val dialogClickListener = DialogInterface.OnClickListener { dialog, which ->
when (which) {
// Upwards
DialogInterface.BUTTON_POSITIVE -> {
try {
upOrDown(btnNum)
}
catch (e: IndexOutOfBoundsException) { noSpaceUpwardsMsg() }
}
// Downwards
DialogInterface.BUTTON_NEGATIVE -> {
try {
leftOrRight(btnNum)
}
catch (e: IndexOutOfBoundsException) { noSpaceDownwardsMsg() }
}
}
}
// Editing the text of the dialog and its buttons
val builder: AlertDialog.Builder? = AlertDialog.Builder(this)
builder?.setMessage("Place the battleship vertically or horizontally?")
?.setPositiveButton("Vertically", dialogClickListener)
?.setNegativeButton("Horizontally", dialogClickListener)?.show()
}
private fun upOrDown(btnNum: Int) {
// Creating a dialog message and listeners for its buttons.
val dialogClickListener = DialogInterface.OnClickListener { dialog, which ->
when (which) {
// Upwards
DialogInterface.BUTTON_POSITIVE -> {
try {
userInput = UPWARDS
placeBattleshipVertical(btnNum)
}
catch (e: IndexOutOfBoundsException) { noSpaceUpwardsMsg() }
}
// Downwards
DialogInterface.BUTTON_NEGATIVE -> {
try {
userInput = DOWNWARDS
placeBattleshipVertical(btnNum)
}
catch (e: IndexOutOfBoundsException) { noSpaceDownwardsMsg() }
}
}
}
// Editing the text of the dialog and its buttons
val builder: AlertDialog.Builder? = AlertDialog.Builder(this)
builder?.setMessage("Place the battleship upwards or downwards?")
?.setPositiveButton("Upwards", dialogClickListener)
?.setNegativeButton("Downwards", dialogClickListener)?.show()
}
private fun leftOrRight(btnNum: Int) {
val dialogClickListener = DialogInterface.OnClickListener { dialog, which ->
when (which) {
// Upwards
DialogInterface.BUTTON_POSITIVE -> {
try {
userInput = RIGHT
placeBattleshipHorizontal(btnNum)
}
catch (e: IndexOutOfBoundsException) { noSpaceRightMsg() }
}
// Downwards
DialogInterface.BUTTON_NEGATIVE -> {
try {
userInput = LEFT
placeBattleshipHorizontal(btnNum)
}
catch (e: IndexOutOfBoundsException) { noSpaceLeftMsg() }
}
}
}
val builder: AlertDialog.Builder? = AlertDialog.Builder(this)
builder?.setMessage("Place the battleship to the left or to the right?")
?.setPositiveButton("Right", dialogClickListener)
?.setNegativeButton("Left", dialogClickListener)?.show()
}
private fun placeBattleshipVertical(btnNum: Int) {
if(verticalCheck(btnNum)) {
if(userInput == UPWARDS) placeVertically(btnNum - 8 * (numOfTiles - 1), btnNum + 8)
else placeVertically(btnNum, btnNum + 8 * numOfTiles)
changeInstruction()
}
}
private fun placeBattleshipHorizontal(btnNum: Int) {
if(checkHorizontal(btnNum)) {
if (userInput == RIGHT) placeHorizontally(btnNum, btnNum + numOfTiles)
else placeHorizontally(btnNum - numOfTiles + 1, btnNum + 1)
changeInstruction()
}
}
private fun verticalCheck(btnNum: Int): Boolean {
// Are the tiles above occupied?
if(userInput == UPWARDS) {
for (num in btnNum - (8 * (numOfTiles - 1)) until btnNum) {
if (num < 0) {
noSpaceUpwardsMsg()
return false
}
}
val occupied = isOccupiedVertically(btnNum - 8 * (numOfTiles - 1), btnNum + 8)
if(!occupied) occupiedMsg()
return occupied
}
else {
for(num in btnNum + 8 until btnNum + (8 * (numOfTiles - 1)) step 8) {
if(num > 64) {
noSpaceDownwardsMsg()
return false
}
}
val occupied = isOccupiedVertically(btnNum, btnNum + 8 * numOfTiles)
if(!occupied) occupiedMsg()
return occupied
}
}
private fun checkHorizontal(btnNum: Int): Boolean {
if(userInput == LEFT) {
for (num in btnNum - numOfTiles + 1 until btnNum + 1) {
// Checking if battleship might be placed off screen
if (num % 8 == 0 && num != btnNum) {
noSpaceLeftMsg()
return false
}
}
// Checking if battleships overlap
val occupied = isOccupiedHorizontally(btnNum - numOfTiles + 1, btnNum)
if(!occupied) occupiedMsg()
return occupied
}
else {
for (num in btnNum until btnNum + numOfTiles) {
// Right corner to the right
if (num % 8 == 0 && num != btnNum + numOfTiles - 1) {
noSpaceRightMsg()
return false
}
}
}
val occupied = isOccupiedHorizontally(btnNum + 1, btnNum + numOfTiles)
if(!occupied) occupiedMsg()
return occupied
}
/* If a button has a listener, he is not occupied. */
private fun hasListener(num: Int): Boolean = tiles[num - 1].hasOnClickListeners()
// Checks the tiles vertically, returns true if not occupied
private fun isOccupiedVertically(start: Int, end: Int): Boolean {
for(num in start until end step 8) { if(!hasListener(num)) return false }
return true
}
// Checks the tiles horizontally, returns true if not occupied
private fun isOccupiedHorizontally(start: Int, end: Int): Boolean {
for(num in start until end) { if(!hasListener(num)) return false }
return true
}
private fun changeInstruction() {
when(numOfTiles) {
4 -> instruction.text = getString(R.string.place_your_4_tile_battleship)
3 -> instruction.text = getString(R.string.place_your_3_tile_battleship)
2 -> instruction.text = getString(R.string.place_your_2_tile_battleship)
1 -> instruction.text = getString(R.string.Go)
}
}
// Placing battleship by marking its tiles
private fun placeVertically(start: Int, end: Int) {
for (num in start until end step 8) {
occupyTile(num)
}
numOfTiles--
placedShips++
}
// Placing battleship by marking its tiles
private fun placeHorizontally(start: Int, end: Int) {
val ship = Battleship(numOfTiles)
for(num in start until end) {
ship.buildShip(tiles[num - 1])
occupyTile(num)
}
battleships.add(ship)
numOfTiles--
placedShips++
}
@SuppressLint("UseCompatLoadingForDrawables")
private fun occupyTile(num: Int) {
//battleships[placedShips].buildShip(tiles[num - 1])
tiles[num - 1].background = getDrawable(R.drawable.button_occupied_tile)
tiles[num - 1].setOnClickListener(null)
}
@SuppressLint("UseCompatLoadingForDrawables")
fun damageShip() {
val btn = Utils.chooseTarget()
println("Target is: $btn")
val tile = tiles[btn - 1]
val s: Battleship
var didMiss = true
for(ship in battleships) {
// Successful hit.
if(ship.contains(tile)) {
s = ship
tile.background = getDrawable(R.drawable.button_hit_tile)
s.removeTile()
s.getShip()[s.getTileInd(tile)].setOnClickListener(null)
// Ship destroyed
if(s.getNumOfTiles() == 0) {
var i = 0
while(i < s.getSize()) {
s.getShip()[i].background = getDrawable(R.drawable.button_destroyed_tile)
i++
}
battleships.remove(s)
// Game Done
if (battleships.size == 0) {
instruction.text = getString(R.string.Lose)
Utils.gameEnd = true
for (t in tiles) t.setOnClickListener(null)
}
}
if(!Utils.gameEnd) {
didMiss = false
Thread.sleep(200)
userTurn()
}
else return
break
}
}
// Missed hit
if(didMiss) {
// Missed hit
tile.background = getDrawable(R.drawable.button_missed_tile)
Thread.sleep(200)
userTurn()
}
}
// This class represents a battleship
class Battleship(private var tiles: Int) {
private var ship: ArrayList<Button> = arrayListOf()
//private var size = tiles
fun buildShip(btn: Button) = ship.add(btn)
fun getSize() = ship.size
fun getShip() = ship
fun removeTile(){ tiles-- }
fun getNumOfTiles() = tiles
fun getTileInd(btn: Button) = ship.indexOf(btn)
fun contains(btn: Button): Boolean {
for(i in 0 until this.getSize()) { if(ship[i] == btn) return true }
return false
}
}
@SuppressLint("UseCompatLoadingForDrawables")
private fun startGame() {
// If all battleships have been placed.
if(instruction.text == getString(R.string.Go)) {
// If the game hasn't started yet.
if (!inSession) {
inSession = true
for (btn in 1 until tiles.size + 1) {
tiles[btn - 1].background = getDrawable(R.drawable.button_start_tile)
}
instruction.text = ""
start.visibility = View.INVISIBLE
userTurn()
}
else inSessionMsg()
}
else notReadyMsg()
}
private fun userTurn() {
Utils.userTurn = true
val intent = Intent(this, ComputerSide::class.java)
this.startActivity(intent)
}
override fun onResume() {
super.onResume()
if(inSession) damageShip()
}
}
计算机端:
class ComputerSide : AppCompatActivity() {
private val VERTICAL = 0
private val HORIZONTAL = 1
private val UPWARDS = 2
private val DOWNWARDS = 3
private val LEFT = 4
private val RIGHT = 5
private lateinit var grid: GridLayout
private var tiles: ArrayList<Button> = arrayListOf()
private var battleships: ArrayList<Battleship> = arrayListOf()
private var numOfTiles = 5 // Number of tiles of the current battleship to be placed.
private var placedShips = 0
private lateinit var instruction: TextView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_computer_side)
instruction = findViewById(R.id.instruction)
// Retrieving the game board
grid = findViewById(R.id.gridLayout)
for(btn in grid) {
tiles.add(findViewById(btn.id))
}
// Initializing battleships array
// for(num in 0 until 4) {
// battleships.add(Battleship(numOfTiles - num))
// }
// Adding a listener to all the tiles
for(btn in 1 until tiles.size + 1) {
tiles[btn - 1].setOnClickListener {}
}
placeBattleship()
}
@SuppressLint("UseCompatLoadingForDrawables")
private fun placeBattleship() {
vertOrHor()
startGame()
}
private fun vertOrHor() {
// Vertical or Horizontal
while(numOfTiles > 1) {
val choice = Random.nextInt(VERTICAL,HORIZONTAL + 1)
when (choice) {
// Vertical
0 ->
try {
upOrDown()
}
catch (e: IndexOutOfBoundsException) { }
// Horizontal
1 ->
try {
leftOrRight()
}
catch (e: IndexOutOfBoundsException) { }
}
}
}
private fun upOrDown() {
val choice = Random.nextInt(UPWARDS,DOWNWARDS + 1)
placeBattleshipVertical(Utils.chooseStartingPlacement(), choice)
}
private fun leftOrRight() {
val choice = Random.nextInt(LEFT, RIGHT + 1)
placeBattleshipHorizontal(Utils.chooseStartingPlacement(), choice)
}
private fun placeBattleshipVertical(btnNum: Int, dir: Int) {
if(verticalCheck(btnNum, dir)) {
if(dir == UPWARDS) placeVertically(btnNum - 8 * (numOfTiles - 1), btnNum + 8)
else placeVertically(btnNum, btnNum + 8 * numOfTiles)
}
}
private fun placeBattleshipHorizontal(btnNum: Int, dir: Int) {
if(dir == RIGHT) {
// If there's space to the right
if(checkHorizontal(btnNum, dir)) placeHorizontally(btnNum, btnNum + numOfTiles)
else throw IndexOutOfBoundsException()
}
else {
// If there's space to the left
if(checkHorizontal(btnNum, dir)) placeHorizontally(btnNum - numOfTiles + 1, btnNum + 1)
else throw IndexOutOfBoundsException()
}
}
private fun verticalCheck(btnNum: Int, dir: Int): Boolean {
// Are the tiles above occupied?
if(dir == UPWARDS) {
for (num in btnNum - (8 * (numOfTiles - 1)) until btnNum) {
if (num < 0) return false
}
return (isOccupiedVertically(btnNum - 8 * (numOfTiles - 1), btnNum + 8))
}
else {
for(num in btnNum + 8 until btnNum + (8 * (numOfTiles - 1)) step 8) {
if(num > 64) return false
}
return (isOccupiedVertically(btnNum, btnNum + 8 * numOfTiles))
}
}
private fun checkHorizontal(btnNum: Int, dir: Int): Boolean {
if(dir == LEFT) {
for (num in btnNum - numOfTiles + 1 until btnNum + 1) {
// Checking if battleship might be placed off screen
if (num % 8 == 0 && num != btnNum) return false
// Checking if battleships overlap
return (isOccupiedHorizontally(btnNum - numOfTiles + 1, btnNum))
}
}
else {
for (num in btnNum until btnNum + numOfTiles) {
// Right corner to the right
if (num % 8 == 0 && num != btnNum + numOfTiles - 1) return false
}
}
return (isOccupiedHorizontally(btnNum + 1, btnNum + numOfTiles))
}
/* If a button has a listener, he is not occupied. */
private fun hasListener(num: Int): Boolean = tiles[num - 1].hasOnClickListeners()
// Checks the tiles vertically, returns true if not occupied
private fun isOccupiedVertically(start: Int, end: Int): Boolean {
for(num in start until end step 8) { if(!hasListener(num)) return false }
return true
}
// Checks the tiles horizontally, returns true if not occupied
private fun isOccupiedHorizontally(start: Int, end: Int): Boolean {
for(num in start until end) { if(!hasListener(num)) return false }
return true
}
// Placing battleship by marking its tiles
private fun placeVertically(start: Int, end: Int) {
val ship = Battleship(numOfTiles)
for (num in start until end step 8) {
ship.buildShip(tiles[num - 1])
occupyTile(num)
}
battleships.add(ship)
numOfTiles--
placedShips++
}
// Placing battleship by marking its tiles
private fun placeHorizontally(start: Int, end: Int) {
val ship = Battleship(numOfTiles)
for(num in start until end) {
ship.buildShip(tiles[num - 1])
occupyTile(num)
}
battleships.add(ship)
numOfTiles--
placedShips++
}
@SuppressLint("UseCompatLoadingForDrawables")
private fun occupyTile(num: Int) {
//battleships[placedShips].buildShip(tiles[num - 1])
tiles[num - 1].background = getDrawable(R.drawable.button_occupied_tile)
tiles[num - 1].setOnClickListener(null)
}
@SuppressLint("UseCompatLoadingForDrawables")
fun damageShip(btn: Button) {
if(Utils.userTurn) {
var didMiss = true
val s: Battleship
for (ship in battleships) {
// Successful hit.
if (ship.contains(btn)) {
s = ship
btn.background = getDrawable(R.drawable.button_hit_tile)
s.getShip()[s.getShip().indexOf(btn)].setOnClickListener(null)
s.removeTile()
// Ship destroyed
if (s.getNumOfTiles() == 0) {
var i = 0
while (i < s.getSize()) {
s.getShip()[i].background = getDrawable(R.drawable.button_destroyed_tile)
i++
}
battleships.remove(s)
// Game Done
if (battleships.size == 0) {
instruction.text = getString(R.string.Win)
Utils.gameEnd = true
for (tile in tiles) tile.setOnClickListener(null)
}
}
if(!Utils.gameEnd) {
didMiss = false
Thread.sleep(200)
computerTurn()
}
else return
break
}
}
if(didMiss) {
// Missed hit
btn.background = getDrawable(R.drawable.button_missed_tile)
Thread.sleep(200)
computerTurn()
}
}
}
// This class represents a battleship
class Battleship(private var tiles: Int) {
private var ship: ArrayList<Button> = arrayListOf()
//private var size = tiles
fun buildShip(btn: Button) = ship.add(btn)
fun getSize() = ship.size
fun getTile(i: Int) : Button = ship[i]
fun getShip() = ship
fun removeTile() = tiles--
fun getNumOfTiles() = tiles
fun contains(btn: Button): Boolean {
for(i in 0 until this.getSize()) { if(ship[i] == btn) return true }
return false
}
}
@SuppressLint("UseCompatLoadingForDrawables")
private fun startGame() {
for (tile in 1 until tiles.size + 1) {
tiles[tile - 1].background = getDrawable(R.drawable.button_start_tile)
tiles[tile - 1].setOnClickListener { damageShip(tiles[tile - 1]) }
}
Utils.initArray()
instruction.text = getString(R.string.strike_a_target)
}
private fun computerTurn() {
Utils.userTurn = false
val intent = Intent(this, UserSide::class.java)
this.startActivity(intent)
}
}
答案 0 :(得分:0)
private fun vertOrHor()
是否一直在运行?您如何突破这个for循环?
您onCreate
的{{1}}中的for循环正在做很多事情。
但是,您需要做一些事情。
您不需要每个按钮都带有clickListener。您可以将单个clickListener放在网格上,例如 how to use onclicklistener for grid view