简单四方向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();
    }
    
    
}
相关推荐
西岸行者3 天前
学习笔记:SKILLS 能帮助更好的vibe coding
笔记·学习
悠哉悠哉愿意3 天前
【单片机学习笔记】串口、超声波、NE555的同时使用
笔记·单片机·学习
别催小唐敲代码3 天前
嵌入式学习路线
学习
毛小茛4 天前
计算机系统概论——校验码
学习
babe小鑫4 天前
大专经济信息管理专业学习数据分析的必要性
学习·数据挖掘·数据分析
winfreedoms4 天前
ROS2知识大白话
笔记·学习·ros2
在这habit之下4 天前
Linux Virtual Server(LVS)学习总结
linux·学习·lvs
我想我不够好。4 天前
2026.2.25监控学习
学习
im_AMBER4 天前
Leetcode 127 删除有序数组中的重复项 | 删除有序数组中的重复项 II
数据结构·学习·算法·leetcode
CodeJourney_J4 天前
从“Hello World“ 开始 C++
c语言·c++·学习