feat 稳定300人
This commit is contained in:
@@ -2,8 +2,10 @@ package server
|
||||
|
||||
import (
|
||||
"common/log"
|
||||
"common/proto/sc/sc_pb"
|
||||
"common/proto/ss/grpc_pb"
|
||||
"context"
|
||||
"google.golang.org/protobuf/proto"
|
||||
"scene/instance"
|
||||
"sync"
|
||||
)
|
||||
@@ -11,7 +13,7 @@ import (
|
||||
func (s *Server) Enter(ctx context.Context, req *grpc_pb.EnterReq) (*grpc_pb.EnterResp, error) {
|
||||
var i *instance.Instance
|
||||
if len(instance.Mgr.GetAll()) == 0 {
|
||||
i = instance.NewScene(s.SID, int(req.InstanceID))
|
||||
i = instance.NewScene(s.SID, req.InstanceID)
|
||||
i.Start(s.EtcdTTL)
|
||||
} else {
|
||||
for _, v := range instance.Mgr.GetAll() {
|
||||
@@ -20,12 +22,29 @@ func (s *Server) Enter(ctx context.Context, req *grpc_pb.EnterReq) (*grpc_pb.Ent
|
||||
}
|
||||
}
|
||||
i.EventIn <- req
|
||||
|
||||
payload, _ := proto.Marshal(&sc_pb.S2C_EnterInstance{
|
||||
Info: &sc_pb.PositionInfo{
|
||||
UID: req.UID,
|
||||
X: 1,
|
||||
Y: 1,
|
||||
},
|
||||
})
|
||||
return &grpc_pb.EnterResp{
|
||||
SceneSID: s.SID,
|
||||
UniqueNo: i.UniqueNo,
|
||||
SceneSID: s.SID,
|
||||
UniqueNo: i.UniqueNo,
|
||||
MessageID: int32(sc_pb.MessageID_MESSAGE_ID_ENTER_INSTANCE),
|
||||
Payload: payload,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Server) Leave(ctx context.Context, req *grpc_pb.LeaveReq) (*grpc_pb.LeaveResp, error) {
|
||||
if i := instance.Mgr.GetByUniqueNo(req.UniqueNo); i != nil {
|
||||
i.EventIn <- req
|
||||
}
|
||||
return &grpc_pb.LeaveResp{}, nil
|
||||
}
|
||||
|
||||
func (s *Server) Action(server grpc_pb.Scene_ActionServer) error {
|
||||
wg := &sync.WaitGroup{}
|
||||
wg.Add(1)
|
||||
|
||||
@@ -19,26 +19,27 @@ import (
|
||||
|
||||
// Instance 场景类
|
||||
type Instance struct {
|
||||
wg sync.WaitGroup
|
||||
players map[int]*npc.PlayerNode // 存储所有玩家节点 [uid]
|
||||
ctx context.Context // 停止指令
|
||||
cancel context.CancelFunc // 停止函数
|
||||
logger *zap.SugaredLogger // 日志
|
||||
wg sync.WaitGroup
|
||||
players map[int32]*npc.PlayerNode // 存储所有玩家节点 [uid]
|
||||
ctx context.Context // 停止指令
|
||||
cancel context.CancelFunc // 停止函数
|
||||
logger *zap.SugaredLogger // 日志
|
||||
lastLogicTime int64 // 上次逻辑帧执行时间(毫秒时间戳)
|
||||
|
||||
SID int64 // 服务ID
|
||||
InstanceID int // 副本ID
|
||||
InstanceID int32 // 副本ID
|
||||
UniqueNo int64 // 唯一编号
|
||||
EventIn chan proto.Message // 消息入口
|
||||
}
|
||||
|
||||
// NewScene 初始化场景
|
||||
func NewScene(sid int64, instanceID int) *Instance {
|
||||
func NewScene(sid int64, instanceID int32) *Instance {
|
||||
s := &Instance{
|
||||
players: make(map[int]*npc.PlayerNode),
|
||||
players: make(map[int32]*npc.PlayerNode),
|
||||
SID: sid,
|
||||
InstanceID: instanceID,
|
||||
UniqueNo: utils.SnowflakeInstance().Generate().Int64(),
|
||||
EventIn: make(chan proto.Message),
|
||||
EventIn: make(chan proto.Message, 1024),
|
||||
}
|
||||
s.logger = log.GetLogger().Named(fmt.Sprintf("instance %v:%v", s.InstanceID, s.UniqueNo))
|
||||
s.ctx, s.cancel = context.WithCancel(context.Background())
|
||||
@@ -69,12 +70,15 @@ func (i *Instance) Start(ttl int64) {
|
||||
}
|
||||
// 场景心跳
|
||||
tick := time.NewTicker(50 * time.Millisecond)
|
||||
i.lastLogicTime = time.Now().UnixMilli()
|
||||
for {
|
||||
select {
|
||||
case <-i.ctx.Done():
|
||||
return
|
||||
case <-tick.C:
|
||||
i.onLogic()
|
||||
now := time.Now().UnixMilli()
|
||||
i.onLogic(now - i.lastLogicTime)
|
||||
i.lastLogicTime = now
|
||||
case e := <-i.EventIn:
|
||||
i.onEvent(e)
|
||||
}
|
||||
@@ -87,25 +91,27 @@ func (i *Instance) Start(ttl int64) {
|
||||
func (i *Instance) onEvent(e proto.Message) {
|
||||
switch v := e.(type) {
|
||||
case *grpc_pb.EnterReq:
|
||||
i.players[int(v.UID)] = npc.NewPlayerNode(v.GatewaySID, int(v.UID))
|
||||
i.players[v.UID] = npc.NewPlayerNode(v.GatewaySID, v.UID)
|
||||
case *grpc_pb.ActionReq:
|
||||
if node, ok := i.players[int(v.UID)]; ok {
|
||||
if node, ok := i.players[v.UID]; ok {
|
||||
node.AddAction(v)
|
||||
}
|
||||
case *grpc_pb.LeaveReq:
|
||||
delete(i.players, v.UID)
|
||||
}
|
||||
}
|
||||
|
||||
// 逻辑帧
|
||||
func (i *Instance) onLogic() {
|
||||
func (i *Instance) onLogic(delta int64) {
|
||||
positionUpdate := make([]*sc_pb.PositionInfo, 0)
|
||||
sid := int64(0)
|
||||
// 优先处理移动指令
|
||||
// 处理玩家指令
|
||||
for _, node := range i.players {
|
||||
if node.LogicMove() {
|
||||
if node.LogicAction(delta) {
|
||||
positionUpdate = append(positionUpdate, &sc_pb.PositionInfo{
|
||||
UID: int32(node.UID),
|
||||
X: node.Position[0],
|
||||
Y: node.Position[1],
|
||||
X: int32(node.Position[0] * 100),
|
||||
Y: int32(node.Position[1] * 100),
|
||||
})
|
||||
sid = node.GatewaySID
|
||||
}
|
||||
|
||||
@@ -23,54 +23,3 @@ func NewNPCNode(gatewaySID int64, uid int) *NPCNode {
|
||||
Action: make([]*grpc_pb.ActionReq, 0),
|
||||
}
|
||||
}
|
||||
|
||||
// 逻辑帧-移动
|
||||
func (p *NPCNode) logicMove() bool {
|
||||
if p.MoveCross&DirUp != 0 && p.MoveCross&DirDown != 0 {
|
||||
p.MoveCross &^= DirUp | DirDown
|
||||
}
|
||||
if p.MoveCross&DirLeft != 0 && p.MoveCross&DirRight != 0 {
|
||||
p.MoveCross &^= DirLeft | DirRight
|
||||
}
|
||||
|
||||
var moveX, moveY float64
|
||||
if p.MoveCross&DirUp != 0 {
|
||||
moveY += 1
|
||||
}
|
||||
if p.MoveCross&DirDown != 0 {
|
||||
moveY -= 1
|
||||
}
|
||||
if p.MoveCross&DirLeft != 0 {
|
||||
moveX -= 1
|
||||
}
|
||||
if p.MoveCross&DirRight != 0 {
|
||||
moveX += 1
|
||||
}
|
||||
// 没有移动
|
||||
if moveX == 0 && moveY == 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
if moveX != 0 && moveY != 0 {
|
||||
const diagonalFactor = 0.7071
|
||||
moveX *= diagonalFactor
|
||||
moveY *= diagonalFactor
|
||||
}
|
||||
|
||||
speed := 10.0
|
||||
p.Position[0] += moveX * speed
|
||||
p.Position[1] += moveY * speed
|
||||
if p.Position[0] < 0 {
|
||||
p.Position[0] = 0
|
||||
}
|
||||
if p.Position[0] > 400 {
|
||||
p.Position[0] = 400
|
||||
}
|
||||
if p.Position[1] < 0 {
|
||||
p.Position[1] = 0
|
||||
}
|
||||
if p.Position[1] > 400 {
|
||||
p.Position[1] = 400
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -1,92 +1,64 @@
|
||||
package npc
|
||||
|
||||
import (
|
||||
"common/proto/sc/sc_pb"
|
||||
"common/proto/ss/grpc_pb"
|
||||
)
|
||||
|
||||
// PlayerNode 定义玩家节点结构体
|
||||
type PlayerNode struct {
|
||||
UID int // 用户ID
|
||||
GatewaySID int64 // 网关服务ID
|
||||
UID int32 // 用户ID
|
||||
GatewaySID int64 // 网关服务ID
|
||||
MoveSpeed float32 // 移动速度
|
||||
|
||||
Position [2]float64 // 二维坐标 [x, y]
|
||||
MoveCross int8 // 移动十字,1 上 2 下 4 左 8 右
|
||||
Action []*grpc_pb.ActionReq // 其他操作
|
||||
Position [2]float32 // 二维坐标 [x, y]
|
||||
MoveDirection [2]int8 // 移动方向 [x, y]
|
||||
MoveCount int8 // 移动指令使用计数
|
||||
Action []*grpc_pb.ActionReq // 其他操作
|
||||
}
|
||||
|
||||
func NewPlayerNode(gatewaySID int64, uid int) *PlayerNode {
|
||||
func NewPlayerNode(gatewaySID int64, uid int32) *PlayerNode {
|
||||
return &PlayerNode{
|
||||
UID: uid,
|
||||
GatewaySID: gatewaySID,
|
||||
Position: [2]float64{0, 0},
|
||||
MoveCross: 0,
|
||||
MoveSpeed: 5 * 0.00001,
|
||||
Position: [2]float32{0, 0},
|
||||
Action: make([]*grpc_pb.ActionReq, 0),
|
||||
}
|
||||
}
|
||||
|
||||
// AddAction 将指令存储到玩家身上
|
||||
func (p *PlayerNode) AddAction(e *grpc_pb.ActionReq) {
|
||||
if e.Action < 16 {
|
||||
p.MoveCross = int8(e.Action)
|
||||
} else {
|
||||
p.Action = append(p.Action, e)
|
||||
}
|
||||
p.Action = append(p.Action, e)
|
||||
}
|
||||
|
||||
const (
|
||||
DirUp int8 = 1 << iota // 1 (00000001)
|
||||
DirDown // 2 (00000010)
|
||||
DirLeft // 4 (00000100)
|
||||
DirRight // 8 (00001000)
|
||||
)
|
||||
// LogicAction 处理玩家操作指令
|
||||
// return 是否更新玩家状态
|
||||
func (p *PlayerNode) LogicAction(delta int64) bool {
|
||||
for _, a := range p.Action {
|
||||
switch sc_pb.ActionID(a.Action) {
|
||||
case sc_pb.ActionID_ACTION_ID_MOVE:
|
||||
p.MoveDirection = [2]int8{int8(a.DirX), int8(a.DirY)}
|
||||
p.MoveCount = 0
|
||||
case sc_pb.ActionID_ACTION_ID_ATTACK:
|
||||
}
|
||||
}
|
||||
p.Action = make([]*grpc_pb.ActionReq, 0)
|
||||
|
||||
// LogicMove 逻辑帧-移动
|
||||
func (p *PlayerNode) LogicMove() bool {
|
||||
if p.MoveCross&DirUp != 0 && p.MoveCross&DirDown != 0 {
|
||||
p.MoveCross &^= DirUp | DirDown
|
||||
}
|
||||
if p.MoveCross&DirLeft != 0 && p.MoveCross&DirRight != 0 {
|
||||
p.MoveCross &^= DirLeft | DirRight
|
||||
}
|
||||
return p.move(delta)
|
||||
}
|
||||
|
||||
var moveX, moveY float64
|
||||
if p.MoveCross&DirUp != 0 {
|
||||
moveY += 1
|
||||
}
|
||||
if p.MoveCross&DirDown != 0 {
|
||||
moveY -= 1
|
||||
}
|
||||
if p.MoveCross&DirLeft != 0 {
|
||||
moveX -= 1
|
||||
}
|
||||
if p.MoveCross&DirRight != 0 {
|
||||
moveX += 1
|
||||
}
|
||||
// 没有移动
|
||||
if moveX == 0 && moveY == 0 {
|
||||
func (p *PlayerNode) move(delta int64) bool {
|
||||
if p.MoveDirection[0] == 0 && p.MoveDirection[1] == 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
if moveX != 0 && moveY != 0 {
|
||||
const diagonalFactor = 0.7071
|
||||
moveX *= diagonalFactor
|
||||
moveY *= diagonalFactor
|
||||
}
|
||||
|
||||
speed := 10.0
|
||||
p.Position[0] += moveX * speed
|
||||
p.Position[1] += moveY * speed
|
||||
if p.Position[0] < 0 {
|
||||
p.Position[0] = 0
|
||||
}
|
||||
if p.Position[0] > 400 {
|
||||
p.Position[0] = 400
|
||||
}
|
||||
if p.Position[1] < 0 {
|
||||
p.Position[1] = 0
|
||||
}
|
||||
if p.Position[1] > 400 {
|
||||
p.Position[1] = 400
|
||||
// 移动指令只能用2秒,客户端需要定期续上
|
||||
if p.MoveCount >= 40 {
|
||||
p.MoveDirection = [2]int8{0, 0}
|
||||
return false
|
||||
}
|
||||
p.Position[0] += float32(p.MoveDirection[0]) * float32(delta) * p.MoveSpeed
|
||||
p.Position[1] += float32(p.MoveDirection[1]) * float32(delta) * p.MoveSpeed
|
||||
p.MoveCount++
|
||||
return true
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user