рдЬрд╛рдУ рдФрд░ рдХреИрдирд╡рд╛рд╕ [рд╕рд░реНрд╡рд░] рдкрд░ NanoMMO


рдкреНрд░рддреНрдпреЗрдХ рдкреНрд░реЛрдЧреНрд░рд╛рдорд░ рдХреЛ рдЕрдкрдирд╛ рд╕реНрд╡рдпрдВ рдХрд╛ рд╕реЗрдореА , рдлреНрд░реЗрдорд╡рд░реНрдХ , mmorpg рд▓рд┐рдЦрдирд╛ рдЪрд╛рд╣рд┐рдПред рд╡рд╣реА рд╣рдо рдХрд░реЗрдВрдЧреЗред
рдбреЗрдореЛ

conventionalities

рд╕рд╛рдордЧреНрд░реА рдХреЛ рд╕рдордЭрдиреЗ рдХреЗ рд▓рд┐рдП, рдЖрдкрдХреЛ рдпрд╛ рддреЛ рдЧреЛ рдпрд╛ рдХрд┐рд╕реА рдЕрдиреНрдп рд╕реА-рд▓рд╛рдЗрдХ рднрд╛рд╖рд╛ рдХреЛ рдЬрд╛рдирдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ, рдФрд░ рдпрд╣ рднреА рдХрд▓реНрдкрдирд╛ рдХрд░реЗрдВ рдХрд┐ js рдореЗрдВ рдХреИрд╕реЗ рд▓рд┐рдЦреЗрдВред
рдЗрдВрдЯреНрд░реЛ рдЯреВрд░ рдкрд░ рдЬрд╛рдПрдВ
рдХреИрдирд╡рд╛рд╕ рдЯреНрдпреВрдЯреЛрд░рд┐рдпрд▓
рдЗрд╕ рд╕рд╛рдордЧреНрд░реА рдХрд╛ рдореБрдЦреНрдп рдЙрджреНрджреЗрд╢реНрдп рдореЗрд░реЗ рдЕрдкрдиреЗ рд╡рд┐рдЪрд╛рд░реЛрдВ рдХреЛ рдХреНрд░рдо рдореЗрдВ рд░рдЦрдирд╛ рд╣реИред рдХрд┐рд╕реА рднреА рдорд╛рдорд▓реЗ рдореЗрдВ рдЖрдкрдХреЛ рдпрд╣рд╛рдВ рдХреЗ рдкреВрд░реНрд╡рдЧрд╛рдореА рдХреЛ рдПрдХ рдЙрджрд╛рд╣рд░рдг рдХреЗ рд░реВрдк рдореЗрдВ рдирд╣реАрдВ рдорд╛рдирдирд╛ тАЛтАЛрдЪрд╛рд╣рд┐рдП, рдЬрд╣рд╛рдВ рд╕реЗ рдЖрдк рдмрд┐рдирд╛ рд╕реЛрдЪреЗ рд╕рдордЭреЗ рдХреЙрдкреА рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред

рд╕рдорд╕реНрдпрд╛ рдХрд╛ рдмрдпрд╛рди

рд╕рдмрд╕реЗ рдкрд╣рд▓реЗ, рдХрд╛рд░реНрдп рдкрд░ рдирд┐рд░реНрдгрдп рд▓реЗрддреЗ рд╣реИрдВред рдЖрдкрдХреЛ рдЫреЛрдЯрд╛ рд╢реБрд░реВ рдХрд░рдирд╛ рдЪрд╛рд╣рд┐рдП, рдЗрд╕рд▓рд┐рдП рд╣рдо рдПрдХ рдЕрддреНрдпрдВрдд рд╕рд░рд▓реАрдХреГрдд рдХреНрд▓рд╛рдЗрдВрдЯ рд▓рд┐рдЦреЗрдВрдЧреЗ рдЬреЛ рдХреЗрд╡рд▓ рд╕рд░реНрд╡рд░ рд╕реЗ рд╡рд░реНрдг рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ, рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдФрд░ рдбреЗрдЯрд╛ рднреЗрдЬрдиреЗ рдореЗрдВ рд╕рдХреНрд╖рдо рд╣реЛрдЧрд╛ред рдмрджрд▓реЗ рдореЗрдВ, рдХреНрд▓рд╛рдЗрдВрдЯ рдХреЗ рд▓рд┐рдП рдЖрд╡рд╢реНрдпрдХ рд╕рднреА рдЧреЗрдо рд▓реЙрдЬрд┐рдХ рдХреЗ рд▓рд┐рдП рд╕рд░реНрд╡рд░ рдЬрд┐рдореНрдореЗрджрд╛рд░ рд╣реЛрдЧрд╛ред

