簡體   English   中英

計算機AI上交UIViewController

[英]Computer AI turns in a UIViewController

在我正在編寫的使用UIKit的快速游戲中,人類玩家將與UIKit UIButtons(GUI元素)交互以采取行動。

在游戲中,玩家將與AI玩家對戰。

但這是事實; 人類玩家按下按鈕並進行交互,而AI玩家則沒有。

給定一個簡單的UIViewController;

class SampleViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
    }

    @IBAction func buyBtnPressed(_ sender: UIButton) {
       print ("pressed")
    }
}

那么我想確定的是,AI播放器本身如何在當前視圖控制器的上下文內采取行動並處理轉彎?

我認為最好的方法是應該有一個循環,等待所有玩家完成各自的回合。

但是這個循環在哪里呢? 在視圖中加載了嗎?

如果是這樣,它會不會耗盡內存,或者是否可能導致(如果不小心)無休止的循環?

考慮到GUI元素是用於人機交互的,我發現很難確定AI播放器如何在UIViewController的給定上下文中采取行動。

我的意思不是說AI應該為按下按鈕設置動畫或與屏幕互動。 我有一個UIViewController,它的視圖確實已加載; 實現AI轉彎的策略是什么?是否應該在加載了View的“游戲循環”中實現它,或者是否可以通過其他方式實現?

我的問題是; 給定一個UIViewController的上下文; 我該如何編碼AI玩家輪流使用的處理方式,並且可以通過循環或其他策略來實現?

非常感謝

編輯:現在已添加代碼

我已經寫了一個使用Swift游樂場的轉彎基地經理,還有2個示例,一個使用UIViewController,另一個是循環。

現在代碼如下;

import Foundation
import GameplayKit

class Player {
    var name: String
    public private(set) var isAI: Bool = false
    public private(set) var turnOrder: Int = 0

    init(name: String, isAI: Bool?) {
        self.name = name
        if let hasAI = isAI {
            self.isAI = hasAI
        }
    }

    func setTurnOrderIndex(number: Int) {
        self.turnOrder = number
    }
}

let p1 = Player.init(name: "Bob", isAI: false)
let p2 = Player.init(name: "Alex", isAI: true)

protocol TurnOrderManagerDelegate: NSObjectProtocol {
    func turnOrderWasSet()
}

protocol TurnDelegate: class {
    func turnIsCompleted()
}

class Turn: NSObject {
    weak var player: Player?
    weak var delegate: TurnDelegate?

    public private(set) var completed: Bool = false {
        didSet {
            delegate?.turnIsCompleted()
        }
    }

    init(player:Player, delegate: TurnDelegate) {
        self.player = player
        self.delegate = delegate
    }

    func setAsComplete() {
        self.completed = true
    }
}

class TurnOrderManager: NSObject, TurnOrderManagerDelegate, TurnDelegate {
    static var instance = TurnOrderManager()

    public private(set) var turnOrderIndex: Int = 0
    public private(set) var turnOrder: [Turn] = [Turn]() {
        didSet {
            self.turnOrderWasSet()
        }
    }

    var playerOnTurn: Player? {
        let turnObj = self.turnOrder[turnOrderIndex]
        return (turnObj.player)
    }

    var allTurnsCompleted: Bool {
        let filtered = turnOrder.filter { (turnObj:Turn) -> Bool in
            return (turnObj.completed)
        }.count
        return (filtered == turnOrder.count)
    }

    func setTurnOrder(players:[Player]) {
        if (self.turnOrder.count == 0) {
            for playerObj in players {
                let turnObj = Turn.init(player: playerObj, delegate: self)
                self.turnOrder.append(turnObj)
            }
        }
    }

    func turnOrderWasSet() {
        for (index, turnObj) in self.turnOrder.enumerated() {
            turnObj.player?.setTurnOrderIndex(number: index)
        }
    }

    func next() {
        if (turnOrderIndex < (self.turnOrder.count - 1)) {
            turnOrderIndex += 1
        }
        else {
            turnOrderIndex = 0
        }
    }

    internal func turnIsCompleted() {
        print (" - turnIsCompleted")
        TurnOrderManager.instance.next()
    }

}

class GameModel {
    var turnOrderManager: TurnOrderManager

    init() {
        self.turnOrderManager = TurnOrderManager.instance
        self.turnOrderManager.setTurnOrder(players:[p1,p2])
    }

    // other game model stuff [...]
}

class Phase1State : GKState {

    var gameModel: GameModel!

    init(gameModel:GameModel) {
        super.init()
        self.gameModel = gameModel
    }

    override func isValidNextState(_ stateClass: AnyClass) -> Bool
    {
        return false
    }

    override func didEnter(from previousState: GKState?) {
    }

    override func willExit(to nextState: GKState) {
    }

    // MARK: - Action

    func buy() {
        let index = self.gameModel.turnOrderManager.turnOrderIndex
        let turn = self.gameModel.turnOrderManager.turnOrder[index]
        turn.setAsComplete()
    }
}

