Bläddra i källkod

添加测试2048 demo

haojianlong 4 år sedan
förälder
incheckning
623eaa7cae

+ 462 - 0
docs/.vuepress/components/engine/demo/2048test.vue

@@ -0,0 +1,462 @@
+import {STextAlign} from "@persagy-web/draw/lib";
+<template>
+    <div>
+        <canvas id="canvas" width="410" height="410" style="background: #bbada0;border-radius: 10px" tabindex="0"></canvas>
+        <el-button @click="reset" type="primary">重新开始</el-button>
+    </div>
+</template>
+
+<script lang="ts">
+    import {Component, Vue} from "vue-property-decorator"
+    import {SCanvasView, SColor, SPainter, STextAlign, STextBaseLine} from "@persagy-web/draw/lib";
+
+    /**
+     * 2048
+     *
+     * @author 郝洁 <haojie@persagy.com>
+     */
+    class GameView extends SCanvasView {
+        /** 格子宽度 */
+        box_width: number = this.width * 0.8 * 0.25;
+        margin_width: number = this.width * 0.2 * 0.20;
+        /** */
+        gridMap: number[][] = [];
+        /** */
+        score: number = 0;
+        /** 游戏结束 */
+        isGameOver: boolean = false;
+        /** 颜色 */
+        color = {
+            0:{
+                font: "#ffffffff",
+                background: "#eee4da59"
+            },
+            2: {
+                font: "#776e65",
+                background: "#eee4da"
+            },
+            4: {
+                font: "#776e65",
+                background: "#ede0c8"
+            },
+            8: {
+                font: "#f9f6f2",
+                background: "#f2b179"
+            },
+            16: {
+                font: "#f9f6f2",
+                background: "#f59563"
+            },
+            32: {
+                font: "#f9f6f2",
+                background: "#f67c5f"
+            },
+            64: {
+                font: "#f9f6f2",
+                background: "#f65e3b"
+            },
+            128: {
+                font: "#f9f6f2",
+                background: "#edcf72"
+            },
+            256: {
+                font: "#f9f6f2",
+                background: "#edcc61"
+            },
+            512: {
+                font: "#f9f6f2",
+                background: "#edc850"
+            },
+            1024: {
+                font: "#f9f6f2",
+                background: "#edc53f"
+            },
+            2048: {
+                font: "#f9f6f2",
+                background: "#edc22e"
+            },
+        };
+
+
+        /**
+         * 构造函数
+         *
+         * @param id canvas DOM id
+         */
+        constructor(id: string) {
+            super(id);
+            this.init()
+        }
+
+        /**
+         * 初始化游戏
+         */
+        init(): void {
+            this.gridMap = [];
+            for (let row = 0; row < 4; row++) {    // 循环行数
+                const m1: number[] = [];
+                for (let col = 0; col < 4; col++) {    // 循环列数
+                    m1.push(0);
+                }
+                this.gridMap.push(m1);
+            }
+
+            // 初始化分数
+            this.score = 0;
+            // 游戏结束标记为 false
+            this.isGameOver = false;
+            // 生成随机位置的数字
+            this.generateOneNumber('left');
+        }
+
+        /**
+         * 键盘按下事件
+         *
+         * @param   event   事件对象
+         */
+        onKeyDown(event: KeyboardEvent): void {
+            if (this.isGameOver) {
+                return;
+            }
+            let moved, merged;
+            // 按键判断
+            switch (event.code) {
+                case "KeyW": // 上移动作
+                case "ArrowUp":
+                    moved = this.moveToFill('top');
+                    merged = this.mergeGrid('top');
+                    (moved || merged) && this.generateOneNumber('top');
+                    break;
+
+                case "KeyA": // 左移动作
+                case "ArrowLeft":
+                    moved = this.moveToFill('left');
+                    merged = this.mergeGrid('left');
+                    (moved || merged) && this.generateOneNumber('left');
+                    // this.update()
+                    break;
+
+                case "KeyD":    // 右移动作
+                case "ArrowRight":
+                    // 判断游戏是否继续,左部产生随机位置随机数
+                    moved = this.moveToFill('right');
+                    merged = this.mergeGrid('right');
+                    (moved || merged) && this.generateOneNumber('right');
+                    break;
+                // 按键 下
+                case "KeyS": // 下移动作
+                case "ArrowDown":
+                    // 判断游戏是否继续,上部产生随机位置随机数
+                    moved = this.moveToFill('bottom');
+                    merged = this.mergeGrid('bottom');
+                    (moved || merged) && this.generateOneNumber('bottom');
+                    break;
+                default :
+                // do nothing
+            }
+            this.isGameOver = this.checkIsOver();
+        }
+
+        /**
+         * 生成随机的格子
+         */
+        generateOneNumber(direction: string): void {
+            let temp = [];
+            if (direction == "left") {
+                for (let i = 0; i < 4; i++) {
+                    temp.push(this.gridMap[i][3])
+                }
+            } else if (direction == "top") {
+                temp = this.gridMap[3];
+            } else if (direction == "bottom") {
+                temp = this.gridMap[0];
+            } else {
+                // (direction == "right")
+                for (let i = 0; i < 4; i++) {
+                    temp.push(this.gridMap[i][0])
+                }
+            }
+
+            let indexArr = [];
+            for(let i = 0; i < temp.length; i++) {
+                if(temp[i] == 0) {
+                    indexArr.push(i)
+                }
+            }
+            const len = indexArr.length;
+            if (len) {
+                const random = Math.floor(len * Math.random());
+                const index = indexArr[random];
+                if (direction == "left") {
+                    this.gridMap[index][3] = 2
+                } else if (direction == "top") {
+                    this.gridMap[3][index] = 2;
+                } else if (direction == "bottom") {
+                    this.gridMap[0][index] = 2;
+                } else {
+                    // (direction == "right")
+                    this.gridMap[index][0] = 2
+                }
+                this.update()
+            } else {
+                // this.isGameOver = true;
+                this.update();
+            }
+
+            //随机一个位置,取新方块出现的位置
+
+            //随机一个数字 2 或 4 ,在随机位置显示随机数字
+        }
+
+        /**
+         * 移动数字,使移动方向的数字填满
+         */
+        moveToFill(direction: string): boolean{
+            let flag = false;
+            if (direction == "left") {
+                for (let i = 0; i < 4; i++) {
+                    const tempJrr = new Array(4).fill(0);
+                    let index = 0;
+                    for (let j = 0; j < 4; j++) {
+                        if (this.gridMap[i][j]!=0) {
+                            tempJrr[index] = this.gridMap[i][j];
+                            index++;
+                        } else {
+                            flag = true;
+                        }
+                    }
+                    this.gridMap[i] = tempJrr;
+                }
+            } else if (direction == "top") {
+                for (let j = 0; j < 4; j++) {
+                    const tempJrr = new Array(4).fill(0);
+                    let index = 0;
+                    for (let i = 0; i < 4; i++) {
+                        if (this.gridMap[i][j]!=0) {
+                            tempJrr[index] = this.gridMap[i][j];
+                            index++;
+                        } else {
+                            flag = true;
+                        }
+                    }
+                    for(let u = 0; u < 4; u++) {
+                        this.gridMap[u][j] = tempJrr[u];
+                    }
+                }
+            } else if (direction == "bottom") {
+                for (let j = 0; j < 4; j++) {
+                    const tempJrr = new Array(4).fill(0);
+                    let index = 3;
+                    for (let i = 3; i >= 0; i--) {
+                        if (this.gridMap[i][j]!=0) {
+                            tempJrr[index] = this.gridMap[i][j];
+                            index--;
+                        } else {
+                            flag = true;
+                        }
+                    }
+                    for(let u = 3; u >= 0; u--) {
+                        this.gridMap[u][j] = tempJrr[u];
+                    }
+                }
+            } else {
+                for (let i = 0; i < 4; i++) {
+                    const tempJrr = new Array(4).fill(0);
+                    let index = 3;
+                    for (let j = 3; j >= 0; j--) {
+                        if (this.gridMap[i][j]!=0) {
+                            tempJrr[index] = this.gridMap[i][j];
+                            index--;
+                        } else {
+                            flag = true;
+                        }
+                    }
+                    this.gridMap[i] = tempJrr;
+                }
+            }
+            return flag;
+        }
+
+        /**
+         * 合并数字
+         *
+         * @param direction     方向
+         */
+        mergeGrid(direction: string): boolean{
+            let flag = false;
+            if (direction == "left") {
+                for (let i = 0; i < 4; i++) {
+                    for (let j = 0; j < 3; j++) {
+                        if (this.gridMap[i][j] == this.gridMap[i][j + 1]) {
+                            this.gridMap[i][j] = 2*this.gridMap[i][j];
+                            this.gridMap[i][j + 1] = 0;
+                            flag = true;
+                        }
+                    }
+                }
+            } else if (direction == "top") {
+                for (let i = 0; i < 3; i++) {
+                    for (let j = 0; j < 4; j++) {
+                        if (this.gridMap[i][j] == this.gridMap[i + 1][j]) {
+                            this.gridMap[i][j] = 2*this.gridMap[i][j];
+                            this.gridMap[i + 1][j] = 0;
+                            flag = true;
+                        }
+                    }
+                }
+            } else if (direction == "bottom") {
+                for (let i = 3; i >= 1; i--) {
+                    for (let j = 0; j < 4; j++) {
+                        if (this.gridMap[i][j] == this.gridMap[i - 1][j]) {
+                            this.gridMap[i][j] = 2*this.gridMap[i][j];
+                            this.gridMap[i - 1][j] = 0;
+                            flag = true;
+                        }
+                    }
+                }
+            } else {
+                // (direction == "right")
+                for (let i = 0; i < 4; i++) {
+                    for (let j = 3; j >= 1; j--) {
+                        if (this.gridMap[i][j] == this.gridMap[i][j - 1]) {
+                            this.gridMap[i][j] = 2*this.gridMap[i][j];
+                            this.gridMap[i][j - 1] = 0;
+                            flag = true;
+                        }
+                    }
+                }
+            }
+            if (flag) {
+                this.moveToFill(direction)
+            }
+            return flag;
+        }
+
+        /**
+         * 绘制游戏画面
+         *
+         * @param painter   绘制对象
+         */
+        onDraw(painter: SPainter): void {
+            painter.clearRect(0, 0, this.width, this.height);
+
+            painter.pen.color = SColor.Transparent;
+            this.drawMap(painter);
+
+            this.drawNum(painter);
+
+            // 如果游戏结束,绘制文字
+            if (this.isGameOver) {
+                painter.brush.color = SColor.Blue;
+                painter.font.size = 20;
+                painter.font.textAlign = STextAlign.Center;
+                painter.drawText("GAME OVER", 180, 30);
+                // return;
+            }
+        }
+
+        /**
+         * 绘制数字
+         */
+        drawNum(painter: SPainter): void {
+            // 遍历行
+            for (let row = 0; row < 4; row++) {
+                // 遍历列
+                for (let col = 0; col < 4; col++) {
+                    this.drawCellNum(painter, row, col, this.gridMap[row][col]);
+                }
+            }
+        }
+
+        /**
+         * 绘制格子中的数字
+         */
+        drawCellNum(painter: SPainter, row: number, col: number, type: number): void {
+            const x = col * 100 + 10;
+            const y = row * 100 + 10;
+            if (type != 0) {
+                painter.font.textAlign = STextAlign.Center;
+                painter.font.size = 40;
+                // @ts-ignore
+                painter.font.textBaseLine = STextBaseLine.Middle;
+                painter.brush.color = new SColor(this.color[type].font);
+                painter.drawText(type+'', x+45, y+45);
+            }
+        }
+
+        /**
+         * 绘制背景图
+         */
+        drawMap(painter: SPainter) {
+            // 遍历行
+            for (let row = 0; row < 4; row++) {
+                // 遍历列
+                for (let col = 0; col < 4; col++) {
+                    this.drawCell(painter, row, col, this.gridMap[row][col]);
+                }
+            }
+        }
+
+        /**
+         * 绘制具体格子
+         *
+         * @param painter   绘制对象
+         * @param row       行
+         * @param col       列
+         * @param type      图类型
+         */
+        private drawCell(painter: SPainter, row: number, col: number, type: number): void {
+            const x = col * 100 + 10;
+            const y = row * 100 + 10;
+            painter.brush.color = new SColor(this.color[type].background);
+            painter.drawRoundRect(x, y, 90, 90, 10);
+        }
+
+
+        /**
+         * 检测结束
+         */
+        checkIsOver():boolean{
+            for(let i = 0; i < 4; i++) {
+                if (this.gridMap[i].indexOf(0) > -1) {
+                    return false;
+                }
+                for(let j = 0; j < 3; j++) {
+                    if (this.gridMap[i][j] == this.gridMap[i][j+1]) {
+                        return false
+                    }
+                    if (i < 3 && this.gridMap[i][j] == this.gridMap[i+1][j]){
+                        return false
+                    }
+                }
+            }
+            return this.gridMap[3][3] != this.gridMap[2][3];
+        }
+    }
+
+    @Component
+    export default class Gcanvas extends Vue {
+        /** 实例化 */
+        view: GameView | null = null;
+
+        /**
+         * 页面挂载完成
+         */
+        mounted(): void {
+            this.view = new GameView('canvas');
+            document.getElementById('canvas')!!.focus()
+        }
+
+        /**
+         * 重置操作
+         */
+        reset(): void {
+            this.view!!.init()
+            document.getElementById("canvas")!!.focus()
+        }
+    }
+</script>
+
+<style scoped>
+
+</style>

+ 2 - 0
docs/guides/engine/demo/2048.md

@@ -4,6 +4,8 @@
 [[toc]]
 :::
 
+<engine-demo-2048 />
+
 规则 游戏画布大小 4 * 4
 
 初始化 两个方块 数字为2

+ 1 - 0
docs/guides/index.js

@@ -28,6 +28,7 @@ const content = [
                 children: [
                     ["/guides/engine/demo/elsfk", "俄罗斯方块"],
                     ["/guides/engine/demo/elsfkDifficult", "俄罗斯方块-英雄版"],
+                    ["/guides/engine/demo/2048", "2048"],
                 ]
             }
         ]