客户端向leafserver传输玩家所在位置,数据是json格式,使用大端序len+data,len占两个字节,可以在leafserver中配置。gs中没有逻辑判断只是广播玩家位置消息,对方玩家会因一定延迟导致卡顿,所以使用了while循环确保能够收到对方玩家的逻辑帧。另外在step里边直接同步逻辑实际上也是不妥的,但这里只作为学习,不用计较。 资源地址https://download.csdn.net/download/Jailman/68047268 to be continued,不断完善中……
python使用socket通信的示例脚本
import socket
import struct
import time
import json
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
client.connect(("127.0.0.1", 3563))
while True:
msg_data = b'''{"PLAYER_POSITION": {"pos_x": 300.13233, "pos_y": 200.13233}}'''
msg_len = len(msg_data)
big_endian_head = struct.pack(">H", msg_len)
fin_data = bytes(big_endian_head) + bytes(msg_data)
print("SND MSG LEN: " + str(len(fin_data)))
print("SND MSG: " + msg_data)
client.send(fin_data)
info = client.recv(1024)
rcv_msg_len = struct.unpack(">H",info[:2])[0]
rsv_msg = str(info[2:rcv_msg_len+2])
print("RCV MSG LEN: " + str(rcv_msg_len))
print("RCV MSG: " + rsv_msg)
position = json.loads(rsv_msg)
pos_x = position["PLAYER_POSITION"]["Pos_x"]
pos_y = position["PLAYER_POSITION"]["Pos_y"]
with open("client_location", "a") as f:
f.write("player_position: {} {}\n".format(str(pos_x), str(pos_y)))
time.sleep(0.1)
完全的网游雏形,客户端使用while粗暴的解决补帧逻辑(可以联想一下外挂的原理),缺点就是对方掉线我方直接卡死! cocos2d客户端1
from pyglet.window import key
from cocos import actions, layer, sprite, scene
from cocos.director import director
from cocos.actions import *
import socket
import struct
import json
class Frame_Sync(actions.Move):
def __init__(self, player_id, client, local):
super(Frame_Sync, self).__init__()
self.player_id = player_id
self.client = client
self.local = local
def step(self, dt):
super(Frame_Sync, self).step(dt)
if self.local:
velocity_x = 200 * (keyboard[key.RIGHT] - keyboard[key.LEFT])
velocity_y = 200 * (keyboard[key.UP] - keyboard[key.DOWN])
if self.target.position[0] > 960:
self.target.velocity = (-100, velocity_y)
elif self.target.position[0] < 0:
self.target.velocity = (100, velocity_y)
elif self.target.position[1] < 0:
self.target.velocity = (velocity_x, 100)
elif self.target.position[1] > 640:
self.target.velocity = (velocity_x, -100)
else:
self.target.velocity = (velocity_x, velocity_y)
msg_data = b'{"PLAYER_STATUS": {"id": %s, "pos_x": %s, "pos_y": %s}}' % (self.player_id, self.target.position[0], self.target.position[1])
msg_len = len(msg_data)
big_endian_head = struct.pack(">H", msg_len)
fin_data = bytes(big_endian_head) + bytes(msg_data)
print("SND MSG LEN: " + str(len(fin_data)))
print("SND MSG: " + msg_data)
self.client.send(fin_data)
else:
tick = 0
while True:
info = self.client.recv(1024)
rcv_msg_len = struct.unpack(">H",info[:2])[0]
rsv_msg = str(info[2:rcv_msg_len+2])
print("RCV MSG LEN: " + str(rcv_msg_len))
print("RCV MSG: " + rsv_msg)
position = json.loads(rsv_msg)
id = position["PLAYER_STATUS"]["Id"]
pos_x = position["PLAYER_STATUS"]["Pos_x"]
pos_y = position["PLAYER_STATUS"]["Pos_y"]
if id == self.player_id:
self.target.position = (pos_x, pos_y)
break
tick += 1
if tick > 100:
break
def run_scene():
global keyboard
director.init(width=960, height=640, autoscale=False, resizable=True)
player_layer = layer.Layer()
bg = sprite.Sprite('images/bg1.jpeg')
me = sprite.Sprite('images/ufo1.png')
him = sprite.Sprite('images/ufo2.png')
player_layer.add(bg)
player_layer.add(me)
player_layer.add(him)
bg.position = (480, 320)
me.position = (400, 100)
me.velocity = (0, 0)
him.position = (400, 100)
him.velocity = (0, 0)
my_player_id = 1
local = True
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
client.connect(("127.0.0.1", 3563))
me.do(Frame_Sync(my_player_id, client, local))
his_player_id = 2
local = False
him.do(Frame_Sync(his_player_id, client, local))
main_scene = scene.Scene(player_layer)
keyboard = key.KeyStateHandler()
director.window.push_handlers(keyboard)
director.run(main_scene)
if __name__ == '__main__':
run_scene()
客户端2
from pyglet.window import key
from cocos import actions, layer, sprite, scene
from cocos.director import director
from cocos.actions import *
import socket
import struct
import json
class Frame_Sync(actions.Move):
def __init__(self, player_id, client, local):
super(Frame_Sync, self).__init__()
self.player_id = player_id
self.client = client
self.local = local
def step(self, dt):
super(Frame_Sync, self).step(dt)
if self.local:
velocity_x = 200 * (keyboard[key.RIGHT] - keyboard[key.LEFT])
velocity_y = 200 * (keyboard[key.UP] - keyboard[key.DOWN])
if self.target.position[0] > 960:
self.target.velocity = (-100, velocity_y)
elif self.target.position[0] < 0:
self.target.velocity = (100, velocity_y)
elif self.target.position[1] < 0:
self.target.velocity = (velocity_x, 100)
elif self.target.position[1] > 640:
self.target.velocity = (velocity_x, -100)
else:
self.target.velocity = (velocity_x, velocity_y)
msg_data = b'{"PLAYER_STATUS": {"id": %s, "pos_x": %s, "pos_y": %s}}' % (self.player_id, self.target.position[0], self.target.position[1])
msg_len = len(msg_data)
big_endian_head = struct.pack(">H", msg_len)
fin_data = bytes(big_endian_head) + bytes(msg_data)
print("SND MSG LEN: " + str(len(fin_data)))
print("SND MSG: " + msg_data)
self.client.send(fin_data)
else:
tick = 0
while True:
info = self.client.recv(1024)
rcv_msg_len = struct.unpack(">H",info[:2])[0]
rsv_msg = str(info[2:rcv_msg_len+2])
print("RCV MSG LEN: " + str(rcv_msg_len))
print("RCV MSG: " + rsv_msg)
position = json.loads(rsv_msg)
id = position["PLAYER_STATUS"]["Id"]
pos_x = position["PLAYER_STATUS"]["Pos_x"]
pos_y = position["PLAYER_STATUS"]["Pos_y"]
if id == self.player_id:
self.target.position = (pos_x, pos_y)
break
tick += 1
if tick > 100:
break
def run_scene():
global keyboard
director.init(width=960, height=640, autoscale=False, resizable=True)
player_layer = layer.Layer()
bg = sprite.Sprite('images/bg1.jpeg')
me = sprite.Sprite('images/ufo2.png')
him = sprite.Sprite('images/ufo1.png')
player_layer.add(bg)
player_layer.add(me)
player_layer.add(him)
bg.position = (480, 320)
me.position = (400, 100)
me.velocity = (0, 0)
him.position = (400, 100)
him.velocity = (0, 0)
my_player_id = 2
local = True
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
client.connect(("127.0.0.1", 3563))
me.do(Frame_Sync(my_player_id, client, local))
his_player_id = 1
local = False
him.do(Frame_Sync(his_player_id, client, local))
main_scene = scene.Scene(player_layer)
keyboard = key.KeyStateHandler()
director.window.push_handlers(keyboard)
director.run(main_scene)
if __name__ == '__main__':
run_scene()
两个客户端均同leafserver通信,并得到所有的游戏广播消息 leafserver修改 msg/mgs.go
package msg
import (
"github.com/name5566/leaf/network/json"
)
var Processor = json.NewProcessor()
func init() {
Processor.Register(&PLAYER_STATUS{})
}
type PLAYER_STATUS struct {
Id int
Pos_x float32
Pos_y float32
}
gate/router.go
package gate
import (
"server/game"
"server/msg"
)
func init() {
msg.Processor.SetRouter(&msg.PLAYER_STATUS{}, game.ChanRPC)
}
game/internal/chanrpc.go广播消息
package internal
import (
"github.com/name5566/leaf/gate"
)
var agents = make(map[gate.Agent]struct{})
func init() {
skeleton.RegisterChanRPC("NewAgent", rpcNewAgent)
skeleton.RegisterChanRPC("CloseAgent", rpcCloseAgent)
}
func rpcNewAgent(args []interface{}) {
a := args[0].(gate.Agent)
agents[a] = struct{}{}
}
func rpcCloseAgent(args []interface{}) {
a := args[0].(gate.Agent)
delete(agents, a)
}
game/internal/handler.go
package internal
import (
"github.com/name5566/leaf/log"
"reflect"
"server/msg"
)
func init() {
handler(&msg.PLAYER_STATUS{}, handleplayerstatus)
}
func handler(m interface{}, h interface{}) {
skeleton.RegisterChanRPC(reflect.TypeOf(m), h)
}
func handleplayerstatus(args []interface{}) {
m := args[0].(*msg.PLAYER_STATUS)
log.Debug("PLAYER_STATUS: %v,%v,%v", m.Id, m.Pos_x, m.Pos_y)
for a := range agents {
a.WriteMsg(&msg.PLAYER_STATUS{
Id: m.Id,
Pos_x: m.Pos_x,
Pos_y: m.Pos_y,
})
}
}
效果图
|