class SomeViewController: UIViewController
{
    var gameModel: GameModel?
    weak var gamePhase: Phase1State?
    var isPhaseComplete: Bool {
        return self.gameModel?.turnOrderManager.allTurnsCompleted ?? false
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        self.gameModel = GameModel.init()
        self.gamePhase = Phase1State.init(gameModel: self.gameModel!)
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }

    func buyButtonPressed() {
        self.gamePhase?.buy()
        self.finishTurn()
    }

    func finishTurn() {
        guard let turnIndex = self.gameModel?.turnOrderManager.turnOrderIndex else {
            return
        }
        guard let turn = self.gameModel?.turnOrderManager.turnOrder[turnIndex] else {
            return
        }
        turn.setAsComplete()

        if (self.isPhaseComplete)
        {
            print ("All turns are completed")
        }
        else {
            //self.gameModel?.turnOrderManager.next()
            self.gamePhase?.buy()

            guard let playerOnTurn = self.gameModel?.turnOrderManager.playerOnTurn else {
                print ("No player is on turn")
                return
            }

            print ("\(playerOnTurn.name) is on turn")

            if (playerOnTurn.isAI)
            {
                self.gamePhase?.buy()
                self.finishTurn()
            }
        }
    }
}


// EXAMPLE 1 -- first attempt ...

let vc = SomeViewController()
vc.viewDidLoad()
vc.buyButtonPressed()

// EXAMPLE 2 -- another attempt ....


let gameModel: GameModel = GameModel.init()
let gamePhase = Phase1State.init(gameModel: gameModel)

// player then takes an action

while (gameModel.turnOrderManager.allTurnsCompleted == false)
{
    let turnIndex = gameModel.turnOrderManager.turnOrderIndex
    let turnObj = gameModel.turnOrderManager.turnOrder[turnIndex]
    guard let playerOnTurn = turnObj.player else {
        break
    }

    print ("Player \(playerOnTurn.name) is on turn")

    gamePhase.buy()
}

print ("All turns are completed, advance to next phase")

問題是;

在finishTurn上,只有依靠索引中的第一個玩家為人類玩家時,它才似乎起作用。 如果不是這樣,我不知道如何觸發購買行為。

在第二個示例中,我使用一個循環。 但我擔心使用循環可能會永遠循環下去。

因此澄清了我的查詢,如何確保我的視圖控制器在AI玩家不按下按鈕並在每個玩家中循環並執行各自的回合時為他們觸發動作。

非常感謝

進一步編輯:

我不知道我的viewDidLoad()內是否應該有while (gameModel.turnOrderManager.allTurnsCompleted == false)循環來像游戲循環一樣。

看,我不確定您在制作哪種游戲,請您可能應該學習SpriteKit ,尤其是SKActions 這樣,您可以輕松控制游戲中事件的流程。

話雖如此,您的AI實施情況如何? 根據您的代碼,我將從以下內容開始:

class AI {

    enum Decision {
        case doSomething
        case doAnotherThing
        case dontDoAnything
    }

    public func decide() -> Decision {
        // Decide which action the AI will take...
        return .doSomething // This return is just a example!
    }

    public func act(on : Decision) {
        // Do whatever the AI needs based on a decision...
    }

}

然后,在您的ViewController中:

class SampleViewController: UIViewController {

    var ai = AI()

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    @IBAction func buyBtnPressed(_ sender: UIButton) {
        print ("pressed")
        ai.act(on: ai.decide())
    }

}

希望對您有所幫助!

無需為此專門使用Sprite Kit。 SpriteKit將更多地與UI的制作方式有關,而不是游戲邏輯的運作方式。

但是,我建議您查看GameplayKit。 它是一個包含許多內置游戲邏輯工具的框架。 具體來說,您想要類似GKDecisionTree東西。 也有一些WWDC視頻。 GameplayKit可以與SpriteKit,UIKit,SSceneKit或您決定使用(或不使用)任何其他游戲引擎一起使用。

另外,您要問的問題是關於游戲開發的一個非常普遍的問題。 讓計算機“決定”做某事是一個相當復雜的主題。

我還建議您快速觀看AI&Games的視頻以及該頻道的其他視頻。

它會給您一個解決問題的思路。

WWDC 2015和2016的會議609和608可能不錯:D

關於更新AI。

您的AI應該是事件驅動的。 您具有“轉彎”和“玩家”的概念。 游戲中有一個地方變成“玩家的”“轉身”。 (即使在游戲開始時,也就是玩家1或玩家2的回合。

這時有兩種可能性。 玩家是AI還是玩家是人。

一旦發生這種情況,就應該有某種觸發器(例如函數調用之類的東西)告訴玩家輪到其開始了。

如果該玩家是AI,則您需要開始某種計算(可能需要內置延遲才能使它變得現實),以便它決定要做什么。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM