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技术客栈