OpenHarmony- 基于ArkUI (JS)实现数字排序小游戏 原创 精华

中软国际鸿蒙生态
发布于 2022-8-3 10:30
浏览
1收藏

作者:82王先生

前言

拼数字小游戏其实是借鉴了很多前辈写的案例,然后自己去动手写了一下。主要是学习使用OpenHarmony开发相关知识,包括一些API需要自己去踩踩坑才行,小游戏其中还有很多不足之处,后面有时间了会尝试做成闯关的类型,包括统计分数做一个排行榜等其他功能。

效果展示

简单演示一下,因为是4*4的,想拼成可能要花费一些时间。

OpenHarmony- 基于ArkUI (JS)实现数字排序小游戏-鸿蒙开发者社区

排列成功后的效果是这样的!

OpenHarmony- 基于ArkUI (JS)实现数字排序小游戏-鸿蒙开发者社区

实现原理

  1. 创建一个4*4的表格方阵,将一个空白方格和1到15的数字随意打乱在方阵中,使其随机分布。表格上方放一个定时器,用来记录游戏进行的时间,单位为秒,表格下方放一个“开始游戏”的按钮,点击后开始游戏。
  2. 单击控制鼠标,在表格方阵上向上、下、左、右随意一个方向进行移动,计时器开始计时,空白方格周围对应位置的方格会随着鼠标移动的方向,向对应的方向移动一格。
  3. 在进行多次的移动后,所有的数字按照顺序排列完成后,会弹出“你真滴棒!”的提示游戏完成的界面。

使用到的官方API

getContext

getContext(type: ‘2d’, options: ContextAttrOptions): CanvasRendering2dContext

获取canvas绘图上下文 – 不支持在onInit和onReady中进行调用

  • 参数

    参数名 参数类型 必填 描述
    type string 设置为’2d’,返回值为2D绘制对象,该对象可用于在画布组件上绘制矩形、文本、图片等。
    options ContextAttrOptions 当前仅支持配置是否开启抗锯齿功能,默认为关闭。

    表1 ContextAttrOptions

    参数名 类型 说明
    antialias boolean 是否开启抗锯齿功能,默认为false。
  • 返回值

    类型 说明
    CanvasRenderingContext2D 用于在画布组件上绘制矩形、文本、图片等。

fillRect

fillRect(x: number, y: number, width:number, height: number): void

填充一个矩形。

  • 参数

    参数 类型 描述
    x number 指定矩形左上角点的x坐标。
    y number 指定矩形左上角点的y坐标。
    width number 指定矩形的宽度。
    height number 指定矩形的高度。

fillText

fillText(text: string, x: number, y: number): void

绘制填充类文本。

  • 参数

    参数 类型 描述
    text string 需要绘制的文本内容。
    x number 需要绘制的文本的左下角x坐标。
    y number 需要绘制的文本的左下角y坐标。

代码实现

1. html代码

<div class="container" >
    <text class="times">
        游戏用时:{{ currentTime}} 秒
    </text>
    <stack class="stack">
        <canvas class="canvas" ref="canvas" onswipe="onSwipeGrids"></canvas>
        <div class="success" show="{{isShow}}">
            <text class="gameOver">
                你真滴棒!
            </text>
        </div>
    </stack>
    <input type="button" value="开始游戏" class="tip" onclick="startGame"/>
</div>

2. css代码

.container {
    flex-direction: column;
    justify-content: center;
    align-items: center;
    width:100%;
    height:100%;
    margin: 0 auto;
}
.times{
    font-size: 25px;
    text-align:center;
    width:300px;
    letter-spacing:0px;
}
.canvas{
    width:100%;
    height:100%;
    background-color: #FFEFD5     ;
}
.tip{
    
    width:150px;
    height:35px;
    background-color: #20B2AA;
    font-size:25px;
    margin-top:10px;
    margin-bottom: 5px;
}

.stack{
    width: 305px;
    height: 305px;
    margin-top: 10px;
}
.success {
    left:50px;
    top:95px;
    width: 220px;
    height: 130px;
    justify-content: center;
    align-items: center;
    background-color: #E9C2A6;
}
.gameOver {
    font-size: 38px;
    color: black;
}

3. js代码

var grids;
var context;
var timer;

const sideLen = 70; // 方格的边长
const margin = 5; // 方格的间距

