Tic tac toe basically done
This commit is contained in:
Binary file not shown.
Before Width: | Height: | Size: 124 KiB After Width: | Height: | Size: 275 KiB |
@ -26,6 +26,7 @@ target_sources(${DAWN_TARGET_NAME}
|
|||||||
# Subdirs
|
# Subdirs
|
||||||
add_subdirectory(asset)
|
add_subdirectory(asset)
|
||||||
add_subdirectory(display)
|
add_subdirectory(display)
|
||||||
|
add_subdirectory(games)
|
||||||
add_subdirectory(input)
|
add_subdirectory(input)
|
||||||
add_subdirectory(locale)
|
add_subdirectory(locale)
|
||||||
add_subdirectory(physics)
|
add_subdirectory(physics)
|
||||||
|
7
src/dawn/games/CMakeLists.txt
Normal file
7
src/dawn/games/CMakeLists.txt
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
# Copyright (c) 2023 Dominic Masters
|
||||||
|
#
|
||||||
|
# This software is released under the MIT License.
|
||||||
|
# https://opensource.org/licenses/MIT
|
||||||
|
|
||||||
|
# Subdirs
|
||||||
|
add_subdirectory(tictactoe)
|
10
src/dawn/games/tictactoe/CMakeLists.txt
Normal file
10
src/dawn/games/tictactoe/CMakeLists.txt
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
# Copyright (c) 2023 Dominic Masters
|
||||||
|
#
|
||||||
|
# This software is released under the MIT License.
|
||||||
|
# https://opensource.org/licenses/MIT
|
||||||
|
|
||||||
|
# Sources
|
||||||
|
target_sources(${DAWN_TARGET_NAME}
|
||||||
|
PRIVATE
|
||||||
|
TicTacToeLogic.cpp
|
||||||
|
)
|
45
src/dawn/games/tictactoe/TicTacToeLogic.cpp
Normal file
45
src/dawn/games/tictactoe/TicTacToeLogic.cpp
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
// Copyright (c) 2023 Dominic Masters
|
||||||
|
//
|
||||||
|
// This software is released under the MIT License.
|
||||||
|
// https://opensource.org/licenses/MIT
|
||||||
|
|
||||||
|
#include "TicTacToeLogic.hpp"
|
||||||
|
|
||||||
|
using namespace Dawn;
|
||||||
|
|
||||||
|
enum TicTacToeTileState Dawn::ticTacToeDetermineWinner(
|
||||||
|
const std::map<uint8_t, enum TicTacToeTileState> board,
|
||||||
|
std::vector<uint8_t> *winningCombo
|
||||||
|
) {
|
||||||
|
uint8_t i;
|
||||||
|
assertNotNull(winningCombo);
|
||||||
|
|
||||||
|
// Check rows
|
||||||
|
for(i = 0; i < 9; i += 3) {
|
||||||
|
if(board.at(i) == board.at(i + 1) && board.at(i) == board.at(i + 2) && board.at(i) != 0) {
|
||||||
|
*winningCombo = { i, (uint8_t)i + 1, (uint8_t)i + 2 };
|
||||||
|
return board.at(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check columns
|
||||||
|
for(i = 0; i < 3; i++) {
|
||||||
|
if(board.at(i) == board.at(i + 3) && board.at(i) == board.at(i + 6) && board.at(i) != 0) {
|
||||||
|
*winningCombo = { i, (uint8_t)i + 3, (uint8_t)i + 6 };
|
||||||
|
return board.at(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check diagonals
|
||||||
|
if(board.at(0) == board.at(4) && board.at(0) == board.at(8) && board.at(0) != 0) {
|
||||||
|
*winningCombo = {0, 4, 8};
|
||||||
|
return board.at(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(board.at(2) == board.at(4) && board.at(2) == board.at(6) && board.at(2) != 0) {
|
||||||
|
*winningCombo = { 2, 4, 6 };
|
||||||
|
return board.at(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
return TIC_TAC_TOE_EMPTY;
|
||||||
|
}
|
20
src/dawn/games/tictactoe/TicTacToeLogic.hpp
Normal file
20
src/dawn/games/tictactoe/TicTacToeLogic.hpp
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
// Copyright (c) 2023 Dominic Masters
|
||||||
|
//
|
||||||
|
// This software is released under the MIT License.
|
||||||
|
// https://opensource.org/licenses/MIT
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "assert/assert.hpp"
|
||||||
|
|
||||||
|
namespace Dawn {
|
||||||
|
enum TicTacToeTileState {
|
||||||
|
TIC_TAC_TOE_EMPTY,
|
||||||
|
TIC_TAC_TOE_NOUGHT,
|
||||||
|
TIC_TAC_TOE_CROSS
|
||||||
|
};
|
||||||
|
|
||||||
|
enum TicTacToeTileState ticTacToeDetermineWinner(
|
||||||
|
const std::map<uint8_t, enum TicTacToeTileState> board,
|
||||||
|
std::vector<uint8_t> *winningCombo
|
||||||
|
);
|
||||||
|
}
|
@ -66,6 +66,7 @@ int32_t DawnHost::init(DawnGame *game) {
|
|||||||
game->inputManager.bind(INPUT_BIND_NEGATIVE_Y, GLFW_KEY_S);
|
game->inputManager.bind(INPUT_BIND_NEGATIVE_Y, GLFW_KEY_S);
|
||||||
game->inputManager.bind(INPUT_BIND_POSITIVE_Y, GLFW_KEY_W);
|
game->inputManager.bind(INPUT_BIND_POSITIVE_Y, GLFW_KEY_W);
|
||||||
|
|
||||||
|
game->inputManager.bind(INPUT_BIND_MOUSE_CLICK, INPUT_MANAGER_AXIS_MOUSE_0);
|
||||||
game->inputManager.bind(INPUT_BIND_MOUSE_X, INPUT_MANAGER_AXIS_MOUSE_X);
|
game->inputManager.bind(INPUT_BIND_MOUSE_X, INPUT_MANAGER_AXIS_MOUSE_X);
|
||||||
game->inputManager.bind(INPUT_BIND_MOUSE_Y, INPUT_MANAGER_AXIS_MOUSE_Y);
|
game->inputManager.bind(INPUT_BIND_MOUSE_Y, INPUT_MANAGER_AXIS_MOUSE_Y);
|
||||||
|
|
||||||
@ -85,6 +86,7 @@ int32_t DawnHost::init(DawnGame *game) {
|
|||||||
glfwSetFramebufferSizeCallback(this->data->window, &glfwOnResize);
|
glfwSetFramebufferSizeCallback(this->data->window, &glfwOnResize);
|
||||||
glfwSetKeyCallback(this->data->window, &glfwOnKey);
|
glfwSetKeyCallback(this->data->window, &glfwOnKey);
|
||||||
glfwSetCursorPosCallback(this->data->window, &glfwOnCursor);
|
glfwSetCursorPosCallback(this->data->window, &glfwOnCursor);
|
||||||
|
glfwSetMouseButtonCallback(this->data->window, &glfwOnMouseButton);
|
||||||
|
|
||||||
return DAWN_HOST_INIT_RESULT_SUCCESS;
|
return DAWN_HOST_INIT_RESULT_SUCCESS;
|
||||||
}
|
}
|
||||||
@ -195,4 +197,12 @@ void glfwOnCursor(GLFWwindow* window, double xpos, double ypos) {
|
|||||||
(float_t)(ypos / DAWN_HOST->game->renderManager.backBuffer.getHeight()),
|
(float_t)(ypos / DAWN_HOST->game->renderManager.backBuffer.getHeight()),
|
||||||
0, 1
|
0, 1
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void glfwOnMouseButton(GLFWwindow* window, int button, int action, int mods) {
|
||||||
|
if(DAWN_HOST == nullptr) return;
|
||||||
|
assertTrue(window == DAWN_HOST->data->window);
|
||||||
|
|
||||||
|
float_t value = action == GLFW_PRESS ? 1 : 0;
|
||||||
|
DAWN_HOST->game->inputManager.rawInputValues[INPUT_MANAGER_AXIS_MOUSE_0 + button] = value;
|
||||||
}
|
}
|
@ -31,4 +31,5 @@ void glfwOnKey(
|
|||||||
GLFWwindow *window,
|
GLFWwindow *window,
|
||||||
int32_t key, int32_t scancode, int32_t action, int32_t mods
|
int32_t key, int32_t scancode, int32_t action, int32_t mods
|
||||||
);
|
);
|
||||||
void glfwOnCursor(GLFWwindow* window, double xpos, double ypos);
|
void glfwOnCursor(GLFWwindow* window, double xpos, double ypos);
|
||||||
|
void glfwOnMouseButton(GLFWwindow* window, int button, int action, int mods);
|
@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
#define INPUT_MANAGER_AXIS_MOUSE_X -580000
|
#define INPUT_MANAGER_AXIS_MOUSE_X -580000
|
||||||
#define INPUT_MANAGER_AXIS_MOUSE_Y -580001
|
#define INPUT_MANAGER_AXIS_MOUSE_Y -580001
|
||||||
|
#define INPUT_MANAGER_AXIS_MOUSE_0 -590000
|
||||||
|
|
||||||
namespace Dawn {
|
namespace Dawn {
|
||||||
class InputManager : public IInputManager<int32_t> {
|
class InputManager : public IInputManager<int32_t> {
|
||||||
|
@ -24,4 +24,4 @@ add_subdirectory(save)
|
|||||||
set(DIR_GAME_ASSETS games/tictactoe)
|
set(DIR_GAME_ASSETS games/tictactoe)
|
||||||
|
|
||||||
tool_language(locale_en ${DIR_GAME_ASSETS}/locale/en.xml)
|
tool_language(locale_en ${DIR_GAME_ASSETS}/locale/en.xml)
|
||||||
tool_tileset(tileset_xo texture_xo ${DIR_GAME_ASSETS}/xo.png 1 3)
|
tool_tileset(tileset_xo texture_xo ${DIR_GAME_ASSETS}/xo.png 1 4)
|
@ -13,11 +13,22 @@ using namespace Dawn;
|
|||||||
TicTacToeGame::TicTacToeGame(SceneItem *item) : SceneItemComponent(item) {}
|
TicTacToeGame::TicTacToeGame(SceneItem *item) : SceneItemComponent(item) {}
|
||||||
|
|
||||||
void TicTacToeGame::onStart() {
|
void TicTacToeGame::onStart() {
|
||||||
this->tiles = getScene()->findComponents<TicTacToeTile>();
|
// Map tiles by tile number = tile
|
||||||
|
auto tiles = getScene()->findComponents<TicTacToeTile>();
|
||||||
|
auto itTiles = tiles.begin();
|
||||||
|
while(itTiles != tiles.end()) {
|
||||||
|
this->tiles[(*itTiles)->tile] = *itTiles;
|
||||||
|
++itTiles;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Listen
|
||||||
getScene()->eventSceneUpdate.addListener(this, &TicTacToeGame::onSceneUpdate);
|
getScene()->eventSceneUpdate.addListener(this, &TicTacToeGame::onSceneUpdate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TicTacToeGame::onDispose() {
|
||||||
|
getScene()->eventSceneUpdate.removeListener(this, &TicTacToeGame::onSceneUpdate);
|
||||||
|
}
|
||||||
|
|
||||||
void TicTacToeGame::onSceneUpdate() {
|
void TicTacToeGame::onSceneUpdate() {
|
||||||
// Get mouse in screen space.
|
// Get mouse in screen space.
|
||||||
auto mouse = getGame()->inputManager.getAxis2D(INPUT_BIND_MOUSE_X, INPUT_BIND_MOUSE_Y);
|
auto mouse = getGame()->inputManager.getAxis2D(INPUT_BIND_MOUSE_X, INPUT_BIND_MOUSE_Y);
|
||||||
@ -30,17 +41,46 @@ void TicTacToeGame::onSceneUpdate() {
|
|||||||
struct Ray3D ray;
|
struct Ray3D ray;
|
||||||
ray.origin = camera->transform->getWorldPosition();
|
ray.origin = camera->transform->getWorldPosition();
|
||||||
ray.direction = camera->getRayDirectionFromScreenSpace(mouse);
|
ray.direction = camera->getRayDirectionFromScreenSpace(mouse);
|
||||||
std::cout << "World " << ray.origin.x << ", " << ray.origin.y << ", " << ray.origin.z << std::endl;
|
|
||||||
|
|
||||||
|
// Find the hovered tile (if any)
|
||||||
|
TicTacToeTile *hovered = nullptr;
|
||||||
auto results = getPhysics()->raycast3DAll(ray);
|
auto results = getPhysics()->raycast3DAll(ray);
|
||||||
auto itResult = results.begin();
|
auto itResult = results.begin();
|
||||||
while(itResult != results.end()) {
|
while(itResult != results.end()) {
|
||||||
auto result = *itResult;
|
auto result = *itResult;
|
||||||
getScene()->debugRay((struct SceneDebugRay){
|
auto tile = result.collider->item->getComponent<TicTacToeTile>();
|
||||||
.start = result.point,
|
if(tile == nullptr) {
|
||||||
.direction = result.normal,
|
++itResult;
|
||||||
.color = COLOR_BLUE
|
continue;
|
||||||
});
|
}
|
||||||
++itResult;
|
|
||||||
|
hovered = tile;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Now update the state of each tile, also get the state while we are at it
|
||||||
|
std::map<uint8_t, enum TicTacToeTileState> tileMap;
|
||||||
|
|
||||||
|
auto itTiles = tiles.begin();
|
||||||
|
while(itTiles != tiles.end()) {
|
||||||
|
auto t = itTiles->second;
|
||||||
|
|
||||||
|
if(t == hovered) {
|
||||||
|
if(t->state == TIC_TAC_TOE_EMPTY && getGame()->inputManager.isPressed(INPUT_BIND_MOUSE_CLICK)) {
|
||||||
|
t->setState(nextMove);
|
||||||
|
nextMove = nextMove == TIC_TAC_TOE_NOUGHT ? TIC_TAC_TOE_CROSS : TIC_TAC_TOE_NOUGHT;
|
||||||
|
} else if(t->state == TIC_TAC_TOE_EMPTY) {
|
||||||
|
t->hovered = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
t->hovered = false;
|
||||||
|
}
|
||||||
|
tileMap[itTiles->second->tile] = itTiles->second->getState();
|
||||||
|
++itTiles;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine winner
|
||||||
|
std::vector<uint8_t> winningCombo;
|
||||||
|
auto winner = ticTacToeDetermineWinner(tileMap, &winningCombo);
|
||||||
}
|
}
|
@ -11,11 +11,13 @@
|
|||||||
namespace Dawn {
|
namespace Dawn {
|
||||||
class TicTacToeGame : public SceneItemComponent {
|
class TicTacToeGame : public SceneItemComponent {
|
||||||
public:
|
public:
|
||||||
std::vector<TicTacToeTile*> tiles;
|
std::map<int32_t, TicTacToeTile*> tiles;
|
||||||
|
enum TicTacToeTileState nextMove = TIC_TAC_TOE_NOUGHT;
|
||||||
|
|
||||||
TicTacToeGame(SceneItem *item);
|
TicTacToeGame(SceneItem *item);
|
||||||
|
|
||||||
void onStart() override;
|
void onStart() override;
|
||||||
|
void onDispose() override;
|
||||||
|
|
||||||
void onSceneUpdate();
|
void onSceneUpdate();
|
||||||
};
|
};
|
||||||
|
@ -11,6 +11,14 @@ using namespace Dawn;
|
|||||||
TicTacToeTile::TicTacToeTile(SceneItem *item) : SceneItemComponent(item) {
|
TicTacToeTile::TicTacToeTile(SceneItem *item) : SceneItemComponent(item) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TicTacToeTile::onStart() {
|
||||||
|
this->setState(TIC_TAC_TOE_EMPTY);
|
||||||
|
}
|
||||||
|
|
||||||
|
enum TicTacToeTileState TicTacToeTile::getState() {
|
||||||
|
return this->state;
|
||||||
|
}
|
||||||
|
|
||||||
void TicTacToeTile::setState(enum TicTacToeTileState state) {
|
void TicTacToeTile::setState(enum TicTacToeTileState state) {
|
||||||
auto ts = this->item->getComponent<TiledSprite>();
|
auto ts = this->item->getComponent<TiledSprite>();
|
||||||
|
|
||||||
|
@ -6,20 +6,21 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "scene/SceneItemComponent.hpp"
|
#include "scene/SceneItemComponent.hpp"
|
||||||
#include "scene/components/display/TiledSprite.hpp"
|
#include "scene/components/display/TiledSprite.hpp"
|
||||||
|
#include "games/tictactoe/TicTacToeLogic.hpp"
|
||||||
|
|
||||||
namespace Dawn {
|
namespace Dawn {
|
||||||
enum TicTacToeTileState {
|
|
||||||
TIC_TAC_TOE_BLANK,
|
|
||||||
TIC_TAC_TOE_NOUGHT,
|
|
||||||
TIC_TAC_TOE_CROSS
|
|
||||||
};
|
|
||||||
|
|
||||||
class TicTacToeTile : public SceneItemComponent {
|
class TicTacToeTile : public SceneItemComponent {
|
||||||
public:
|
public:
|
||||||
enum TicTacToeTileState state = TIC_TAC_TOE_BLANK;
|
enum TicTacToeTileState state = TIC_TAC_TOE_EMPTY;
|
||||||
|
bool_t hovered = false;
|
||||||
|
uint8_t tile;
|
||||||
|
|
||||||
TicTacToeTile(SceneItem *item);
|
TicTacToeTile(SceneItem *item);
|
||||||
|
|
||||||
|
void onStart() override;
|
||||||
|
|
||||||
|
enum TicTacToeTileState getState();
|
||||||
|
|
||||||
void setState(enum TicTacToeTileState state);
|
void setState(enum TicTacToeTileState state);
|
||||||
};
|
};
|
||||||
}
|
}
|
@ -7,10 +7,12 @@
|
|||||||
#include "input/InputManager.hpp"
|
#include "input/InputManager.hpp"
|
||||||
|
|
||||||
#define INPUT_BIND(n) ((inputbind_t)n)
|
#define INPUT_BIND(n) ((inputbind_t)n)
|
||||||
|
|
||||||
#define INPUT_BIND_ACCEPT INPUT_BIND(1)
|
#define INPUT_BIND_ACCEPT INPUT_BIND(1)
|
||||||
#define INPUT_BIND_NEGATIVE_X INPUT_BIND(2)
|
#define INPUT_BIND_NEGATIVE_X INPUT_BIND(2)
|
||||||
#define INPUT_BIND_POSITIVE_X INPUT_BIND(3)
|
#define INPUT_BIND_POSITIVE_X INPUT_BIND(3)
|
||||||
#define INPUT_BIND_NEGATIVE_Y INPUT_BIND(4)
|
#define INPUT_BIND_NEGATIVE_Y INPUT_BIND(4)
|
||||||
#define INPUT_BIND_POSITIVE_Y INPUT_BIND(5)
|
#define INPUT_BIND_POSITIVE_Y INPUT_BIND(5)
|
||||||
#define INPUT_BIND_MOUSE_X INPUT_BIND(6)
|
#define INPUT_BIND_MOUSE_X INPUT_BIND(6)
|
||||||
#define INPUT_BIND_MOUSE_Y INPUT_BIND(7)
|
#define INPUT_BIND_MOUSE_Y INPUT_BIND(7)
|
||||||
|
#define INPUT_BIND_MOUSE_CLICK INPUT_BIND(8)
|
@ -17,10 +17,7 @@ namespace Dawn {
|
|||||||
|
|
||||||
void stage() override {
|
void stage() override {
|
||||||
camera = Camera::create(this);
|
camera = Camera::create(this);
|
||||||
// camera->transform->lookAt(glm::vec3(0, 0, 5), glm::vec3(0, 0, 0));
|
camera->transform->lookAt(glm::vec3(0, 0, 8), glm::vec3(0, 0, 0));
|
||||||
// camera->type = CAMERA_TYPE_ORTHONOGRAPHIC;
|
|
||||||
// camera->transform->lookAt(glm::vec3(1, 2, 3), glm::vec3(0, 0, 0));
|
|
||||||
camera->transform->lookAt(glm::vec3(0, 0, 3), glm::vec3(0, 0, 0));
|
|
||||||
|
|
||||||
float_t s = 2.0f;
|
float_t s = 2.0f;
|
||||||
camera->orthoTop = s;
|
camera->orthoTop = s;
|
||||||
@ -33,12 +30,12 @@ namespace Dawn {
|
|||||||
auto gameItem = this->createSceneItem();
|
auto gameItem = this->createSceneItem();
|
||||||
auto game = gameItem->addComponent<TicTacToeGame>();
|
auto game = gameItem->addComponent<TicTacToeGame>();
|
||||||
|
|
||||||
int32_t i = 0;
|
uint8_t i = 0;
|
||||||
for(int32_t x = -1; x <= 1; x++) {
|
for(int32_t x = -1; x <= 1; x++) {
|
||||||
for(int32_t y = -1; y <= 1; y++) {
|
for(int32_t y = -1; y <= 1; y++) {
|
||||||
auto tile = TicTacToeTilePrefab::create(this);
|
auto tile = TicTacToeTilePrefab::create(this);
|
||||||
tile->transform.setLocalPosition(glm::vec3(x * 1.25f, y * 1.25f, 0));
|
tile->transform.setLocalPosition(glm::vec3(x * 1, y * 1, 0));
|
||||||
// tile->ticTacToe->setState(i % 2 == 0 ? TIC_TAC_TOE_CROSS : TIC_TAC_TOE_NOUGHT);
|
tile->ticTacToe->tile = i++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user