| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275 |
- package mapPathfind
- import (
- "f1-game/internal/algorithm/astar6"
- "f1-game/internal/code"
- "f1-game/internal/constant"
- "f1-game/internal/data"
- "f1-game/internal/enum"
- nameActor "f1-game/internal/name/actor"
- nameRemote "f1-game/internal/name/remote"
- "f1-game/internal/pb"
- "f1-game/internal/types"
- mapCall "f1-game/nodes/map/internal/call"
- mapTypes "f1-game/nodes/map/internal/types"
- clog "github.com/cherry-game/cherry/logger"
- cactor "github.com/cherry-game/cherry/net/actor"
- )
- type (
- // actorPathfind 寻路子Actor,计划开启多个实例轮询调用
- actorPathfind struct {
- cactor.Base
- barrierData mapTypes.BarrierData // 动态障碍数据
- astar *astar6.AStar // a星寻路
- }
- )
- func newActorPathfind(barrierData mapTypes.BarrierData) *actorPathfind {
- var (
- width = data.MapInfo().Width
- height = data.MapInfo().Height
- )
- if width < 0 || height < 0 {
- clog.Errorf("map width or height is invalid. width = %v, height = %v", width, height)
- return nil
- }
- // 加载寻路数据
- tileData := make([][]int32, width)
- for x := range width {
- tileData[x] = make([]int32, height)
- for y := range height {
- tileID, ok := data.PointToTileID(int32(x), int32(y))
- if !ok {
- continue
- }
- tile := data.MapData().Tiles[tileID]
- if tile != nil && !tile.IsBlock() {
- tileData[x][y] = int32(tile.BlockType)
- }
- }
- }
- actor := &actorPathfind{
- barrierData: barrierData.Clone(),
- }
- actor.astar = astar6.New(astar6.Config{
- Min: types.Point{
- X: 0,
- Y: 0,
- },
- Max: types.Point{
- X: width - 1,
- Y: height - 1,
- },
- MapData: tileData,
- IsWalkableFunc: actor.isWalkable,
- })
- return actor
- }
- func (p *actorPathfind) AliasID() string {
- return nameActor.Map_Pathfind
- }
- func (p *actorPathfind) OnInit() {
- p.Remote().Register(nameRemote.MapPathFind_Find, p.findPath)
- p.Remote().Register(nameRemote.MapPathFind_SetBarriers, p.setBarriers)
- p.Remote().Register(nameRemote.MapPathFind_RemoveBarriers, p.removeBarriers)
- p.Remote().Register(nameRemote.MapPathFind_SiegePath, p.siegePath)
- }
- // siegePath 攻城路径
- func (p *actorPathfind) siegePath(req *mapTypes.SiegePathReq) {
- rsp := mapTypes.SiegePathRsp{
- SiegeBaseObjectID: req.SiegeBaseObjectID,
- MainForceDepartPath: make([]types.Points, req.MainForcePoints.Size()),
- MainForceArrivePath: make([]types.Points, req.MainForcePoints.Size()),
- SiegeSquadDepartPath: make([]types.Points, req.SiegeSquadPoints.Size()),
- SiegeSquadArrivePath: make([]types.Points, req.SiegeSquadPoints.Size()),
- DirectPath: make([]types.Points, req.SiegePoints.Size()),
- }
- // 主力出发路径
- for i, point := range req.MainForcePoints {
- path, errCode := p.doFindPath(req.StartPoint.X, req.StartPoint.Y, point.X, point.Y)
- if code.IsFail(errCode) {
- clog.Errorf("find main force path failed. start to middle: %v -> %v, errCode = %v",
- req.StartPoint, point, errCode)
- continue
- }
- points := types.Points{}
- for _, p := range path.List {
- points = append(points, &types.Point{X: p.X, Y: p.Y})
- }
- rsp.MainForceDepartPath[i] = points
- }
- // 搬迁队出发路径
- for i, point := range req.SiegeSquadPoints {
- path, errCode := p.doFindPath(req.StartPoint.X, req.StartPoint.Y, point.X, point.Y)
- if code.IsFail(errCode) {
- clog.Errorf("find siege squad path failed. start to middle: %v -> %v, errCode = %v",
- req.StartPoint, point, errCode)
- continue
- }
- points := types.Points{}
- for _, p := range path.List {
- points = append(points, &types.Point{X: p.X, Y: p.Y})
- }
- rsp.SiegeSquadDepartPath[i] = points
- }
- // 主力到达路径
- for i, point := range req.SiegePoints {
- startPoint := req.MainForcePoints[i]
- path, errCode := p.doFindPath(startPoint.X, startPoint.Y, point.X, point.Y)
- if code.IsFail(errCode) {
- clog.Errorf("find main force path failed. middle to siege: %v -> %v, errCode = %v",
- startPoint, point, errCode)
- continue
- }
- points := types.Points{}
- for _, p := range path.List {
- points = append(points, &types.Point{X: p.X, Y: p.Y})
- }
- rsp.MainForceArrivePath[i] = points
- }
- // 拆迁队到达路径
- for i, point := range req.SiegePoints {
- startPoint := req.SiegeSquadPoints[i]
- path, errCode := p.doFindPath(startPoint.X, startPoint.Y, point.X, point.Y)
- if code.IsFail(errCode) {
- clog.Errorf("find siege squad path failed. middle to siege: %v -> %v, errCode = %v",
- startPoint, point, errCode)
- continue
- }
- points := types.Points{}
- for _, p := range path.List {
- points = append(points, &types.Point{X: p.X, Y: p.Y})
- }
- rsp.SiegeSquadArrivePath[i] = points
- }
- // 直接到达路径
- for i, point := range req.SiegePoints {
- path, errCode := p.doFindPath(req.StartPoint.X, req.StartPoint.Y, point.X, point.Y)
- if code.IsFail(errCode) {
- clog.Errorf("find path failed. start to siege: %v -> %v, errCode = %v",
- req.StartPoint, point, errCode)
- continue
- }
- points := types.Points{}
- for _, p := range path.List {
- points = append(points, &types.Point{X: p.X, Y: p.Y})
- }
- rsp.DirectPath[i] = points
- }
- // 设置路径
- mapCall.Logic.SetSiegePath(&rsp)
- }
- // 计算寻路
- func (p *actorPathfind) findPath(req *pb.FindPathRequest) (*pb.Points, int32) {
- ctx := astar6.NewFindContext(req.StartX, req.StartY, req.EndX, req.EndY, req.PlayerID, req.LeagueID, req.MarchType)
- nodes, ok := p.astar.FindPath(ctx)
- if !ok {
- return nil, code.MapPathFindFail
- }
- path := &pb.Points{}
- for _, node := range nodes {
- path.List = append(path.List, &pb.Point{
- X: node.X(),
- Y: node.Y(),
- })
- }
- return path, code.OK
- }
- // findLocalPath 在指定区域内寻路
- func (p *actorPathfind) doFindPath(sx, sy, ex, ey int32) (*pb.Points, int32) {
- ctx := astar6.DefaultFindContext(sx, sy, ex, ey)
- nodes, ok := p.astar.FindPath(ctx)
- if !ok {
- return nil, code.MapPathFindFail
- }
- path := &pb.Points{}
- for _, node := range nodes {
- path.List = append(path.List, &pb.Point{
- X: node.X(),
- Y: node.Y(),
- })
- }
- return path, code.OK
- }
- func (p *actorPathfind) isWalkable(node *astar6.Node, ctx *astar6.FindContext) bool {
- // 当前坐标的障碍点
- barrier, found := p.barrierData.Get(node.X(), node.Y())
- // 没有障碍可直接通过
- if !found {
- return true
- }
- // 通用 marchType 执行逻辑
- marchType := enum.MarchType(ctx.MarchType())
- switch marchType {
- case enum.MarchType_Unknow: // 默认情况,所有障碍点不可通行
- return false
- case enum.MarchType_Retreat: // 撤退类型可以通过所有障碍点
- return true
- default:
- // 如果是攻城或者掠夺是可以上敌方的城墙, TODO: 仅限终点,现在先不限制,等配置了攻城点再打开
- if marchType == enum.MarchType_Siege || marchType == enum.MarchType_Snatch /*&& ctx.IsEndPoint(x, y)*/ {
- return true
- }
- // 其他行军指令,或者非攻城指令的终点
- // 1. 只能通过友军的城墙
- if barrier.PlayerID == ctx.PlayerID() || (barrier.LeagueID != 0 && barrier.LeagueID == ctx.LeagueID()) {
- return true
- }
- // 2. 中立的码头是可以通行的
- // 码头 + 通道
- if barrier.ConfigID == constant.MapCastle_Dock1 || barrier.ConfigID == constant.MapCastle_Dock2 {
- return barrier.LeagueID == 0
- }
- }
- return false
- }
- func (p *actorPathfind) setBarriers(req *mapTypes.BarrierRequest) {
- p.barrierData.Add(req)
- }
- func (p *actorPathfind) removeBarriers(req types.Points) {
- for _, point := range req {
- p.barrierData.Remove(point.X, point.Y)
- }
- }
|