diff --git a/web/src/assets/scripts/Cell.js b/web/src/assets/scripts/Cell.js new file mode 100644 index 0000000..16d5984 --- /dev/null +++ b/web/src/assets/scripts/Cell.js @@ -0,0 +1,11 @@ +// 定义一个格子 +export class Cell { + // 参数是格子的行数和列数 + constructor(r,c){ + this.r = r; + this.c = c; + // 坐标转换,用于确定蛇的每节身体所在格子中心点的坐标 + this.x = c + 0.5; + this.y = r + 0.5; + } +} \ No newline at end of file diff --git a/web/src/assets/scripts/GameMap.js b/web/src/assets/scripts/GameMap.js index 9487cf0..9752eea 100644 --- a/web/src/assets/scripts/GameMap.js +++ b/web/src/assets/scripts/GameMap.js @@ -1,5 +1,6 @@ // 在 AcGameObject.js 里使用的是 export class ,因此这里需要使用 {} 括起来引用;如果是 export default 则不需要用括号括起来 import { AcGameObject } from "./AcGameObject"; +import { Snake } from "./Snake"; // 导入墙组件 import { Wall } from "./Wall"; @@ -18,8 +19,9 @@ export class GameMap extends AcGameObject{ this.L = 0; // 定义棋盘格的行数和列数 + // 行数和列数不同时设置为偶数或者不同时设置为奇数,可以避免AB两蛇同时进入同一个格子,避免因此对优势者不公平 this.rows = 13; - this.cols = 13; + this.cols = 14; // 绘制棋盘内部区域的障碍物(墙)的数量 this.inner_walls_count = 50; @@ -27,6 +29,13 @@ export class GameMap extends AcGameObject{ // 存储所有的墙 // 上面的 super() 会先将 AcGameObject 先绘制, walls 的绘制在后面执行,因此墙最后会覆盖原棋盘格进行绘制 this.walls = []; + + // 创建蛇对象数组 + this.snakes = [ + // 注意这里的对象生成方式和传参方式 + new Snake({id: 0, color: "#4876ec", r: this.rows-2, c: 1}, this), + new Snake({id: 1, color: "#f94848", r: 1, c: this.cols-2}, this), + ]; } // 判断函数:判断角色路径是否联通。传入参数:g数组,起点和终点的横纵坐标 @@ -83,13 +92,17 @@ export class GameMap extends AcGameObject{ // 主对角线对称 g[r][c] 和 g[c][r] 完成两种联合判断 // 当此位置已经有障碍物了,则重新计算下一个位置 - if(g[r][c] || g[c][r]) continue; + // if(g[r][c] || g[c][r]) continue; + // 解决中心对称问题,需要将注释代码修改为下一行 + if(g[r][c] || g[this.rows-1-r][this.cols-1-c]) continue; // 将计算求得的随机障碍物的位置置为 true ,以对该位置进行绘制 // g[r][c] 和 g[c][r] 的坐标在对角线位置会重合,会被绘制为一个障碍物 - g[r][c] = g[c][r] = true; + // g[r][c] || g[c][r] = true; + // 解决中心对称问题,需要将注释代码修改为下一行 + g[r][c] = g[this.rows-1-r][this.cols-1-c] = true; - // 1000 次中,规定数量的内部障碍物已经够了之后就 break 掉 + // 1000 次中,规定数量的内部障碍物已经够了之后就 break 掉 break; } } diff --git a/web/src/assets/scripts/Snake.js b/web/src/assets/scripts/Snake.js new file mode 100644 index 0000000..12c3458 --- /dev/null +++ b/web/src/assets/scripts/Snake.js @@ -0,0 +1,51 @@ +// 每条蛇定义成一个对象 +import { AcGameObject } from "./AcGameObject"; +import { Cell } from "./Cell"; + +// 需要继承自绘制基础类 AcGameObject ,用于蛇的绘制刷新 +export class Snake extends AcGameObject { + // 参数:蛇的信息 info ,当前游戏地图 gamemap + constructor(info, gamemap) { + super(); + + // 每条蛇的 id 用于区分每条蛇, color 用于定义蛇的颜色 + this.id = info.id; + this.color = info.color; + // 调用地图的引用获取一些地图参数,例如:每个格子的边长 + this.gamemap = gamemap; + + // 蛇初始只有一个点(蛇头),初始时只需要定义出蛇头即可。初始坐标为每条蛇的起始位置 + // cells[] 存放蛇的身体, cells[0] 存放蛇头 + this.cells = [new Cell(info.r, info.c)] + } + + start() { + + } + + update() { + // 每次更新蛇类对象都重新调用一次渲染 + this.render(); + } + + // render 不来自基类,需要本类自己实现 + render() { + // 取出单元格长度引用和画布 + const L = this.gamemap.L; + const ctx = this.gamemap.ctx; + + // 画圆(蛇的身体结点) + ctx.fillStyle = this.color; + // 蛇的身体不止一节,需要枚举画出所有的肢结。of 遍历 cells 值 + for(const cell of this.cells){ + // 画成正方形 + // ctx.fillRect(cell.c * L, cell.r * L, L, L); + + // 画成圆形 + ctx.beginPath(); + ctx.arc(cell.x * L, cell.y * L, L * 0.5, 0, 2*Math.PI); + // 填充颜色 + ctx.fill(); + } + } +} \ No newline at end of file