Go是可以做游戏服务器的相信大家都知道,今天呢给大家分享一下go做游戏服务器的实战
需求说明:
游戏场景:
玩家可以在一个简单的场景地图上移动。
玩家角色:
每个玩家都有一个独特的名称,并且可以在地图上自由移动。
实时通信:
玩家之间可以实时聊天,并且在游戏中看到其他玩家的移动和聊天信息。
移动限制:
玩家不能走出地图边界。
技术实现:
使用TCP协议进行网络通信。
使用goroutines处理玩家连接和消息处理,并使用通道进行消息传递。
使用简单的文本地图表示游戏场景,并实现玩家移动逻辑。使用基于命令行的客户端进行连接和操作。
有了需求就开干
游戏服务器:server.go
package main
import (
"fmt"
"net"
"strings"
)
type Player struct {
Name string // 玩家名字
Position Position // 玩家位置
Conn net.Conn // 玩家连接
}
type Position struct {
X, Y int // X和Y坐标
}
type GameServer struct {
Players []*Player // 当前连接的所有玩家
Messages chan string // 消息通道,用于向所有玩家发送消息
}
// 创建一个新的游戏服务器
func NewGameServer() *GameServer {
return &GameServer{
Players: make([]*Player, 0),
Messages: make(chan string),
}
}
// 广播消息给所有玩家
func (gs *GameServer) Broadcast(message string) {
for _, player := range gs.Players {
player.Conn.Write([]byte(message + "\n"))
}
}
// 处理玩家连接
func (gs *GameServer) HandlePlayer(conn net.Conn) {
defer conn.Close()
// 读取玩家名字
buffer := make([]byte, 1024)
n, err := conn.Read(buffer)
if err != nil {
fmt.Println("读取名字错误:", err)
return
}
playerName := strings.TrimSpace(string(buffer[:n]))
// 广播玩家加入游戏的消息给所有玩家
gs.Broadcast(fmt.Sprintf("\n 玩家 %s 加入了游戏。", playerName))
// 创建新的玩家并加入到玩家列表中
player := &Player{
Name: playerName,
Conn: conn,
}
gs.Players = append(gs.Players, player)
// 处理玩家的消息
for {
buffer := make([]byte, 1024)
n, err := conn.Read(buffer)
if err != nil {
// 玩家离开游戏的处理
fmt.Printf("\n 玩家 %s 离开了游戏。\n", playerName)
gs.Broadcast(fmt.Sprintf("\n 玩家 %s 离开了游戏。", playerName))
gs.removePlayer(player)
return
}
// 处理玩家发送的移动指令
message := string(buffer[:n])
if strings.HasPrefix(message, "/move") {
direction := strings.TrimSpace(strings.TrimPrefix(message, "/move"))
gs.MovePlayer(player, direction)
}
}
}
// 移动玩家
func (gs *GameServer) MovePlayer(player *Player, direction string) {
switch direction {
case "上":
player.Position.Y++
case "下":
player.Position.Y--
case "左":
player.Position.X--
case "右":
player.Position.X++
}
// 广播玩家移动的消息给所有玩家
gs.Broadcast(fmt.Sprintf("玩家 %s 移动到了 (%d, %d) 处", player.Name, player.Position.X, player.Position.Y))
}
// 移除离线的玩家
func (gs *GameServer) removePlayer(player *Player) {
for i, p := range gs.Players {
if p == player {
gs.Players = append(gs.Players[:i], gs.Players[i+1:]...)
break
}
}
}
func main() {
// 创建一个新的游戏服务器
gameServer := NewGameServer()
// 监听端口8080
listener, err := net.Listen("tcp", ":8080")
if err != nil {
fmt.Println("监听错误:", err)
return
}
defer listener.Close()
fmt.Println("服务器已启动,监听在端口 8080")
// 处理客户端连接
for {
conn, err := listener.Accept()
if err != nil {
fmt.Println("连接接受错误:", err)
continue
}
// 启动一个新的协程处理玩家连接
go gameServer.HandlePlayer(conn)
}
}
1: 创建了一个 Player 结构体来表示玩家,其中包含名字、位置和连接信息。
2: 创建了一个 GameServer 结构体来表示游戏服务器,其中包含了玩家列表和消息通道。
3:实现了 NewGameServer() 函数用于创建一个新的游戏服务器。
4:实现了 Broadcast() 方法用于向所有玩家发送消息。
5:实现了 HandlePlayer() 方法来处理玩家连接,包括读取玩家名字、处理玩家消息、处理玩家离线等逻辑。
6:实现了 MovePlayer() 方法来处理玩家移动,包括更新玩家位置和向所有玩家广播玩家移动的消息。
7:实现了 removePlayer() 方法来移除离线的玩家。
8:在 main() 函数中创建了一个新的游戏服务器,并监听端口8080,等待客户端连接,每当有新的客户端连接时,会启动一个新的协程来处理玩家连接。
玩家客户端 - client.go
package main
import (
"bufio"
"fmt"
"net"
"os"
"strings"
)
func main() {
// 连接到服务器
conn, err := net.Dial("tcp", "localhost:8080")
if err != nil {
fmt.Println("连接错误:", err)
return
}
defer conn.Close()
// 从标准输入读取玩家名字并发送给服务器
reader := bufio.NewReader(os.Stdin)
fmt.Print("请输入您的名字:")
name, _ := reader.ReadString('\n')
name = strings.TrimSpace(name) // 去除名字两端的空白字符
conn.Write([]byte(name + "\n"))
// 启动一个协程用于持续接收服务器的消息并打印到标准输出
go func() {
scanner := bufio.NewScanner(conn)
for scanner.Scan() {
fmt.Println(scanner.Text())
}
}()
// 循环读取玩家的移动指令并发送给服务器
for {
fmt.Print("输入指令(例如,/move 上,/move 下,/move 左,/move 右):")
command, _ := reader.ReadString('\n')
conn.Write([]byte(command))
}
}
1:连接到指定的服务器地址和端口(这里是 localhost:8080)。
2:从标准输入读取玩家的名字,并将其发送给服务器。
3:启动一个协程来持续接收服务器发送的消息,并将其打印到标准输出。
4:在一个无限循环中,从标准输入读取玩家的移动指令,并将其发送给服务器。
客户端可以启动多个client2.go
运行游戏服务器和多个玩家客户端
玩家1: 乔峰
玩家2: 张无忌
到这里其实已经实现了一个简易的游戏服务器,每个玩家都有一个独特的名称,并且可以在地图上自由移动。玩家之间可以实时聊天,并且在游戏中看到其他玩家的移动和聊天信息。如果在配合移动端或者web端 就可以实现游戏场景的效果
转自: Golang技术客栈