Complete most of networked tick-tac-toe. Finish the questions to ponder!
This commit is contained in:
@@ -12,7 +12,7 @@
|
|||||||
// A thourough rework is necessary for SFML 3.0.
|
// A thourough rework is necessary for SFML 3.0.
|
||||||
|
|
||||||
enum GameMessageType : unsigned char {
|
enum GameMessageType : unsigned char {
|
||||||
JOIN_GAME = 0x01, PLACE_TOKEN = 0x02
|
JOIN_GAME = 0x01, PLACE_TOKEN = 0x02, START_GAME = 0x03, GAME_OVER = 0x04
|
||||||
};
|
};
|
||||||
|
|
||||||
enum Token : unsigned char {
|
enum Token : unsigned char {
|
||||||
@@ -24,13 +24,26 @@ public:
|
|||||||
GameServer(unsigned short tcp_port) :
|
GameServer(unsigned short tcp_port) :
|
||||||
m_tcp_port(tcp_port) {}
|
m_tcp_port(tcp_port) {}
|
||||||
|
|
||||||
|
|
||||||
|
bool send_start_game_to_clients() {
|
||||||
|
char buf[1] = { START_GAME };
|
||||||
|
std::cout << "Starting the game..." << std::endl;
|
||||||
|
return broadcast_message(buf, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool send_game_over_to_clients() {
|
||||||
|
char buf[1] = { GAME_OVER };
|
||||||
|
std::cout << "Game Over!" << std::endl;
|
||||||
|
return broadcast_message(buf, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
// Binds to a port and then loops around. For every client that connects,
|
// Binds to a port and then loops around. For every client that connects,
|
||||||
// we start a new thread receiving their messages.
|
// we start a new thread receiving their messages.
|
||||||
void tcp_start()
|
void tcp_start()
|
||||||
{
|
{
|
||||||
// BINDING
|
// BINDING
|
||||||
sf::TcpListener listener;
|
sf::TcpListener listener;
|
||||||
sf::Socket::Status status = listener.listen(m_tcp_port, sf::IpAddress("A.B.C.D"));
|
sf::Socket::Status status = listener.listen(m_tcp_port, sf::IpAddress("152.105.66.120")); // Make sure to change this!
|
||||||
if (status != sf::Socket::Status::Done)
|
if (status != sf::Socket::Status::Done)
|
||||||
{
|
{
|
||||||
std::cerr << "Error binding listener to port" << std::endl;
|
std::cerr << "Error binding listener to port" << std::endl;
|
||||||
@@ -71,6 +84,10 @@ public:
|
|||||||
// Slight pause to ensure the all threads have started
|
// Slight pause to ensure the all threads have started
|
||||||
// --------------------------------------------------------------
|
// --------------------------------------------------------------
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(250));
|
std::this_thread::sleep_for(std::chrono::milliseconds(250));
|
||||||
|
|
||||||
|
if(!send_start_game_to_clients()) {
|
||||||
|
std::cerr << "Could not start game. One or both players did not recieve START_GAME" << std::endl;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -79,10 +96,11 @@ public:
|
|||||||
// The connection is closed automatically when the listener object is out of scope.
|
// The connection is closed automatically when the listener object is out of scope.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
unsigned short m_tcp_port;
|
unsigned short m_tcp_port;
|
||||||
unsigned short m_player_count { 0 };
|
unsigned short m_player_count { 0 };
|
||||||
|
unsigned short m_turns_played { 0 };
|
||||||
|
int board[3][3];
|
||||||
|
|
||||||
std::vector<sf::TcpSocket*> m_clients;
|
std::vector<sf::TcpSocket*> m_clients;
|
||||||
std::mutex m_clients_mutex;
|
std::mutex m_clients_mutex;
|
||||||
@@ -144,6 +162,12 @@ private:
|
|||||||
debug_message(payload);
|
debug_message(payload);
|
||||||
|
|
||||||
broadcast_message(payload, client);
|
broadcast_message(payload, client);
|
||||||
|
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(250));
|
||||||
|
|
||||||
|
if(++m_turns_played == 9) {
|
||||||
|
send_game_over_to_clients();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -194,6 +218,8 @@ private:
|
|||||||
switch(messageType) {
|
switch(messageType) {
|
||||||
case JOIN_GAME: return 2;
|
case JOIN_GAME: return 2;
|
||||||
case PLACE_TOKEN: return sizeof(int) * 2 + 2;
|
case PLACE_TOKEN: return sizeof(int) * 2 + 2;
|
||||||
|
case START_GAME: return 1;
|
||||||
|
case GAME_OVER: return 1;
|
||||||
default: return 0;
|
default: return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -222,7 +248,7 @@ private:
|
|||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
GameServer server(4300);
|
GameServer server(4331);
|
||||||
|
|
||||||
server.tcp_start();
|
server.tcp_start();
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,9 @@ interface Deserializable {
|
|||||||
|
|
||||||
enum class GameMessageType(val id: Byte) {
|
enum class GameMessageType(val id: Byte) {
|
||||||
JOIN_GAME(1),
|
JOIN_GAME(1),
|
||||||
PLACE_TOKEN(2);
|
PLACE_TOKEN(2),
|
||||||
|
START_GAME(3),
|
||||||
|
GAME_OVER(4);
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun fromByte(id: Byte) = entries.first { it.id == id }
|
fun fromByte(id: Byte) = entries.first { it.id == id }
|
||||||
@@ -23,6 +25,9 @@ sealed class GameMessage(val type: GameMessageType) : Serializable {
|
|||||||
|
|
||||||
override fun serialize() = byteArrayOf(type.id)
|
override fun serialize() = byteArrayOf(type.id)
|
||||||
|
|
||||||
|
object StartGameMessage : GameMessage(GameMessageType.START_GAME)
|
||||||
|
object GameOverMessage : GameMessage(GameMessageType.GAME_OVER)
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------------------
|
||||||
data class JoinGameMessage(val token: Token) : GameMessage(GameMessageType.JOIN_GAME) {
|
data class JoinGameMessage(val token: Token) : GameMessage(GameMessageType.JOIN_GAME) {
|
||||||
|
|
||||||
|
|||||||
@@ -20,11 +20,11 @@ class Main : KtxGame<KtxScreen>() {
|
|||||||
override fun create() {
|
override fun create() {
|
||||||
KtxAsync.initiate()
|
KtxAsync.initiate()
|
||||||
|
|
||||||
networkHandler = NetworkHandler("A.B.C.D", 4300, serverChannel, clientChannel)
|
networkHandler = NetworkHandler("152.105.66.120", 4331, serverChannel, clientChannel)
|
||||||
|
|
||||||
addScreen(FirstScreen(this, clientChannel, serverChannel))
|
addScreen(FirstScreen(this, clientChannel, serverChannel))
|
||||||
|
|
||||||
addScreen(GameOverScreen())
|
addScreen(GameOverScreen(0))
|
||||||
|
|
||||||
setScreen<FirstScreen>()
|
setScreen<FirstScreen>()
|
||||||
|
|
||||||
|
|||||||
@@ -153,6 +153,10 @@ class NetworkHandler(
|
|||||||
GameMessageType.JOIN_GAME -> GameMessage.JoinGameMessage.deserialize(this)
|
GameMessageType.JOIN_GAME -> GameMessage.JoinGameMessage.deserialize(this)
|
||||||
|
|
||||||
GameMessageType.PLACE_TOKEN -> GameMessage.PlaceTokenMessage.deserialize(this)
|
GameMessageType.PLACE_TOKEN -> GameMessage.PlaceTokenMessage.deserialize(this)
|
||||||
|
|
||||||
|
GameMessageType.START_GAME -> GameMessage.StartGameMessage
|
||||||
|
|
||||||
|
GameMessageType.GAME_OVER -> GameMessage.GameOverMessage
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -27,6 +27,9 @@ class FirstScreen(
|
|||||||
private val receiveChannel: ReceiveChannel<GameMessage>,
|
private val receiveChannel: ReceiveChannel<GameMessage>,
|
||||||
private val sendChannel: SendChannel<GameMessage>
|
private val sendChannel: SendChannel<GameMessage>
|
||||||
) : KtxScreen, InputProcessor {
|
) : KtxScreen, InputProcessor {
|
||||||
|
private var gameStarted = false
|
||||||
|
|
||||||
|
private var gameOver = false
|
||||||
|
|
||||||
private val batch = SpriteBatch()
|
private val batch = SpriteBatch()
|
||||||
|
|
||||||
@@ -56,6 +59,12 @@ class FirstScreen(
|
|||||||
override fun render(delta: Float) {
|
override fun render(delta: Float) {
|
||||||
clearScreen(red = 0.7f, green = 0.7f, blue = 0.7f)
|
clearScreen(red = 0.7f, green = 0.7f, blue = 0.7f)
|
||||||
|
|
||||||
|
if (gameOver) {
|
||||||
|
game.setScreen<GameOverScreen>()
|
||||||
|
disposeSafely()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
camera.update()
|
camera.update()
|
||||||
|
|
||||||
batch.use { board.draw(it) }
|
batch.use { board.draw(it) }
|
||||||
@@ -87,6 +96,18 @@ class FirstScreen(
|
|||||||
localPlayerTurn = true
|
localPlayerTurn = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
is GameMessage.StartGameMessage -> {
|
||||||
|
Gdx.app.log(TAG, "The Server has started the game")
|
||||||
|
|
||||||
|
gameStarted = true
|
||||||
|
}
|
||||||
|
|
||||||
|
is GameMessage.GameOverMessage -> {
|
||||||
|
Gdx.app.log(TAG, "The Server has sent Game Over")
|
||||||
|
|
||||||
|
gameStarted = false
|
||||||
|
gameOver = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Gdx.app.log(TAG, "THE MESSAGE RECEIVED IS: $gm")
|
Gdx.app.log(TAG, "THE MESSAGE RECEIVED IS: $gm")
|
||||||
@@ -114,7 +135,7 @@ class FirstScreen(
|
|||||||
button: Int
|
button: Int
|
||||||
): Boolean {
|
): Boolean {
|
||||||
|
|
||||||
if(!localPlayerTurn)
|
if(!gameStarted || !localPlayerTurn)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
val col = ((screenX.toFloat() / Gdx.graphics.width) * 3).toInt()
|
val col = ((screenX.toFloat() / Gdx.graphics.width) * 3).toInt()
|
||||||
|
|||||||
@@ -6,16 +6,25 @@ import ktx.app.KtxScreen
|
|||||||
import ktx.app.clearScreen
|
import ktx.app.clearScreen
|
||||||
import ktx.graphics.use
|
import ktx.graphics.use
|
||||||
|
|
||||||
class GameOverScreen : KtxScreen {
|
class GameOverScreen(private val winType: Int) : KtxScreen {
|
||||||
|
private var label = winType.toString()
|
||||||
private val font = BitmapFont()
|
private val font = BitmapFont()
|
||||||
private val batch = SpriteBatch()
|
private val batch = SpriteBatch()
|
||||||
|
|
||||||
|
override fun show() {
|
||||||
|
when (winType) {
|
||||||
|
0 -> label = "You Win!"
|
||||||
|
1 -> label = "You Lose."
|
||||||
|
2 -> label = "Game Over!"
|
||||||
|
else -> "Invalid type!"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun render(delta: Float) {
|
override fun render(delta: Float) {
|
||||||
clearScreen(red = 0.7f, green = 0.7f, blue = 0.7f)
|
clearScreen(red = 0.7f, green = 0.7f, blue = 0.7f)
|
||||||
|
|
||||||
batch.use {
|
batch.use {
|
||||||
font.draw(it, "Game Over!", 10f, 10f)
|
font.draw(it, label, 10f, 10f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user