/* point.go && character.go */ ... type Point struct { X, Y float64 } ... type Character struct { Pos, Dst Point // Angle float64 // Speed uint // Name string } ...
character.x = data.X
for all current and future fields, we will recursively walk through the data fields from the server and, if the names match, assign them to client objects. But the fields in go are capitalized. Therefore, we will accept the naming convention for js fields in the go style. It is for this reason that we started by looking at the server. /* 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() }
/* 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 } } }
/* 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/212701/
All Articles