简体   繁体   中英

Not seeing an activity on the screen while switching between activities

I tried to code the game Battleship(I'm a total beginner) and while switching between activities so the computer will take its turn after the user, the computer does end up taking its turn, but I don't see his screen for some reason, it stays on the user's screen(which is the computer's board).

Anyone can tell me why that is? The board is composed of a 8x8 grid of buttons. After clicking the play button on MainActivity, the program will ask the user to place his battleships, after he's done and clicks the start button, the activity will switch to ComputerSide. The computer will place its battleships randomly on the board and then the user will be asked to pick a target. After the target has been picked and the tile changed color appropriately, the activity will switch to UserSide where the computer will take its turn, and that's when I can't see the activity's screen.

Also as a side note, it keeps saying in the console that frames are being skipped, and I read it's because the main thread is doing too much work, but I don't understand where too much work is being done...

If there's additional information you need to answer let me know please.

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()
    }
}

ComputerSide:

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)
    }
}

Is private fun vertOrHor() running forever? How do you break out of this for loop?

The for loops in your onCreate of ComputerSide are doing too much stuff.

However, you need something to do those things.

You do not need a clickListener on every single button. You can put a single clickListener on the grid like how to use onclicklistener for grid view

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM