// Copyright (c) 2023 Dominic Masters // // This software is released under the MIT License. // https://opensource.org/licenses/MIT #include "TicTacToeGame.hpp" #include "game/DawnGame.hpp" #include "scene/components/example/ExampleSpin.hpp" #include "scene/components/physics/3d/CubeCollider.hpp" #include "state/StateProvider.hpp" using namespace Dawn; TicTacToeGame::TicTacToeGame(SceneItem *item) : SceneItemComponent(item), winner(TIC_TAC_TOE_EMPTY), nextMove(TIC_TAC_TOE_NOUGHT), gameOver(false), scoreCross(0), scoreNought(0) { } void TicTacToeGame::onStart() { // Map tiles by tile number = tile auto ts = getScene()->findComponents(); auto itTiles = ts.begin(); while(itTiles != ts.end()) { this->tiles[(*itTiles)->tile] = *itTiles; ++itTiles; } useTimeout([&]{ std::cout << "Timeout" << std::endl; }, 1000, this)(); useEffect([&]{ if(!gameOver) return; auto board = this->getBoard(); std::vector winningCombo; winner = ticTacToeDetermineWinner(board, &winningCombo); switch(winner) { case TIC_TAC_TOE_CROSS: scoreCross++; break; case TIC_TAC_TOE_NOUGHT: scoreNought++; break; default: break; } }, gameOver); useEvent([&](float_t delta) { // Only allow player input if it's their turn. if(gameOver) return; Camera *camera = getScene()->findComponent(); if(camera == nullptr) return; TicTacToeTile *hovered = nullptr; bool_t isPlayerMove = nextMove == TIC_TAC_TOE_NOUGHT; // Get hovered tile (for player move only) if(isPlayerMove) { // Get mouse in screen space. auto mouse = getGame()->inputManager.getAxis2D(INPUT_BIND_MOUSE_X, INPUT_BIND_MOUSE_Y); mouse *= 2.0f; mouse -= glm::vec2(1, 1); struct Ray3D ray; ray.origin = camera->transform->getWorldPosition(); ray.direction = camera->getRayDirectionFromScreenSpace(mouse); // Find the hovered tile (if any) auto results = getPhysics()->raycast3DAll(ray); auto itResult = results.begin(); while(itResult != results.end()) { auto result = *itResult; auto tile = result.collider->item->getComponent(); if(tile == nullptr) { ++itResult; continue; } hovered = tile; break; } } // Now update the hover state(s) auto itTiles = tiles.begin(); while(itTiles != tiles.end()) { auto t = itTiles->second; if(t == hovered) { t->hovered = true; } else { t->hovered = false; } ++itTiles; } if(isPlayerMove) { if(getGame()->inputManager.isPressed(INPUT_BIND_MOUSE_CLICK) && hovered != nullptr) { this->makeMove(hovered->tile, nextMove); } } else if(nextMove != TIC_TAC_TOE_NOUGHT) { auto board = this->getBoard(); auto move = ticTacToeGetAiMove(board, nextMove); this->makeMove(move, nextMove); } // Did game just end? gameOver = ticTacToeIsGameOver(this->getBoard()); }, getScene()->eventSceneUpdate); } std::map TicTacToeGame::getBoard() { std::map tileMap; auto itTiles = tiles.begin(); while(itTiles != tiles.end()) { auto t = itTiles->second; tileMap[t->tile] = t->tileState; ++itTiles; } return tileMap; } void TicTacToeGame::makeMove(uint8_t tile, enum TicTacToeTileState player) { this->tiles[tile]->tileState = player; nextMove = player == TIC_TAC_TOE_NOUGHT ? TIC_TAC_TOE_CROSS : TIC_TAC_TOE_NOUGHT; }