简单四方向a*学习记录4 能初步实现从角色到目的地寻路

go 复制代码
const ng=g+1;
    this.shangx=qidianx;
    this.shangy=qidiany-1;
    this.zuox=qidianx-1;


    this.zuoy=qidiany;
    this.youx=qidianx+1;
    this.youy=qidiany;
    this.xiax=qidianx;

    this.xiay=qidiany+1; 

都用ng是因为不用算起点的g 所以就算是第一次传过来的是起点g=0 还是得加1是正确的还是啥

好问题!你的理解非常关键!

答案是:✅ 完全正确!必须用ng!

让我解释为什么:

起点G值的正确计算流程:

你的正确理解:

TEXT

第0步:站在起点(3,8),传入g=0 // g=起点自己的累计G值(0)

ng = g + 1 = 0 + 1 = 1 // 走到邻居的代价

邻居格子G值计算:

上(3,7): G = 1 (从起点走一步的代价)

左(2,8): G = 1

右(4,8): G = 1

下(3,9): G = 1

这才是正确的A!* 因为:

当前格子自己的G值 = 已走的总代价

邻居格子的G值 = 当前G + 走到邻居的代价(1)

相比上次的没多大变化 在角色脚本

h

uoqushangxiazuoyou(qidianx:number,qidiany:number,g:number){这个函数加三个形参 const ng=g+1;创建ng变量 作为走几步的g

this.huoqushangxiazuoyou(this.juesex,this.juesey,0); 初次调用是格子将数组地图传给角色脚本 所以g是0

在这个函数最后做个判断

go 复制代码
if(zuixiaof>0&&(zuixiaofangxiangx!==this.mubiaox||zuixiaofangxiangy!==this.mubiaoy)){
            this.huoqushangxiazuoyou(zuixiaofangxiangx,zuixiaofangxiangy,ng);
        }

如果最小f不是0 证明还没到目的地 如果最小格子xy 也就是下一步的xy不是目的地格子的xy 开始递归 调用自己

将ng传给自己

虾片开始做障碍寻路跟 寻路时对数组地图边界处理

go 复制代码
import { _decorator, Collider2D, Component, Contact2DType, director, IPhysics2DContact, math, Node } from 'cc';
const { ccclass, property,executeInEditMode } = _decorator;

@ccclass('xiaobing')

@executeInEditMode
export class xiaobing extends Component {
    juesex:number=null;
    juesey:number=null;
    mubiaox:number=null;
    mubiaoy:number=null;
    shangf:number=0;
    shangg:number=0;

    shangh:number=0;


    zuof:number=0;
    zuoh:number=0;
    zuog:number=0;
    youf:number=0;
    youh:number=0;
    youg:number=0;
    xiaf:number=0;
    xiah:number=0;
    xiag:number=0;
    shangx:number=0;
    shangy:number=0;
    zuox:number=0;
    zuoy:number=0;
    youx:number=0;
    youy:number=0;
    xiax:number=0;
    xiay:number=0;
    nextx:number=0;
    nexty:number=0;
    nextg:number=0;
    onLoad(){

        // 监听碰撞事件

      const collider = this.getComponent(Collider2D);
      
      if (collider) {
          collider.on(Contact2DType.BEGIN_CONTACT, this.onBeginContact, this);
          
          
      }
      director.on('gezi_ditu_xiaobing', this.huoquditu, this);
        
    }

    
    // 碰撞回调
    onBeginContact(selfCollider: Collider2D, otherCollider: Collider2D, contact: IPhysics2DContact | null) {
        if(otherCollider.node.name.includes("shantou")){
            this.scheduleOnce(()=>{

                selfCollider.node.destroy();
            },0.7);
        }
    }
    start() {

        director.emit('xiaobing_position_gezi', this.node.worldPosition);
    }

    update(deltaTime: number) {

    }







    huoquditu(ditu:[][]){
       let len=ditu.length;
       console.log(len+"=");

       for(let y=0;y<len;y++){
        for(let x=0;x<ditu[y].length;x++){
            console.log(ditu[y][x]);
            if(ditu[y][x]==1){
                this.mubiaox=x;

                this.mubiaoy=y;

                console.log("/"+this.mubiaox,this.mubiaoy)
            }else if(ditu[y][x]==7){
                this.juesex=x;
                this.juesey=y;
                console.log("/"+this.juesex,this.juesey);
            }
            
        }
           
       }
       //this.jisuanf(this.juesex,this.juesey);
       this.huoqushangxiazuoyou(this.juesex,this.juesey,0);
    }

    jisuannext(x:number,y:number,f:number,g:number){
        
        
        if(f>0){

            //g=g+1;
            this.huoqushangxiazuoyou(x,y,(g+1));
        }


    }

    huoqushangxiazuoyou(qidianx:number,qidiany:number,g:number){
        



        this.shangx=qidianx;
        this.shangy=qidiany-1;
        this.zuox=qidianx-1;


        this.zuoy=qidiany;
        this.youx=qidianx+1;
        this.youy=qidiany;
        this.xiax=qidianx;

        this.xiay=qidiany+1;
        this.shangg=ng;
        this.shangh=Math.abs(this.shangx-this.mubiaox)+Math.abs(this.shangy-this.mubiaoy);
        this.shangf=this.shangg+this.shangh;
        const ng=g+1;
        this.zuog=ng;
        this.zuoh=Math.abs(this.zuox-this.mubiaox)+Math.abs(this.zuoy-this.mubiaoy);

        this.zuof=this.zuog+this.zuoh;
        this.youg=ng;
        this.youh=Math.abs(this.youx-this.mubiaox)+Math.abs(this.youy-this.mubiaoy);
        this.youf=this.youg+this.youh;


        this.xiag=ng;
        this.xiah=Math.abs(this.xiax-this.mubiaox)+Math.abs(this.xiay-this.mubiaoy);
        this.xiaf=this.xiag+this.xiah;
        
        const suoyouf=[this.shangf,this.zuof,this.youf,this.xiaf];
        let zuixiaof=suoyouf[0];
        let fangxiang=0; // 0/shang 1/zuo 2/you 3/xia
        let zuixiaog=0;
        for(let i=1;i<suoyouf.length;i++){
            if(suoyouf[i]<zuixiaof){
                zuixiaof=suoyouf[i];
                fangxiang=i;
            }
        }
        let zuixiaofangxiangx=0;
        let zuixiaofangxiangy=0;
        if(fangxiang==0){
            zuixiaofangxiangx=this.shangx;
            zuixiaofangxiangy=this.shangy;
        }else if(fangxiang==1){
            zuixiaofangxiangx=this.zuox;
            zuixiaofangxiangy=this.zuoy;
        }else if(fangxiang==2){
            zuixiaofangxiangx=this.youx;
            zuixiaofangxiangy=this.youy;
        }else if(fangxiang==3){
            zuixiaofangxiangx=this.xiax;
            zuixiaofangxiangy=this.xiay;
        }
        const directionData = {
            shangf: this.shangf,  // 上方向状态或坐标x
            xiaf: this.xiaf,      // 下
            zuof: this.zuof,      // 左  
            youf: this.youf,      // 右
            shangx: this.shangx, // 上方向x坐标
            shangy: this.shangy, // 上方向y坐标
            zuox: this.zuox,     // 左方向x坐标
            zuoy: this.zuoy,     // 左方向y坐标
            youx: this.youx,     // 右方向x坐标
            youy: this.youy,     // 右方向y坐标(如果有)
            xiax: this.xiax,     // 下方向x坐标(如果有)
            xiay: this.xiay,     // 下方向y坐标(如果有)
            zuixiaof:zuixiaof,
            zuixiaofangxiangx:zuixiaofangxiangx,
            zuixiaofangxiangy:zuixiaofangxiangy,
            mubiaox:this.mubiaox,
            mubiaoy:this.mubiaoy,
            juesex:this.juesex,
            juesey:this.juesey
        };

        console.log("s"+this.shangf+"z"+this.zuof+"y"+this.youf+"x"+this.xiaf+"f"+zuixiaof+"fang"+fangxiang);
        director.emit('xiaobing_sxzy_gezi', directionData);
        //this.nextx=zuixiaofangxiangx;
        //this.nexty=zuixiaofangxiangy;
        if(zuixiaof>0&&(zuixiaofangxiangx!==this.mubiaox||zuixiaofangxiangy!==this.mubiaoy)){
            this.huoqushangxiazuoyou(zuixiaofangxiangx,zuixiaofangxiangy,ng);
        }
        
    }
}

格子脚本分成数组地图 存储角色起点跟目的地 显示路径数组 用来显示路径

go 复制代码
import { _decorator, Color, Component, director, Graphics, Node, Vec3 } from 'cc';
const { ccclass, property,executeInEditMode} = _decorator;

@ccclass('gezi')

@executeInEditMode
export class gezi extends Component {
    @property
    gridWidth: number = 10;  // 水平格子数
    
    @property
    gridHeight: number = 10; // 垂直格子数
    
    @property
    cellSize: number = 100;   // 每个格子的大小(像素)
    
    @property
    lineWidth: number = 2;   // 线宽
    
    @property

    lineColor: Color = Color.GRAY;  // 线颜色
    





    @property
    targetColor: Color = new Color(1, 27, 3);  // 线颜色
    @property
    jueseColor: Color = new Color(1, 27, 3);  // 线颜色
    @property
    fillColor: Color = new Color(240, 240, 240);  // 填充颜色(浅灰)
    @property
    xiaColor: Color = new Color(240, 240, 240);  // 填充颜色(浅灰)
    @property
    zuixiaoColor: Color = new Color(240, 240, 240);  // 填充颜色(浅灰)
    @property
    zhangaiColor: Color = new Color(240, 240, 240);  // 填充颜色(浅灰)
    @property(Node)
    xiaobing:Node=null;
    private graphics: Graphics | null = null;

    gezi=[[0,0,0,0,0,0,0,0,0,0],
          [0,0,0,0,0,0,0,0,1,0],
          [0,0,0,0,0,0,0,0,0,0],
          [0,0,0,0,0,0,11,0,0,0],
          [0,0,0,0,0,0,0,0,0,0],
          [0,0,0,0,0,0,0,0,0,0],
          [0,0,0,0,0,0,0,0,0,0],
          [0,0,0,0,0,0,0,0,0,0],
          [0,0,0,0,0,0,0,0,0,0],
          [0,0,0,0,0,0,0,0,0,0],
          
        ];

    


















    shangx:number=0;
    shangy:number=0;
    shangf:number=0;
   
    xianshigezi=[[0,0,0,0,0,0,0,0,0,0],
          [0,0,0,0,0,0,0,0,1,0],
          [0,0,0,0,0,0,0,0,0,0],
          [0,0,0,0,0,0,11,0,0,0],
          [0,0,0,0,0,0,0,0,0,0],
          [0,0,0,0,0,0,0,0,0,0],
          [0,0,0,0,0,0,0,0,0,0],
          [0,0,0,0,0,0,0,0,0,0],
          [0,0,0,0,0,0,0,0,0,0],
          [0,0,0,0,0,0,0,0,0,0],
          
        ];
    onLoad() {
        director.on('xiaobing_sxzy_gezi', this.huasxzy, this);
        // 1. 创建并获取 Graphics 组件
        this.graphics = this.node.getComponent(Graphics);
        if (!this.graphics) {
            this.graphics = this.node.addComponent(Graphics);
        }
        
        // 2. 绘制网格
        
        director.on('xiaobing_position_gezi', this.xiaobingposition, this);
        // 获取角色位置并标记
    const worldPos = this.xiaobing.getWorldPosition();
    const gridPos = this.worldPositionToGrid(worldPos);
    

    console.log("转换结果:", gridPos);
    
    // 关键修正:检查边界并更新数组
    if (this.isInGrid(gridPos.x, gridPos.y)) {
        // 注意:你的数组是 gezi[y][x] 结构!所以要 [gridPos.y][gridPos.x]
        this.gezi[gridPos.y][gridPos.x] = 7;

        this.xianshigezi[gridPos.y][gridPos.x] = 7;
    } else {
        console.warn("角色在网格外!位置:", gridPos);
    }
    
    this.drawGrid(this.gezi);
    director.emit('gezi_ditu_xiaobing', this.gezi);
   
}

// 添加边界检查方法
private isInGrid(x: number, y: number): boolean {
    return x >= 0 && x < this.gridWidth && y >= 0 && y < this.gridHeight;

    }

    // 在gezi.ts中添加一个**可靠的**坐标转换方法
public worldPositionToGrid(worldPos: Vec3): { x: number, y: number } {
    const gridWorldPos = this.node.getWorldPosition();
    const offsetX = worldPos.x - gridWorldPos.x;
    const offsetY = worldPos.y - gridWorldPos.y;
    
    // DEBUG: 打印调试信息

    //console.log("=== 坐标转换调试 ===");
    //console.log("1. 网格中心:", gridWorldPos);

    //console.log("2. 角色位置:", worldPos);
    //console.log("3. 偏移量 offsetX=", offsetX, "offsetY=", offsetY);
    


    // 网格半宽/半高 (注意:这里有坐标轴方向问题)
    const halfWidth = (this.gridWidth * this.cellSize) / 2;
    const halfHeight = (this.gridHeight * this.cellSize) / 2;
    

    // Cocos Y轴向上为正,但数组通常是左下角为(0,0)
    // 所以需要调整Y轴方向
    const gridX = Math.floor((offsetX + halfWidth) / this.cellSize);
    const gridY = Math.floor((offsetY + halfHeight) / this.cellSize);
    
    // Y轴翻转(因为屏幕上方是正Y,但数组从上到下索引)
    const flippedY = (this.gridHeight - 1) - gridY;
    
    //console.log(`4. 计算:gridX=${gridX} (${offsetX}+${halfWidth})/${this.cellSize}`);
    //console.log(`5. 计算:gridY=${gridY} (${offsetY}+${halfHeight})/${this.cellSize}`);


    //console.log(`6. 翻转后:gridX=${gridX}, flippedY=${flippedY}`);
    //console.log(`7. 结果:[${this.gezi[flippedY][gridX]}]`);

    
    // 使用 flippedY 因为数组是从上到下存储
    return { x: gridX, y: flippedY };
}
huoquditu(){
    return this.gezi;
}






















huasxzy(data:any){

    //console.log("....");
    //console.log("/"+data.shangf+"z"+data.zuof+"y"+data.youf+"x"+data.xiaf);
    let xiaof=0;
    //this.hua(data.shangx,data.shangy);
    //this.hua(data.zuox,data.zuoy);
    //this.hua(data.youx,data.youy);

    //this.hua(data.xiax,data.xiay);
    this.huazuixiaof(data.zuixiaofangxiangx,data.zuixiaofangxiangy,data.mubiaox,data.mubiaoy,data.juesex,data.juesey);
    this.drawGrid(this.xianshigezi);

}
hua(x:number,y:number){




    this.xianshigezi[y][x]=4;


}

huazuixiaof(x:number,y:number,mubiaox:number,mubiaoy:number,juesex:number,juesey:number){

    //let mubiaox=0;
    //let mubiaoy=0;

    if(this.gezi[y][x]==11){

        console.log("no");
        return;
        
    }

    // 判断是否是目标点
    const isTargetPoint = (x === mubiaox && y === mubiaoy);
    
    if(isTargetPoint) {
        console.log(`⭐ 这是目标点[${x},${y}],保持为1`);
        // 保持目标标记不变,或者标记为其他区分色
        this.xianshigezi[y][x] = 1; // 保持原目标值
    } else {
        // 普通路径点
        console.log(`📝 标记路径点[${x},${y}]为9`);
        this.xianshigezi[y][x] = 9;
    }

    

}


public gridToWorldPosition(gridX: number, gridY: number): Vec3 {
    const gridWorldPos = this.node.getWorldPosition();


    
    // 计算世界坐标(格子中心点)

    const worldX = gridWorldPos.x + (gridX - this.gridWidth / 2 + 0.5) * this.cellSize;

    const worldY = gridWorldPos.y + 
                  (gridY - this.gridHeight / 2 + 0.5) * this.cellSize;
    
    return new Vec3(worldX, worldY, 0);
}

    xiaobingposition(position:Vec3){
        console.log("xiaobing",position);
    }
    
    drawGrid(g:number[][]) {
        if (!this.graphics) return;
        
        // 清空之前的绘制
        this.graphics.clear();
        
        // 设置线条样式
        this.graphics.lineWidth = this.lineWidth;
        this.graphics.strokeColor = this.lineColor;
        
        // 首先填充背景色
        this.graphics.fillColor = this.fillColor;
        
        // 计算网格的总宽高(用于居中显示)
        const totalWidth = this.gridWidth * this.cellSize;
        const totalHeight = this.gridHeight * this.cellSize;
        
        // 设置绘制原点在节点中心(Cocos默认)
        // 也可以从左上角开始画,看个人习惯
        
        // 绘制每个格子的填充背景
        for (let x = 0; x < this.gridWidth; x++) {
            for (let y = 0; y < this.gridHeight; y++) {
                let huoqugezi=g[y][x];
                // 然后反转Y坐标,让第一行显示在最上面
                const screenY = this.gridHeight - 1 - y;

                const posX = (x - this.gridWidth/2) * this.cellSize;
                //const posY = (y - this.gridWidth/2) * this.cellSize;
                const posY = (screenY - this.gridHeight/2) * this.cellSize;
                if(huoqugezi==1){
                    this.graphics.fillColor = this.targetColor;
                    //this.graphics.rect(posX, posY, this.cellSize, this.cellSize);
                    
                    //console.log(huoqugezi+"shi");
                }else if(huoqugezi==7){
                    this.graphics.fillColor = this.jueseColor;
                    //this.graphics.rect(posX, posY, this.cellSize, this.cellSize);
                    
                    //console.log(huoqugezi+"shi");
                }else if(huoqugezi==4){
                    this.graphics.fillColor = this.xiaColor;
                }else if(huoqugezi==9){
                    this.graphics.fillColor = this.zuixiaoColor;
                }
                else if(huoqugezi==11){
                    this.graphics.fillColor = this.zhangaiColor;
                }
                else{
                    this.graphics.fillColor = this.fillColor;
                }

                    
                    
                
                this.graphics.rect(posX, posY, this.cellSize, this.cellSize);
                    //console.log(huoqugezi);
                    this.graphics.fill();
            }
            
        }
        
        
        // 绘制垂直线
        for (let x = 0; x <= this.gridWidth; x++) {
            const lineX = (x - this.gridWidth/2) * this.cellSize;
            const startY = (-this.gridHeight/2) * this.cellSize;
            const endY = (this.gridHeight/2) * this.cellSize;
            
            this.graphics.moveTo(lineX, startY);
            this.graphics.lineTo(lineX, endY);
        }
        
        // 绘制水平线
        for (let y = 0; y <= this.gridHeight; y++) {
            const lineY = (y - this.gridHeight/2) * this.cellSize;
            const startX = (-this.gridWidth/2) * this.cellSize;
            const endX = (this.gridWidth/2) * this.cellSize;
            
            this.graphics.moveTo(startX, lineY);
            this.graphics.lineTo(endX, lineY);
        }
        
        // 描边完成绘制
        this.graphics.stroke();
        
        // 可选:绘制坐标标签(调试用)
        this.drawCoordinates();
    }
    
    // 绘制坐标标签(可选,调试用)
    private drawCoordinates() {
        const font = '14px Arial';
        for (let x = 0; x < this.gridWidth; x++) {
            for (let y = 0; y < this.gridHeight; y++) {
                const centerX = (x - this.gridWidth/2) * this.cellSize + this.cellSize/2;
                const centerY = (y - this.gridHeight/2) * this.cellSize + this.cellSize/2;
                
                // Graphics 不支持文字,可以用Label或另想办法
                // 这里先注释,下文有改进方法
            }
        }
    }
    
    // 获取格子中心的世界坐标(有用!)
    public getCellCenterPosition(gridX: number, gridY: number): { x: number, y: number } {
        const worldX = this.node.position.x + 
                      (gridX - this.gridWidth/2) * this.cellSize + 
                      this.cellSize/2;
        const worldY = this.node.position.y + 
                      (gridY - this.gridHeight/2) * this.cellSize + 
                      this.cellSize/2;
        return { x: worldX, y: worldY };
    }
    
    // 世界坐标转格子坐标(有用!)
    public worldToGrid(worldX: number, worldY: number): { x: number, y: number } {
        const localX = worldX - this.node.position.x;
        const localY = worldY - this.node.position.y;
        
        const gridX = Math.floor((localX + this.gridWidth * this.cellSize / 2) / this.cellSize);
        const gridY = Math.floor((localY + this.gridHeight * this.cellSize / 2) / this.cellSize);
        
        return { x: gridX, y: gridY };
    }
    
    // 绘制带颜色的格子(用于标记障碍、起点、终点等)
    public drawColoredCell(gridX: number, gridY: number, color: Color) {
        if (!this.graphics) return;
        
        const posX = (gridX - this.gridWidth/2) * this.cellSize;
        const posY = (gridY - this.gridHeight/2) * this.cellSize;
        
        this.graphics.fillColor = color;
        this.graphics.rect(posX, posY, this.cellSize, this.cellSize);
        this.graphics.fill();
    }
    
    
}
相关推荐
瑶光守护者2 小时前
【学习笔记】5G RedCap:智能回落5G NR驻留的接入策略
笔记·学习·5g
你想知道什么?2 小时前
Python基础篇(上) 学习笔记
笔记·python·学习
SHOJYS2 小时前
学习离线处理 [CSP-J 2022 山东] 部署
数据结构·c++·学习·算法
xian_wwq3 小时前
【学习笔记】可信数据空间的工程实现
笔记·学习
Li.CQ3 小时前
SQL学习笔记
笔记·sql·学习
jtymyxmz4 小时前
《Maya 2024 超级学习手册》3.4.8 实例:制作垃圾桶模型
学习·maya
jtymyxmz4 小时前
《Maya 2024 超级学习手册》3.4.6 实例:制作小筐模型
学习·maya
Ada大侦探4 小时前
新手小白学习PowerBI第三弹--------获取项目数据源+KPI、折线图、地图、柱状图可视化展示
学习·数据分析·powerbi
点云SLAM5 小时前
Singularity 英文单词学习
人工智能·学习·奇异点·英文单词学习·雅思备考·singularity