рдХреНрд▓рд╛рдЗрдВрдЯ рдФрд░ рд╕рд░реНрд╡рд░ рдХреЗ рдмреАрдЪ рдХрд╛ рдХрдиреЗрдХреНрд╢рди рд╡реЗрдм рд╕реЙрдХреЗрдЯреНрд╕ рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдЖрдпреЛрдЬрд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛, рдЬрд┐рд╕рдХрд╛ рдЕрд░реНрде рд╣реИ рдХрд┐ рд╣рдо рдХреЗрд╡рд▓ рд╕реНрдЯреНрд░рд┐рдВрдЧреНрд╕ рдХреЛ рдкреНрд░рд╕рд╛рд░рд┐рдд рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ, рдФрд░ рд╣рдореЗрдВ рдЗрддреНрдореАрдирд╛рди рд╕реЗ рдЯреАрд╕реАрдкреА рднреА рд▓рдЧрд╛рдирд╛ рд╣реЛрдЧрд╛ред рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдФрд░ рдбрд┐рдмрдЧрд┐рдВрдЧ рдореЗрдВ рдЖрд╕рд╛рдиреА рдХреЗ рд▓рд┐рдП, рд╣рдо рд╕рдВрджреЗрд╢ рдХреЛ рд╕рдВрджреЗрд╢ рдореЗрдВ рд▓рд┐рдЦреЗрдВрдЧреЗред

рдореЗрд░реЗ рджрд┐рдорд╛рдЧ рдореЗрдВ рдЖрдпрд╛ рдкрд╣рд▓рд╛ рд╡рд┐рдЪрд╛рд░ рдкрд╣рд▓реЗ рдПрдХ рдХреНрд▓рд╛рдЗрдВрдЯ рд▓рд┐рдЦрдирд╛ рдерд╛, рдЬрд┐рд╕рдХреА рдорджрдж рд╕реЗ рдмрд╛рдж рдореЗрдВ рд╕рд░реНрд╡рд░ рдХрд╛ рдкрд░реАрдХреНрд╖рдг рдХрд░рдирд╛ рд╕рдВрднрд╡ рд╣реЛрдЧрд╛ред рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ, рдЗрд╕рд▓рд┐рдП рдореИрдВрдиреЗ рдХрд┐рдпрд╛ред рд▓реЗрдХрд┐рди рд╣рдо рдЕрд▓рдЧ рддрд░рд╣ рд╕реЗ рдХрд╛рд░реНрдп рдХрд░реЗрдВрдЧреЗ; рддрдм рдпрд╣ рд╕реНрдкрд╖реНрдЯ рд╣реЛ рдЬрд╛рдПрдЧрд╛ рдХрд┐ рдХреНрдпреЛрдВред

рд╕рд░реНрд╡рд░

