这里的表格是横行数列,也就是x是行,y是列,不要当x/y轴看。
1 | -1 | 0 | 1 | 2 | | -1 | 0 | 1 | 2 |
-1 | | | | | -1 | | [-1,0] | | |
0 | [0,-1] | [0,0] | [0,1] | [0,2] | 0 | | [0,0] | | |
1 | | | | | 1 | | [1,0] | | |
2 | | | | | 2 | | [2,0] | | |
| -1 | 0 | 1 | 2 | | -1 | 0 | 1 | 2 |
-1 | | | | | -1 | | [-1,0] | | |
0 | [0,-1] | [0,0] | [0,1] | [0,2] | 0 | | [0,0] | | |
1 | | | | | 1 | | [1,0] | | |
2 | | | | | 2 | | [2,0] | | |
2 | -1 | 0 | 1 | 2 | | -1 | 0 | 1 | 2 |
-1 | [-1,-1] | [-1,0] | | | -1 | [-1,-1] | [-1,0] | | |
0 | [0,-1] | [0,0] | | | 0 | [0,-1] | [0,0] | | |
1 | | | | | 1 | | | | |
2 | | | | | 2 | | | | |
| -1 | 0 | 1 | 2 | | -1 | 0 | 1 | 2 |
-1 | [-1,-1] | [-1,0] | | | -1 | [-1,-1] | [-1,0] | | |
0 | [0,-1] | [0,0] | | | 0 | [0,-1] | [0,0] | | |
1 | | | | | 1 | | | | |
2 | | | | | 2 | | | | |
3 | -1 | 0 | 1 | 2 | | -1 | 0 | 1 | 2 |
-1 | | [-1,0] | | | -1 | | [-1,0] | | |
0 | [0,-1] | [0,0] | [0,1] | | 0 | | [0,0] | [0,1] | |
1 | | | | | 1 | | [1,0] | | |
2 | | | | | 2 | | | | |
| -1 | 0 | 1 | 2 | | -1 | 0 | 1 | 2 |
-1 | | | | | -1 | | [-1,0] | | |
0 | [0,-1] | [0,0] | [0,1] | | 0 | [0,-1] | [0,0] | | |
1 | | [1,0] | | | 1 | | [1,0] | | |
2 | | | | | 2 | | | | |
4 | -1 | 0 | 1 | 2 | | -1 | 0 | 1 | 2 |
-1 | | [-1,0] | | | -1 | | | | |
0 | | [0,0] | | | 0 | [0,-1] | [0,0] | [0,1] | |
1 | | [1,0] | [1,1] | | 1 | [1,-1] | | | |
2 | | | | | 2 | | | | |
| -1 | 0 | 1 | 2 | | -1 | 0 | 1 | 2 |
-1 | [-1,-1] | [-1,0] | | | -1 | | | [-1,1] | |
0 | | [0,0] | | | 0 | [0,-1] | [0,0] | [0,1] | |
1 | | [1,0] | | | 1 | | | | |
2 | | | | | 2 | | | | |
5 | -1 | 0 | 1 | 2 | | -1 | 0 | 1 | 2 |
-1 | | [-1,0] | | | -1 | [-1,-1] | | | |
0 | | [0,0] | | | 0 | [0,-1] | [0,0] | [0,1] | |
1 | [1,-1] | [1,0] | | | 1 | | | | |
2 | | | | | 2 | | | | |
| -1 | 0 | 1 | 2 | | -1 | 0 | 1 | 2 |
-1 | | [-1,0] | [-1,1] | | -1 | | | | |
0 | | [0,0] | | | 0 | [0,-1] | [0,0] | [0,1] | |
1 | | [1,0] | | | 1 | | | [1,1] | |
2 | | | | | 2 | | | | |
6 | -1 | 0 | 1 | 2 | | -1 | 0 | 1 | 2 |
-1 | [-1,-1] | [-1,0] | | | -1 | | [-1,0] | | |
0 | | [0,0] | [0,1] | | 0 | [0,-1] | [0,0] | | |
1 | | | | | 1 | [1,-1] | | | |
2 | | | | | 2 | | | | |
| -1 | 0 | 1 | 2 | | -1 | 0 | 1 | 2 |
-1 | [-1,-1] | [-1,0] | | | -1 | | [-1,0] | | |
0 | | [0,0] | [0,1] | | 0 | [0,-1] | [0,0] | | |
1 | | | | | 1 | [1,-1] | | | |
2 | | | | | 2 | | | | |
7 | -1 | 0 | 1 | 2 | | -1 | 0 | 1 | 2 |
-1 | | [-1,0] | [-1,1] | | -1 | [-1,-1] | | | |
0 | [0,-1] | [0,0] | | | 0 | [0,-1] | [0,0] | | |
1 | | | | | 1 | | [1,0] | | |
2 | | | | | 2 | | | | |
| -1 | 0 | 1 | 2 | | -1 | 0 | 1 | 2 |
-1 | | [-1,0] | [-1,1] | | -1 | [-1,-1] | | | |
0 | [0,-1] | [0,0] | | | 0 | [0,-1] | [0,0] | | |
1 | | | | | 1 | | [1,0] | | |
2 | | | | | 2 | | | | |
然后根据这个xslx制作成数据然后
import { v2 } from "cc";export const GridConfig = {//素材限制 行row: 12,//列column: 9,//方块宽高blockWidth: 60,blockHeight: 60,//I型shape1: [[v2(0, -1), v2(0, 0), v2(0, 1), v2(0, 2)],[v2(-1, 0), v2(0, 0), v2(1, 0), v2(2, 0)],[v2(0, -1), v2(0, 0), v2(0, 1), v2(0, 2)],[v2(-1, 0), v2(0, 0), v2(1, 0), v2(2, 0)]],//O型shape2: [[v2(-1, -1), v2(-1, 0), v2(0, -1), v2(0, 0)],[v2(-1, -1), v2(-1, 0), v2(0, -1), v2(0, 0)],[v2(-1, -1), v2(-1, 0), v2(0, -1), v2(0, 0)],[v2(-1, -1), v2(-1, 0), v2(0, -1), v2(0, 0)]],//T型shape3: [[v2(-1, 0), v2(0, -1), v2(0, 0), v2(0, 1)],[v2(-1, 0), v2(0, 0), v2(0, 1), v2(1, 0)],[v2(0, -1), v2(0, 0), v2(0, 1), v2(1, 0)],[v2(-1, 0), v2(0, -1), v2(0, 0), v2(1, 0)]],//L型shape4: [[v2(-1, 0), v2(0, 0), v2(1, 0), v2(1, 1)],[v2(0, -1), v2(0, 0), v2(0, 1), v2(1, -1)],[v2(-1, -1), v2(-1, 0), v2(0, 0), v2(1, 0)],[v2(-1, 1), v2(0, -1), v2(0, 0), v2(0, 1)]],//倒L型shape5: [[v2(-1, 0), v2(0, 0), v2(1, -1), v2(1, 0)],[v2(-1, -1), v2(0, -1), v2(0, 0), v2(0, 1)],[v2(-1, 0), v2(-1, 1), v2(0, 0), v2(1, 0)],[v2(0, -1), v2(0, 0), v2(0, 1), v2(1, 1)]],//Z型shape6: [[v2(-1, -1), v2(-1, 0), v2(0, 0), v2(0, 1)],[v2(-1, 0), v2(0, -1), v2(0, 0), v2(1, -1)],[v2(-1, -1), v2(-1, 0), v2(0, 0), v2(0, 1)],[v2(-1, 0), v2(0, -1), v2(0, 0), v2(1, -1)]],//倒Z型shape7: [[v2(-1, 0), v2(-1, 1), v2(0, -1), v2(0, 0)],[v2(-1, -1), v2(0, -1), v2(0, 0), v2(1, 0)],[v2(-1, 0), v2(-1, 1), v2(0, -1), v2(0, 0)],[v2(-1, -1), v2(0, -1), v2(0, 0), v2(1, 0)]],
}
然后是初始化这些东西
//两个二维数组 一个记录node@propertygridNode: Node[][] = [];//一个记录网点数据@propertygridData: number[][] = [];//540*720 一个作为放置的容器@property(Node)gridMap: Node = null;
//一个存放图片资源的数组,7张@property([SpriteFrame])blockSpriteFrame: SpriteFrame[] = [];//数据模型 id指向生成的类型 starPos指向[0,0]的位置 angleIndex指向是这个类型的第几个,就是旋转后的形状shapeData: any = {id: 0,starPos: v2(0, 0),angleIndex: 0}//方块的预制体,加上Sprite、UITransform组件@property({ type: Prefab, displayName: "方块预制体" })blockPrefab: Prefab = null;//开关 是否开始游戏isStart: boolean = false;
初始化的一些操做
//初始化容器中的节点
this.initGridNodes();
//绑定上网点数据,给个0
this.initGridData();
//随机生成一个形状
this.createRadomShape();
this.isStart = true;
//初始化节点 铺满整个容器 不定时的计算位移并渲染形状initGridNodes() {//防止重新被渲染// if (this.gridNode.length) return;const mapWidth = this.gridMap.getComponent(UITransform).contentSize.width;const mapHeight = this.gridMap.getComponent(UITransform).contentSize.height;for (let row = 0; row < GridConfig.row; row++) {//二维数组 第一位不初始化就使用会报错的this.gridNode[row] = [];for (let column = 0; column < GridConfig.column; column++) {const blockNode: Node = instantiate(this.blockPrefab);//从容器节点的左上角开始计算const x: number = -mapWidth / 2 + GridConfig.blockWidth / 2 + GridConfig.blockWidth * column;const y: number = mapHeight / 2 - GridConfig.blockHeight / 2 - GridConfig.blockHeight * row;blockNode.setPosition(v3(x, y, 0));blockNode.setParent(this.gridMap);this.gridNode[row][column] = blockNode;}}}
//绑定数据initGridData() {//ES6新特性,用于快速填充数组默认值0this.gridData = new Array(GridConfig.row).fill(0).map(() => new Array(GridConfig.column).fill(0));}
//随机创建形状createRadomShape() {this.shapeData.id = math.randomRangeInt(1, 8);this.shapeData.angleIndex = math.randomRangeInt(0, 4);const randomColum = math.randomRangeInt(3, 7);//中心点位置 在这里x指向行,y指向列// console.log(this.shapeData);//2-3//特殊判断 [1,0] [1,2] [3,2] [4,1] [5,3]if ((this.shapeData.id === 1 && this.shapeData.angleIndex == 0) ||(this.shapeData.id === 1 && this.shapeData.angleIndex == 2) ||(this.shapeData.id === 3 && this.shapeData.angleIndex == 2) ||(this.shapeData.id === 4 && this.shapeData.angleIndex == 1) ||(this.shapeData.id === 5 && this.shapeData.angleIndex == 3)) {//初始生成形状[0,0]的位置this.shapeData.starPos = v2(0, randomColum);} else {//初始生成形状[0,0]的位置this.shapeData.starPos = v2(1, randomColum);}//检查有没有超出边界if (this.checkShape()) {//渲染形状this.renderShape();} else {console.log("==========结束游戏了======");this.isStart = false;// this.restartGame();// this.start();}}
//检查边界checkShape(): boolean {const shapeConfig = GridConfig[`shape${this.shapeData.id}`][this.shapeData.angleIndex];for (let i = 0; i < shapeConfig.length; i++) {const row = this.shapeData.starPos.x + shapeConfig[i].x;const column = this.shapeData.starPos.y + shapeConfig[i].y;if (row < 0 || row >= GridConfig.row) {return false;}if (column < 0 || column >= GridConfig.column) {return false;}if (this.gridData[row][column] !== 0) {return false;}}return true;}
//确定生成的形状renderShape() {//生成哪一个形状const shapeConfig = GridConfig[`shape${this.shapeData.id}`][this.shapeData.angleIndex]//遍历shapeConfig.forEach(async (blockPos: any) => {const row = this.shapeData.starPos.x + blockPos.x;const column = this.shapeData.starPos.y + blockPos.y;this.gridData[row][column] = this.shapeData.id;//挂上图片this.gridNode[row][column].getComponent(Sprite).spriteFrame = this.blockSpriteFrame[this.shapeData.id - 1];});}
下落的逻辑,可以用计时器,也可在update中
autoDropTime: number = 0;autoDropTimeDela: number = 1;//插值运行update(deltaTime: number) {if (this.isStart) {this.autoDropTime += deltaTime;if (this.autoDropTime >= this.autoDropTimeDela) {this.autoDropShape();this.autoDropTime = 0;}}}
autoDropShape() {//啥也没有就返回if (this.shapeData.id == 0) return;//清空上一个形状this.clearShape();//位移向下this.shapeData.starPos.x += 1;//没有挨边的或者可以自由下落的if (this.checkShape()) {//重新渲染形状this.renderShape();} else {//有挨边的或者不能再次下落的,返回上一个坐标this.shapeData.starPos.x -= 1;//重新渲染形状this.renderShape();//检查是否能够消除this.checkRows();//完事后创建下一个形状this.createRadomShape();}}
clearShape就是清空图片,数据置0
clearShape() {const shapeConfig = GridConfig[`shape${this.shapeData.id}`][this.shapeData.angleIndex];//遍历shapeConfig.forEach(async (blockPos: any) => {const row = this.shapeData.starPos.x + blockPos.x;const column = this.shapeData.starPos.y + blockPos.y;this.gridData[row][column] = [0][0];this.gridNode[row][column].getComponent(Sprite).spriteFrame = null;});}
由下向上过滤一遍容器,有满足的替换成它上面一个的位置,重新渲染
//由下向上检查是否有满格checkRows() {let lastRow: number = GridConfig.row - 1;let needRender: boolean = false;while (lastRow >= 0) {let isFull: boolean = true;for (let column = 0; column < GridConfig.column; column++) {//从左到右有空的if (this.gridData[lastRow][column] === 0) {isFull = false;break;}}if (isFull) {needRender = true;for (let i = lastRow; i > 0; i--) {for (let j = 0; j < GridConfig.column; j++) {this.gridData[i][j] = this.gridData[i - 1][j];}}} else {lastRow--;}}if (needRender) {this.renderGrid();// this.renderShape();}}
图片也改了它
renderGrid() {for (let row = 0; row < GridConfig.row; row++) {for (let column = 0; column < GridConfig.column; column++) {this.gridNode[row][column].getComponent(Sprite).spriteFrame = this.blockSpriteFrame[this.gridData[row][column] - 1];}}}
旋转按钮
onBtnChange() {this.clearShape();//0~3 3最大下面0 剩下的++或--this.shapeData.angleIndex = this.shapeData.angleIndex === 3 ? 0 : this.shapeData.angleIndex + 1;if (this.checkShape()) {this.renderShape();} else {this.shapeData.angleIndex = this.shapeData.angleIndex === 0 ? 3 : this.shapeData.angleIndex - 1;this.renderShape();}}
其它三个按钮,传位置v2(0, -1) v2(0, 1) 向下吗v2(2, 0)/v2(3, 0)
changeShapePos(pos: Vec2) {this.clearShape();this.shapeData.starPos.x += pos.x;this.shapeData.starPos.y += pos.y;if (this.checkShape()) {this.renderShape();} else {this.shapeData.starPos.x -= pos.x;this.shapeData.starPos.y -= pos.y;this.renderShape();}}
重新开始 我这里直接调用的start方法,有点不妥
onBtnRestartGame() {//清空容器下的所用节点for (let i = this.gridMap.children.length - 1; i > 0; i--) {const element = this.gridMap.children[i];element.destroy();}this.start();}
暂定 恢复 就不说了 就是改this.isStart 游戏截图,这样写也有个很大的问题,如果用骨骼或者龙骨动画制作,动画切换会有问题,循环中加setTimeout或者Promise有点问题。
demo抽时间上传一下,在家休息的日子也快要过去了