export default {
    data: {
        currentTime: '0.0', // 游戏用时
        isShow: false, // 控制‘你真滴棒’弹出框的显示或隐藏
    },
    onInit() {
        // 二维数组grids
        grids = [[1, 2, 3, 4],
        [5, 6, 7, 8],
        [9, 10, 11, 12],
        [13, 14, 15, 0]];
    },

    isInitGrids() {
        let array = ["left", "up", "right", "down"];
        for (let i = 0; i < 100; i++) {
            let randomIndex = Math.floor(Math.random() * 4); // 生成随机整数
            let direction = array[randomIndex]; // 获取上下左右方向值
            this.changeGrids(direction);
        }
    },
    onReady() {
        this.isInitGrids();

    },
    onShow() {
        context = this.$refs.canvas.getContext('2d'); // 获取canvas绘图上下文
        this.drawGrids();
    },
    drawGrids() {
        for (let row = 0; row < 4; row++) {
            for (let column = 0; column < 4; column++) {
                let gridStr = grids[row][column].toString();
                context.fillStyle = "#87CEEB"; // context的方格的颜色
                let leftTopX = column * (margin + sideLen) + margin; // X坐标
                let leftTopY = row * (margin + sideLen) + margin; // y坐标
                context.fillRect(leftTopX, leftTopY, sideLen, sideLen); // 填充
                context.textBaseline = 'top'
                context.font = "30px";
                if (gridStr != "0") { // 除空白格外其他的格子
                    context.fillStyle = "#000000"; // 数字的颜色
                    let offsetX = (4 - gridStr.length) * (sideLen / 8);
                    let offsetY = (sideLen - 30) / 2;
                    context.fillText(gridStr, leftTopX + offsetX, leftTopY + offsetY); // 绘制填充文本
                }
            }
        }
    },
   // 点击开始游戏后计时的方法
    runIt() {
        this.currentTime = (Math.floor(parseFloat(this.currentTime) * 10 + 1) / 10).toString();
        if (parseFloat(this.currentTime) % 1 == 0) {
            this.currentTime = this.currentTime + ".0";
        }
    },
    // 滑动事件的方法
    onSwipeGrids(e) {
        this.changeGrids(e.direction);
        this.drawGrids();
        // 如果this.gameOver()返回true,则清除定时,显示“你真滴棒”表示游戏结束
        if (this.gameOver()) {
            clearInterval(timer);
            this.isShow = true;
        }
    },
    // 判断游戏结束的函数
    gameOver() {
        // 定义一个成功的二维数组oriGrids
        let oriGrids = [[1, 2, 3, 4],
        [5, 6, 7, 8],
        [9, 10, 11, 12],
        [13, 14, 15, 0]];
        for (let row = 0; row < 4; row++) {
            for (let column = 0; column < 4; column++) {
                // 如果二维数组grids不等于二维数组oriGrids返回false继续游戏
                if (grids[row][column] != oriGrids[row][column]) {
                    return false;
                }
            }
        }
        return true; // 结束游戏
    },
    // 点击挪动网格
    changeGrids(direction) {
        let x;
        let y;
        for (let row = 0; row < 4; row++) {
            for (let column = 0; column < 4; column++) {
                if (grids[row][column] == 0) { // 拿到坐标
                    x = row;
                    y = column;
                    break;
                }
            }
        }
        let temp;
        if (this.isShow == false) {
            if (direction == 'up' && (x + 1) < 4) { // 向上移动(x+1必须小于四)
                temp = grids[x + 1][y];
                grids[x + 1][y] = grids[x][y];
                grids[x][y] = temp;
            } else if (direction == 'down' && (x - 1) > -1) { // 向下移动(x-1必须大于负一)
                temp = grids[x - 1][y];
                grids[x - 1][y] = grids[x][y];
                grids[x][y] = temp;
            } else if (direction == 'left' && (y + 1) < 4) { // 向左移动(y + 1必须小于四)
                temp = grids[x][y + 1];
                grids[x][y + 1] = grids[x][y];
                grids[x][y] = temp;
            } else if (direction == 'right' && (y - 1) > -1) { // 向右移动(y-1必须大于负一)
                temp = grids[x][y - 1];
                grids[x][y - 1] = grids[x][y];
                grids[x][y] = temp;
            }
        }
    },
    startGame() {
        timer = setInterval(this.runIt, 100); // 1秒定时执行
        this.isInitGrids();
        this.currentTime = "0.0"; // 初始化游戏用时
        this.isShow = false;
        this.onShow();
    }
}


总结

H5中使用的样式或者方法有些是在OpenHarmony开发过程中无法使用的,要进行FA开发需要多读OpenHarmony的文档,后续的开发中也需要多踩坑,多总结,多练习!有不好的地方欢迎指正!每天进步一点点。

更多原创内容请关注:中软国际 HarmonyOS 技术团队

入门到精通、技巧到案例,系统化分享HarmonyOS开发技术,欢迎投稿和订阅,让我们一起携手前行共建鸿蒙生态。

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
4
收藏 1
回复
举报
4条回复
按时间正序
/
按时间倒序
只有敬亭山
只有敬亭山

哦豁,新的小游戏,666

1
回复
2022-8-3 11:19:41
红叶亦知秋
红叶亦知秋

只留一个空位有点像是基础版的华容道了,4*4的大小正好,5*5感觉确实太折磨人了。 

1
回复
2022-8-3 15:05:34
82王先生
82王先生

真强呀

1
回复
2022-8-3 16:19:41
lollipoptt
lollipoptt

mc王先生----一个被前端事业耽搁的喊麦音乐高手

2
回复
2022-8-3 16:20:06
回复
    相关推荐