1

I have a gameboard consisting of a two dimensional SKShapeNode tile map. It actually works great, but I find that the logic in touchDown(atPoint pos: CGPoint) is a complete mess, filled with conditionals:

        if viewModel.playerIsUsingSkill {
            if player.characterSpriteNode.contains(pos) || self.gameBoardArray[self.player.xPosition][self.player.yPosition].contains(pos) {
                useSkill()
                viewModel.deSelecting(completion: { [weak self] in
                    self?.playerSkillCards.color = UIColor(named: "portrait_background") ?? UIColor.blue
                    self?.viewModel.playerIsUsingSkill = false
                })
            } else {
                viewModel.deSelecting(completion: { [weak self] in
                    self?.playerSkillCards.color = UIColor(named: "portrait_background") ?? UIColor.blue
                    self?.viewModel.playerIsUsingSkill = false
                })
            }
        } else {
            if player.characterActionPoints > 0 {
                updateGUI()
                self.isUserInteractionEnabled = false
                       
                self.setupAttackButton()

                var breakOuterLoop = false

                    // MARK: - Combat Button is Pressed
                if(attackButton.contains(pos) && !attackButton.isHidden) {
                    viewModel.attackButtonIsClicked(attacker: player, defender: enemy) { result in
                        self.player.attackAnimation(animationAtlas: self.player.characterAttackTextureAtlas, completion: { [weak self] in
                            guard let self = self else { return }
                            self.player.idleAnimation(animationAtlas: self.player.characterIdleTextureAtlas)
                        })
                       
                        self.player.turnCharacterInCombat(defender: self.enemy)

                        switch result {
                        case .hit:
                            print("HIT")
                           
                            self.enemy.characterHitAnimation(animationAtlas: self.enemy.characterHitTextureAtlas, completion: { [weak self] in
                                guard let self = self else { return }
                                self.enemy.idleAnimation(animationAtlas: self.enemy.characterIdleTextureAtlas)
                            })
                            self.addChild(self.viewModel.showHitOrMiss(text: "HIT", position: self.enemy.characterSpriteNode.position, character: self.enemy))
                        case .miss:
                            self.addChild(self.viewModel.showHitOrMiss(text: "MISS", position: self.enemy.characterSpriteNode.position, character: self.enemy))
                        case .destroyed:
                            self.enemy.characterSpriteNode.removeFromParent()
                            self.enemy.characterSpriteNode.isAccessibilityElement = true
                            self.attackButton.isHidden = true
                        }
                    }
                    checkCharacterActionPoints()
                }
                else {
                        // MARK: - Loop Whole GameBoard, Find Tile Location Based on Coordinates
                    for x in 0...gameBoardArray.count - 1 where !breakOuterLoop{
                        for y in 0...gameBoardArray.count - 1 {
                            if gameBoardArray[x][y].contains(pos) {
                                viewModel.currentSelectedTile = gameBoardArray[x][y]
                               
                                    // MARK:  - Deselecting
                                if viewModel.currentSelectedTile == viewModel.previousSelectedTile && (viewModel.characterIsSelected || viewModel.tileClickedOnce) {
                                    viewModel.deSelecting(completion: {
                                        self.removeGUI()
                                        })
                                }
                                    // MARK: - Selecting Character
                                else if viewModel.currentSelectedTile == player.characterTilePosition && !viewModel.characterIsSelected {
                                        viewModel.deselectEnemy()
                                        viewModel.selectingCharacter(i: x, j: y, completion: {
                                            self.addGUI()
                                           
                                            self.player.proximityCheck(opponent: self.enemy, completion: { [weak self] enemyIsInProximity in
                                                if enemyIsInProximity {
                                                    self?.attackButton.isHidden = false
                                                    self?.attackChance.isHidden = false
                                                }
                                            })
                                        })
                                }
                                    // MARK: - Selecting Other
                                else if !viewModel.characterIsSelected && viewModel.currentSelectedTile != player.characterTilePosition {
                                        viewModel.selectingOther(i: x, j: y, enemyVM: enemy)
                                }
                                    // MARK: - Moving Character
                                else if viewModel.characterIsSelected && viewModel.currentSelectedTile != player.characterTilePosition {
                                        viewModel.characterIsMoving(i: x, j: y, completion: { moveWasWithinLimit, shouldDeSelect  in
                                       
                                        // Making sure that the player position tile is not acessible for enemy movement
                                        self.viewModel.currentSelectedTile.isAccessibilityElement = false
                                        self.viewModel.previousSelectedTile.isAccessibilityElement = true
                                       
                                            // MARK: - Selecting Enemy, DeSelecting Character
                                        if(shouldDeSelect) {
                                            self.viewModel.deSelecting(completion: {
                                                self.removeGUI()
                                            })
                                            self.viewModel.shouldDeSelect = false
                                        }else {
                                                // MARK: - Move Character Within Move Limit
                                            if(moveWasWithinLimit) {
                                                self.player.previousX = self.player.xPosition
                                                self.player.previousY = self.player.yPosition
                                                self.player.xPosition = x
                                                self.player.yPosition = y
                                               
                                                self.viewModel.turnCharacter(previousX: self.player.previousX, previousY: self.player.previousY, playerOrEnemy: &self.player)
                                           
                                                self.player.characterTilePosition = self.gameBoardArray[x][y]
                                                self.attackButton.isHidden = true
                                                self.attackChance.isHidden = true
                                                self.checkCharacterActionPoints()
                                                self.player.proximityCheck(opponent: self.enemy, completion: { [weak self] enemyIsInProximity in
                                                    if enemyIsInProximity {
                                                        self?.attackButton.isHidden = false
                                                        self?.attackChance.isHidden = false
                                                    }
                                                })
                                            } else {
                                                    // MARK: - DeSelecting
                                                self.viewModel.deSelecting(completion: {
                                                    self.removeGUI()
                                                })
                                            }
                                        }
                                    })
                                }
                                else {
                                    print("Error")
                                }

                                viewModel.previousSelectedTile = viewModel.currentSelectedTile
                                breakOuterLoop = true
                                break
                            }
                        }
                    }
                    if player.characterActionPoints > 0 { isUserInteractionEnabled = true }
                }//else
            }//if
        }
    }

It's basically: If you press this part, x will happen; if you press a player y will happen; if you press an enemy z will happen. Then it's filled with conditionals for different scenarios within all those conditionals. As I said, it works quite well and without any bugs, but I find it immensely hard to work with and fragile to new code. Is there another way I can go about the code? Not sure where to start, so though I should check with some experts on spriteKit and gameplayKit on how to handle it. Any framework I should look at for example...

Joakim Sjöstedt
  • 824
  • 2
  • 9
  • 18

0 Answers0