рд╣рдорд╛рд░рд╛ рд╕рд░реНрд╡рд░ рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдХрд╛рд░реНрдп рдХрд░реЗрдЧрд╛:
рджреБрдирд┐рдпрд╛ рд╕реЗ рд╣рдорд╛рд░рд╛ рддрд╛рддреНрдкрд░реНрдп рдЬреБрдбрд╝реЗ рд╣реБрдП рдкрд╛рддреНрд░реЛрдВ рдФрд░ рдЕрдзрд┐рдХ рдХреА рд╕реВрдЪреА рд╕реЗ рд╣реЛрдЧрд╛ред рдХреЛрдИ рдХрд╛рд░реНрдб рдирд╣реАрдВ, рдХреЛрдИ рдмрд╛рдзрд╛ рдирд╣реАрдВ - рдХреЗрд╡рд▓ рдЦрд┐рд▓рд╛рдбрд╝реАред рдкрд╛рддреНрд░реЛрдВ рдХреЛ рдПрдХ рдирд┐рд╢реНрдЪрд┐рдд рдмрд┐рдВрджреБ рдкрд░ рдПрдХ рдирд┐рд╢реНрдЪрд┐рдд рдЧрддрд┐ рд╕реЗ рд╕реНрдерд╛рдирд╛рдВрддрд░рд┐рдд рдХрд░рдиреЗ рдореЗрдВ рд╕рдХреНрд╖рдо рд╣реЛрдиреЗ рд╡рд╛рд▓реА рдПрдХрдорд╛рддреНрд░ рдЪреАрдЬ рд╣реЛрдЧреАред
рддрдм рд╣рдорд╛рд░реЗ рдЪрд░рд┐рддреНрд░ рдХреА рд╕рдВрд░рдЪрдирд╛ рдЗрд╕ рддрд░рд╣ рджрд┐рдЦрд╛рдИ рджреЗрдЧреА:
/* point.go && character.go */ ... type Point struct { X, Y float64 } ... type Character struct { Pos, Dst Point //     Angle float64 //  Speed uint //  Name string } ... 

рдЖрдкрдХреЛ рдпрд╛рдж рджрд┐рд▓рд╛ рджреВрдВ рдХрд┐ рдЬрд╛рдиреЗ рдореЗрдВ, рдПрдХ рдХреИрдкрд┐рдЯрд▓ рд▓реЗрдЯрд░ рдХреЗ рд╕рд╛рде рд▓рд┐рдЦреЗ рдЧрдП рдлрд╝реАрд▓реНрдб рдПрдХреНрд╕рдкреЛрд░реНрдЯ рдХрд┐рдП рдЬрд╛рддреЗ рд╣реИрдВ (рд╕рд╛рд░реНрд╡рдЬрдирд┐рдХ), рдФрд░ рдЬрдм рдХрд┐рд╕реА рдСрдмреНрдЬреЗрдХреНрдЯ рдХреЛ рд╕реАрд░рд┐рдпрд▓рд╛рдЗрдЬрд╝ рдХрд░рддреЗ рд╣реИрдВ, рддреЛ рдХреЗрд╡рд▓ рдПрдХреНрд╕рдкреЛрд░реНрдЯ рдХрд┐рдП рдЧрдП рдлрд╝реАрд▓реНрдбреНрд╕ рдХреЛ рд╣реА json рдореЗрдВ рдЬреЛрдбрд╝рд╛ рдЬрд╛рддрд╛ рд╣реИред ( рдореИрдВрдиреЗ рдХрдИ рдмрд╛рд░ рдЗрд╕ рд░реЗрдХ рдкрд░ рдХрджрдо рд░рдЦрд╛, рд╕рдордЭ рдореЗрдВ рдирд╣реАрдВ рдЖ рд░рд╣рд╛ рдерд╛ рдХрд┐ рдкреНрд░рддреАрдд рд╣реЛрддрд╛ рд╣реИ рдХрд┐ рд╕рд╣реА рдХреЛрдб рдХреНрдпреЛрдВ рдХрд╛рдо рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИред рдпрд╣ рдкрддрд╛ рдЪрд▓рд╛ рд╣реИ рдХрд┐ рдЦреЗрддреЛрдВ рдХреЛ рдПрдХ рдЫреЛрдЯреЗ рд╕реЗ рдкрддреНрд░ рдХреЗ рд╕рд╛рде рд▓рд┐рдЦрд╛ рдЧрдпрд╛ рдерд╛ )ред

рдХреНрд▓рд╛рдЗрдВрдЯ рдкрд░, рд╣рдореЗрдВ рдбреЗрдЯрд╛ рдХреЛ рд╕рд┐рдВрдХреНрд░рдирд╛рдЗрдЬрд╝ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрдЧреАред рд╕рднреА рд╡рд░реНрддрдорд╛рди рдФрд░ рднрд╡рд┐рд╖реНрдп рдХреЗ рдХреНрд╖реЗрддреНрд░реЛрдВ рдХреЗ рд▓рд┐рдП character.x = data.X рдЬреИрд╕реЗ рдХреЛрдб рдХрд╛ рдПрдХ рдЧреБрдЪреНрдЫрд╛ рдирд╣реАрдВ рд▓рд┐рдЦрдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рдо рдкреБрди: рд╕рд░реНрд╡рд░ рд╕реЗ рдбреЗрдЯрд╛ рдлрд╝реАрд▓реНрдб рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдЬрд╛рдПрдВрдЧреЗ рдФрд░, рдпрджрд┐ рдирд╛рдо рдореЗрд▓ рдЦрд╛рддреЗ рд╣реИрдВ, рддреЛ рдЙрдиреНрд╣реЗрдВ рдХреНрд▓рд╛рдЗрдВрдЯ рдСрдмреНрдЬреЗрдХреНрдЯ рдХреЛ рдЕрд╕рд╛рдЗрди рдХрд░реЗрдВред рд▓реЗрдХрд┐рди рдЬрд╛рдиреЗ рд╡рд╛рд▓реЗ рдХреНрд╖реЗрддреНрд░реЛрдВ рдХрд╛ рдкреВрдВрдЬреАрдХрд░рдг рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред рдЗрд╕рд▓рд┐рдП, рд╣рдо рдЧреЛ рд╕реНрдЯрд╛рдЗрд▓ рдЬреЛрдВрд╕ рдирд╛рдордХрд░рдг рд╕рдореНрдореЗрд▓рди рдХреЛ рд╕реНрд╡реАрдХрд╛рд░ рдХрд░реЗрдВрдЧреЗред рдЗрд╕ рдХрд╛рд░рдг рд╕реЗ, рд╣рдордиреЗ рд╕рд░реНрд╡рд░ рдХреЛ рджреЗрдЦрдХрд░ рд╢реБрд░реВ рдХрд┐рдпрд╛ред

рдЕрдиреБрдкреНрд░рдпреЛрдЧ рдЖрд░рдВрднреАрдХрд░рдг рдФрд░ рдореБрдЦреНрдп рд▓реВрдк
 /* main.go */ package main import ( "fmt" "time" ) const ( MAX_CLIENTS = 100 //      MAX_FPS = 60 //   go    // time.Second      FRAME_DURATION = time.Second / MAX_FPS ) //       var characters map[string]*Character func updateCharacters(k float64) { for _, c := range characters { c.update(k) } } func mainLoop() { //           //  . //    ,       var k float64 for { frameStart := time.Now() updateCharacters(k) duration := time.Now().Sub(frameStart) //    ,      if duration > 0 && duration < FRAME_DURATION { time.Sleep(FRAME_DURATION - duration) } ellapsed := time.Now().Sub(frameStart) //    ,        k = float64(ellapsed) / float64(time.Second) } } func main() { characters = make(map[string]*Character, MAX_CLIENTS) fmt.Println("Server started at ", time.Now()) //    go NanoHandler() mainLoop() } 

Character.update рдореЗрдердб рдореЗрдВ, рд╣рдо рдХреИрд░реЗрдХреНрдЯрд░ рдХреЛ рд▓реЗ рдЬрд╛рддреЗ рд╣реИ рдЕрдЧрд░ рд╡рд╣рд╛рдБ рдЬрд╛рдирд╛ рд╣реИ рдЬрд╣рд╛рдБ:
 /* point.go */ ... //        , //     func (p1 *Point) equals(p2 Point, epsilon float64) bool { if epsilon == 0 { epsilon = 1e-6 } return math.Abs(p1.X-p2.X) < epsilon && math.Abs(p1.Y-p2.Y) < epsilon } ... /* chacter.go */ ... func (c *Character) update(k float64) { //         //   ,        //       , //       if c.Pos.equals(c.Dst, float64(c.Speed)*k) { c.Pos = c.Dst return } // !        //         [],        //           lenX := c.Dst.X - c.Pos.X lenY := c.Dst.Y - c.Pos.Y c.Angle = math.Atan2(lenY, lenX) dx := math.Cos(c.Angle) * float64(c.Speed) * k dy := math.Sin(c.Angle) * float64(c.Speed) * k c.Pos.X += dx c.Pos.Y += dy } ... 

рдЕрдм рд╣рдо рд╕реАрдзреЗ рд╡реЗрдм рд╕реЙрдХреЗрдЯ рд╕реЗ рдЧреБрдЬрд░реЗрдВрдЧреЗред
 /* nano.go */ package main import ( "code.google.com/p/go.net/websocket" "fmt" "io" "net/http" "strings" ) const ( MAX_CMD_SIZE = 1024 MAX_OP_LEN = 64 CMD_DELIMITER = "|" ) //  тАФ    ip:port var connections map[string]*websocket.Conn //       json    type packet struct { Characters *map[string]*Character Error string } //      func NanoHandler() { connections = make(map[string]*websocket.Conn, MAX_CLIENTS) fmt.Println("Nano handler started") //  ws://hostname:48888/    NanoServer http.Handle("/", websocket.Handler(NanoServer)) //  48888      err := http.ListenAndServe(":48888", nil) if err != nil { panic("ListenAndServe: " + err.Error()) } } //   func NanoServer(ws *websocket.Conn) { //   MAX_CLIENTS,    ,      if len(connections) >= MAX_CLIENTS { fmt.Println("Cannot handle more requests") return } //  , , 127.0.0.1:52655 addr := ws.Request().RemoteAddr //    connections[addr] = ws //  ,      character := NewCharacter() fmt.Printf("Client %s connected [Total clients connected: %d]\n", addr, len(connections)) cmd := make([]byte, MAX_CMD_SIZE) for { //   n, err := ws.Read(cmd) //  if err == io.EOF { fmt.Printf("Client %s (%s) disconnected\n", character.Name, addr) //    delete(characters, character.Name) delete(connections, addr) //     ,    go notifyClients() //      break } //  ,     if err != nil { fmt.Println(err) continue } fmt.Printf("Received %d bytes from %s (%s): %s\n", n, character.Name, addr, cmd[:n]) //    : operation-name|{"param": "value", ...} //    opIndex := strings.Index(string(cmd[:MAX_OP_LEN]), CMD_DELIMITER) if opIndex < 0 { fmt.Println("Malformed command") continue } op := string(cmd[:opIndex]) //      json  //   ,       n  //   тАФ ,     , //    json data := cmd[opIndex+len(CMD_DELIMITER) : n] //        switch op { case "login": var name string //     websocket.JSON.Unmarshal(data, ws.PayloadType, &name) //     if _, ok := characters[name]; !ok && len(name) > 0 { //  character.Name = name characters[name] = &character fmt.Println(name, " logged in") } else { //    fmt.Println("Login failure: ", character.Name) go sendError(ws, "Cannot login. Try another name") continue } case "set-dst": var p Point //  -      if err := websocket.JSON.Unmarshal(data, ws.PayloadType, &p); err != nil { fmt.Println("Unmarshal error: ", err) } //    //   ,  Character.update    character.Dst = p default: // fmt.Printf("Unknown op: %s\n", op) continue } //     //           go notifyClients() } } //    func sendError(ws *websocket.Conn, error string) { // ,       packet := packet{Error: error} //   json msg, _, err := websocket.JSON.Marshal(packet) if err != nil { fmt.Println(err) return } //   if _, err := ws.Write(msg); err != nil { fmt.Println(err) } } //    func notifyClients() { //       packet := packet{Characters: &characters} //   json msg, _, err := websocket.JSON.Marshal(packet) if err != nil { fmt.Println(err) return } //      for _, ws := range connections { if _, err := ws.Write(msg); err != nil { fmt.Println(err) return } } } 

рдПрдХ рдЪрд░рд┐рддреНрд░ рдХрд╛ рдирд┐рд░реНрдорд╛рдг, рд╣рдореЗрдВ рдЙрд╕рд╕реЗ рдХреБрдЫ рдорд╛рдкрджрдВрдбреЛрдВ рдХреЛ рдкреВрдЫрдирд╛ рдЪрд╛рд╣рд┐рдПред рдЬрд╛рдиреЗ рдореЗрдВ рдпрд╣ NewTypename рдкреНрд░рдкрддреНрд░ рдХреЗ рдХрд┐рд╕реА рдлрд╝рдВрдХреНрд╢рди рдореЗрдВ рдРрд╕рд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдкреНрд░рдерд╛рдЧрдд рд╣реИ
 /* character.go */ ... const ( CHAR_DEFAULT_SPEED = 100 ) ... func NewCharacter() Character { c := Character{Speed: CHAR_DEFAULT_SPEED} c.Pos = Point{100, 100} c.Dst = c.Pos return c } 

рд╡рд╣ рд╣рдорд╛рд░рд╛ рдкреВрд░рд╛ рд╕рд░реНрд╡рд░ рд╣реИред
рдЗрд╕ рдкрд╛рда рдкрд░ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдПрдХрддреНрд░ рдХрд░рдиреЗ рдХреЗ рдмрд╛рдж рдЧреНрд░рд╛рд╣рдХ рднрд╛рдЧ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдПрдХ рд▓реЗрдЦ рд▓рд┐рдЦрд╛ рдЬрд╛рдПрдЧрд╛ред

рд╕рдВрджрд░реНрдн

рдбреЗрдореЛ
рдХрд╛рд░реНрдб рдЬреЗрдирд░реЗрдЯрд░ (рдкреГрд╖реНрдарднреВрдорд┐ рдкрд░ рдЪрд┐рддреНрд░)
рд╕реНрд░реЛрдд рдХреЛрдб

Source: https://habr.com/ru/post/In212701/


All Articles