60/100 Dias de Golang - Jogo em UDP - Parte 6
Table of Contents
#
Jogo em UDP - Parte 6
Para fechar o jogo, vamos criar um objetivo. Qual player chegar primeiro na coordenada X, Y vence. O que vamos ter que alterar: fazer uma verificação se algum player está na posição de vitória, enviar uma mensagem de vitória depois que alguém alcançar a posição e travar a movimentação dos players após a vitória.
Vamos primeiro adicionar nossas variáveis:
var goalPosition = [2]int{arenaRows - 2, arenaCols - 2}
var gameOver = false
var winner string
Vamos adicionar uma verificação, caso gameOver seja verdade, não enviamos mais os comando para o canal
if !gameOver {
commands <- Command{PlayerID: playerID, Action: msg}
}
E a verificação ficará de responsabilidade da goroutine que trata as informações recebidas do usuário:
if player.Y == goalPosition[0] && player.X == goalPosition[1] {
gameOver = true
winner = string(player.Char)
fmt.Printf("Jogador %s venceu!\n", winner)
}
E para fechar, colocamos um “X” no grid e adicionamos uma mensagem do jogador vencedor:
grid[goalPosition[0]][goalPosition[1]] = 'X'
if gameOver {
sb.WriteString(fmt.Sprintf("=== JOGO ENCERRADO! VENCEDOR: %s ===\n", winner))
} else {
sb.WriteString("=== BATALHA EM ANDAMENTO ===\n")
}
Veja como fica o código completo:
package main
import (
"fmt"
"net"
"strings"
"sync"
"time"
)
const arenaRows = 20
const arenaCols = 60
var grid = make([][]rune, arenaRows)
var goalPosition = [2]int{arenaRows - 2, arenaCols - 2}
var gameOver = false
var winner string
type Player struct {
ID string
Char rune
X, Y int
Addr *net.UDPAddr
}
var players = make(map[string]*Player)
var playersMutex sync.Mutex
var commands = make(chan Command, 100)
type Command struct {
PlayerID string
Action string
}
func main() {
addr, _ := net.ResolveUDPAddr("udp", "0.0.0.0:8080")
conn, _ := net.ListenUDP("udp", addr)
defer conn.Close()
fmt.Println("Servidor iniciado na porta 8080...")
go func() {
buf := make([]byte, 1024)
for {
n, clientAddr, _ := conn.ReadFromUDP(buf)
msg := strings.TrimSpace(string(buf[:n]))
playerID := clientAddr.String()
playersMutex.Lock()
if _, exists := players[playerID]; !exists {
players[playerID] = &Player{
ID: playerID,
Char: rune('A' + len(players)%26),
X: 1,
Y: 1,
Addr: clientAddr,
}
fmt.Printf("Novo jogador %s (%c)\n", playerID, players[playerID].Char)
}
playersMutex.Unlock()
if !gameOver {
commands <- Command{PlayerID: playerID, Action: msg}
}
}
}()
go func() {
for cmd := range commands {
if gameOver {
continue
}
playersMutex.Lock()
player := players[cmd.PlayerID]
switch cmd.Action {
case "w":
if player.Y > 0 && grid[player.Y-1][player.X] != '*' {
player.Y--
}
case "s":
if player.Y < arenaRows-1 && grid[player.Y+1][player.X] != '*' {
player.Y++
}
case "a":
if player.X > 0 && grid[player.Y][player.X-1] != '*' {
player.X--
}
case "d":
if player.X < arenaCols-1 && grid[player.Y][player.X+1] != '*' {
player.X++
}
}
if player.Y == goalPosition[0] && player.X == goalPosition[1] {
gameOver = true
winner = string(player.Char)
fmt.Printf("Jogador %s venceu!\n", winner)
}
playersMutex.Unlock()
}
}()
ticker := time.NewTicker(200 * time.Millisecond)
for range ticker.C {
arena := renderArena()
sendArena(conn, arena)
}
}
func renderArena() string {
for i := 0; i < arenaRows; i++ {
grid[i] = make([]rune, arenaCols)
for j := range grid[i] {
if i == 0 || i == arenaRows-1 || j == 0 || j == arenaCols-1 {
grid[i][j] = '*'
} else {
grid[i][j] = '.'
}
}
}
grid[goalPosition[0]][goalPosition[1]] = 'X'
playersMutex.Lock()
for _, p := range players {
grid[p.Y][p.X] = p.Char
}
playersMutex.Unlock()
var sb strings.Builder
if gameOver {
sb.WriteString(fmt.Sprintf("=== JOGO ENCERRADO! VENCEDOR: %s ===\n", winner))
} else {
sb.WriteString("=== BATALHA EM ANDAMENTO ===\n")
}
for _, row := range grid {
sb.WriteString(string(row))
sb.WriteRune('\n')
}
return sb.String()
}
func sendArena(conn *net.UDPConn, arena string) {
playersMutex.Lock()
for _, p := range players {
conn.WriteToUDP([]byte(arena), p.Addr)
}
playersMutex.Unlock()
}