【合成数字】合成类游戏-uniapp项目开发流程详解

以前玩过2048游戏,从中发现规律,想到跟合成类游戏相似,知道为什么很相似吗,在这里,做一个数字合成游戏玩玩吧,感兴趣的话可以看看,这里给大家讲一讲数字合成游戏的开发过程。

文章目录

  • 创建项目
  • 页面布局
    • 初始页面
    • 游戏页面
  • 游戏逻辑
    • 加载模块
    • 初始化画布
    • 初始化游戏数据
    • 绘制游戏状态
    • 绘制网格
    • 开始游戏
    • 重新开始
    • 触摸事件
  • 游戏测试

创建项目

这里用HBuilderX开发工具来创建一个uniapp项目,

例如项目名填写uniapp_CompositeNumber,依次选择如下图
在这里插入图片描述

  • 选择新建uni-app项目
  • 使用默认模板
  • Vue版本选择 3

页面布局

新建好项目,会看到自动创建了一个初始页面文件,

初始页面

文件位置在pages/index/index.vue,打开看看,

在页面布局中,对应的template标签里添加一个按钮组件,按钮名叫进入游戏,

然后在script标签里,添加一个按钮点击方法,实现打开游戏页面,

打开页面的代码很简单,自己能写出来吧,这里就不展开讲,

游戏页面

需要自己创建一个游戏页面,

页面文件在pages/game/game.vue,打开接着写,

在页面布局中,对应的template标签里添加,内容如下

<!--pages/game/game.wxml-->
<view class="page">
    <canvas type="2d" id="zs1028_csdn" class="canvas" bindtouchstart="onTouchStart" bindtouchmove="onTouchMove" bindtouchend="onTouchEnd" disable-scroll="{{true}}"/>
</view>

就这么简单,只放一个canvas组件即可,组件的一些属性不用说能看懂吧

写好后,要做出运行的游戏页面效果,就像如下图这样
在这里插入图片描述

看着是不是很像2048游戏呢,没错,与其不同的是从数字1开始计算,
实现思路,就是把两个相同的数字合成,如1+1=2,计算规则n+n=2n

游戏逻辑

接下来,在script标签里,写游戏逻辑,

加载模块

开始写初始化代码,先加载游戏模块,添加代码如下

// pages/game/game.js
import ZS1028_CSDN from '../../utils/zs1028_CSDN.js'
import Gesture from '../../utils/gesture.js'

const app = getApp()

Page({
     //...
    /**
     * 生命周期函数--监听页面初次渲染完成
     */
    async onReady() {
       //...这里处理初始化
    },
    /**
     * 生命周期函数--监听页面卸载
     */
    onUnload() {
        if(this.timer) clearTimeout(this.timer)
        this.game?.destroy()
    },
    /**
    * 以下是通过canvas的触摸事件来调用
    */
    onTouchStart(e) {...},

    onTouchMove(e) {...},

    onTouchEnd(e) {...},
})

导入的两个模块,想必看过之前笔者发布过文章的读者会有点映像,
Gesture ,是一个处理触摸手势模块,有参考文章 关于手机中的触摸手势操作实现过程详解;
ZS1028_CSDN ,是一个游戏引擎框架模块,让游戏实现变得简单;

初始化画布

游戏大致的思路呢,是要先把画布初始化,然后绘制出来游戏画面,

也就是绘制网格,然后绘制一些数字在上面,

就在onReady()方法里写,画布初始化的逻辑,代码如下

const { node: canvas, width, height } = await ZS1028_CSDN.query('#zs1028_csdn')
Object.assign(canvas, { width, height })
const game = ZS1028_CSDN.createMiniGameEngine({
      canvas,
     // isTest: true //游戏测试用途
})
this.game = game

初始化游戏数据

继续写下去,初始化游戏数据,代码如下,

//游戏状态数据
const gameState = {
    bottom: 38 //游戏标题底部位置
}
//游戏网格数据
const gridsData = {
    grids: [], //游戏网格列表
    cols: 5, //网格列数
    isNew: false, //是否出现新的数字 
}

绘制游戏状态

接下来,调用游戏对象的绘制过程,

这是绘制游戏标题,显示游戏状态,代码如下

const that = this
//初始化游戏标题层
game.initTopBar({
    data: gameState,
    reset() {
    	//重置数据的
        Object.assign(this.data,{
            scope: 0,
            best: app.getMaxScope(),
            timerNum: 300,
        })
    },
    redraw(data) {
        const { canvas, context: ctx, topBar } = data
        let { scope, best, timerNum } = this.data
        //这里绘制游戏标题区域...
    }
})

绘制网格

接下来,绘制出来网格,代码如下

//添加游戏背景层,绘制网格
game.addBgObject({
    data: gridsData,
    reset() {
        const { grids } = this.data
        //...这里重置游戏网格数据
		//添加随机数字到网格
        for(let i=0;i<5;i++){
            this.addRandomGridValue()
        }
    },
    redraw(data) {
        const { canvas, context: ctx, topBar } = data
        let { cols, grids, gridSize, isNew } = this.data
        if (!this.cacheBgImg) {
            //...在这里画背景图片,也就是绘制网格,第一次就要画出来,导出图片,然后就直接用图片绘制来代替
            return
        }
        //...判断一个状态,如果要新的随机位置数字
        if (isNew) {
            this.addRandomGridValue()
            //添加好,就重置一下状态
            this.data.isNew = false
        }
        //这里先绘制背景图片(网格)
        ctx.drawImage(this.cacheBgImg, 0, 0, canvas.width, canvas.height)
        let r = gridSize / 2
        //...这里绘制网格中的数字
        grids.forEach(g => {
            if (g.value < 1) return
            //...绘制数字value
            ctx.fillText(g.value, g.x + g.relX + r, g.y + g.relY + r * 1.1)
            //...这之后就是绘制移动数字动画的,代码虽少,但不好理解
        })
    },
    methods: {
        addRandomGridValue() {
            //...自定义方法,实现添加随机位置的数
        }
    }
})

开始游戏

最后,准备就绪,开始游戏,代码如下

//将初始化数据存放好
this.gameData = {
    gameState,
    gridsData
}
//最后,调用此方法开始游戏
this.restart()

重新开始

写重新开始的逻辑很简单,

在开始游戏调用方法restart()里有实现,代码如下

game.reset()
//...其它的初始化逻辑
game.run()

可见,重新开始游戏,只需调用游戏对象game的两个方法就可以了

触摸事件

接下来,处理画布canvas触摸事件,让游戏与玩家交互,

用到了处理手势的模块,这实现会变得简单,

开始触摸时,记录下按下的点数据,

就是触摸开始点touch1 和移动到最后的点touch2两个,代码如下

onTouchStart(e) {
 if (this.isGameEnd || this.startAnimating) return
    this.touch1 = e.touches[0]
},

onTouchMove(e) {
    if (!this.touch1) return
    this.touch2 = e.touches[0]
},

触摸移动结束时,调用手势模块的方法,就能得出滑动的方向,

这样就知道往哪个方向移动,来处理网格里的一些数字移动,

实现移动的逻辑,加上动画,这会变得复杂一些,

仔细构思一下,就写了出来,代码如下

onTouchEnd(e) {
    if (this.touch1 && this.touch2) {
    	//通过调用模块的方法获取
        let g = Gesture.touchesToG(this.touch1, this.touch2)
        let list = this.scanGrids(g)
        let gs = []
        let isReverse //是否反向排列
        //判断是哪个手势
        switch (g) {
            case Gesture.G.left:
            case Gesture.G.right:
                isReverse = true
                break
            case Gesture.G.up:
            case Gesture.G.down:
                isReverse = false
                break
            default:
                throw new Error('this is error')
        }
        //遍历一遍,将可移动的数字记录到gs列表中
        list.forEach(arr => gs.push(...this.calcMoveGrids(arr, isReverse)))
        //这里列表若不为空,就有移动的数字在里面
        if (gs.length > 0) {
            this.startAnimating = true
            //开始下一个的移动数字动画 
            this.nextAnimation(list,gs,isReverse,1)
        } else {
        	//没有可移动的,可能有存在两个相邻的相同数字,需要调用合并数字的方法
            let scope = this.compositeNumber(list, isReverse)
            //当scope大于0,也就是有得分,表示合并成功,就执行移动数字动画
            if (scope > 0) {
                this.startAnimating = true
                //开始下一个的移动数字动画
                this.nextAnimation(list,gs,isReverse)
            }
        }
    }
    //最后,别忘了重置触摸点数据
    this.touch1 = undefined
    this.touch2 = undefined
},

别法算法想那么复杂,只要思路是对的,能实现出来的就没问题

游戏测试

写到这里,基本上就可以运行测试玩玩了,

看看合成数字的游戏效果吧,运行动图如下
请添加图片描述

想要改成2048游戏一样是可以的,只需要在新建的随机位置数字代码里修改12即可;

想要项目源码在点这里查看下载,或者直接点这里搜索:合成数字,在本博客站内请放心下载,感谢支持!

可能手机上看不到,请改用电脑浏览器查看;
如果搜索不到,只能在资源一栏慢慢找了(太多了不好找

请添加图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/253377.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

spring事务不生效的场景有哪些

参考文章地址 百度安全验证&#xff0c;https://www.cnblogs.com/novwind/p/17461448.html 这里讨论的是声明式事务的不生效场景。编程式事务不在此处讨论 要说明spring中哪些场景事务不生效&#xff0c;就要说明spring的事务控制是如何实现的。Spring框架中事务控制的运行原理…

磁力计LIS2MDL开发(2)----电子罗盘

磁力计LIS2MDL开发.2--电子罗盘 概述视频教学样品申请源码下载环境磁场建模消除硬铁误差软铁干扰主程序 概述 本文将介绍如何使用 LIS2MDL 传感器来读取数据来转化为指南针。 地磁场强度范围约为 23,000 至 66,000 nT &#xff0c;并且可以建模为磁偶极子&#xff0c;其场线起…

10天玩转Python第8天:python 文件和异常 全面详解与代码示例

今日内容 文件操作 普通文件的操作json 文件的操作[重点] 异常处理(程序代码运行时的报错) 文件介绍 计算机的 文件&#xff0c;就是存储在某种 长期储存设备 上的一段 数据 作用: 将数据长期保存下来&#xff0c;在需要的时候使用 ​ 1.计算机只认识 二进制(0 1) 2.文件中…

CMA、CNAS软件检测公司分享:压力测试应关注的指标和面临的问题

软件压力测试是容易被传统企业忽视的测试点&#xff0c;用户人数一旦超过预期&#xff0c;极易造成软件产品卡顿、崩溃的情况&#xff0c;不利于用户正常使用&#xff0c;严重影响企业公信力和盈利水平。今天卓码软件测评小编来聊聊压力测试过程中应该关注的指标和会面临的问题…

Mysql存储引擎-InnoDB

&#x1f44f;作者简介&#xff1a;大家好&#xff0c;我是爱吃芝士的土豆倪&#xff0c;24届校招生Java选手&#xff0c;很高兴认识大家&#x1f4d5;系列专栏&#xff1a;Spring源码、JUC源码、Kafka原理、分布式技术原理、数据库技术&#x1f525;如果感觉博主的文章还不错的…

电商平台如何选择分账系统

电商平台尤其是多用户商城系统&#xff0c;它属于资源整合型平台&#xff0c;随着商户的入驻&#xff0c;它会面临一个问题&#xff1a;钱要分给谁、分多少、怎么分的问题&#xff0c;今天&#xff0c;商淘云小编与您分享如何选择分账系统。 第一种是银行的分账系统&#xff0c…

1850_emacs_org-download在Windows上的使用

Grey 全部学习内容汇总&#xff1a; https://github.com/greyzhang/g_org 1850_emacs_org-download在Windows上的使用 对我来说&#xff0c;使用emacs很大的一个挑战是在Windows上&#xff0c;emacs的配置会比Linux上麻烦一些。而且&#xff0c;通常来说Windows上的体验会差…

详细了解云堡垒机的作用,提高企业数据信息安全

随着上云企业的不断增加&#xff0c;云上数据安全性成为企业面临的重要问题。为了保障企业的核心数据安全&#xff0c;越来越多的企业采购了云堡垒机来提升数据安全性。今天我们就来详细了解一下云堡垒机的作用&#xff0c;以及如何提高企业数据安全。 一、云堡垒机定义 云堡垒…

【精选】计算机网络教程(第2章网络层)

目录 前言 第2章网络层 1、编码与调制 2、传输方式 前言 总结计算机网络教程课程期末必记知识点。 第2章网络层 1、编码与调制 信道可以分成传送模拟信号的模拟信道和传送数字信号的数字信道两大类。通常人们将数字数据转换成数字信号的过程称为编码&#xff0c;而将数字…

探索 HBase GUI 工具,助您轻松驾驭大数据世界!

你是否曾为 HBase 数据管理而苦恼&#xff1f;别担心&#xff0c;这一款超级好用的 HBase GUI &#xff08;HBase Assistant&#xff09;工具&#xff0c;让您在大数据世界中游刃有余。不再需要繁琐的命令行操作&#xff0c;也不再为复杂的配置感到头疼。 主要功能 直观和设计…

matlab面向对象编程入门笔记

文章目录 1. 类和结构2. 定义类3. 属性3.1 private/protected/public属性3.2 constant属性3.3 hidden属性 4. 方法4.1 private/protected/public方法4.2 static方法4.3 外部方法 5. 动态调用6. 继承-超类6.1 handle超类6.2 dynamicprops 和 hgsetget子类 7. 封闭(sealed)类、方…

STM32_通过Ymodem协议进行蓝牙OTA升级固件教程

目录标题 前言1、OTA升级的重要性和应用场景2、理论基础2.1、单片机的启动流程2.2、什么是IAP&#xff1f;2.3、什么是OTA&#xff1f;2.4、什么是BootLoader&#xff1f;2.5、Ymodem协议是什么&#xff1f;2.6、IAP是如何实现的&#xff1f; 3、具体操作3.1、软硬件工具准备3.…

类加载机制

1.类加载的生命周期 其中类加载的过程包括了加载、验证、准备、解析、初始化五个阶段。在这五个阶段中&#xff0c;加载、验证、准备和初始化这四个阶段发生的顺序是确定的&#xff0c;而解析阶段则不一定&#xff0c;它在某些情况下可以在初始化阶段之后开始&#xff0c;这是为…

计算机中msvcr120.dll丢失怎样修复,这5个方法可以搞定

几乎在所有操作系统中&#xff0c;可分为两种库&#xff0c;一种是静态库&#xff08;.lib&#xff09;&#xff0c;另一种是动态库&#xff08;.dll&#xff09;。 为什么很多小伙伴在打开软件的时候会弹出“由于找不到XXX.dll文件&#xff0c;无法继续执行代码、、、、、、”…

大数据技术之 Kettle(PDI)

Kettle 第一章 Kettle概述1.1、ETL简介1.2、Kettle简介1.3、作业 和 转换 概念1.4、核心组件1.5、下载安装 第二章 控件使用2.1、初体验&#xff1a;csv 转换 excel 示例2.2、转换2.2.1、输入控件2.2.1.1、表输入 2.2.2、输出控件2.2.2.1、表输出2.2.2.2、更新&插入/更新2.…

分享66个Java源码总有一个是你想要的

分享66个Java源码总有一个是你想要的 学习知识费力气&#xff0c;收集整理更不易。 知识付费甚欢喜&#xff0c;为咱码农谋福利。 链接&#xff1a;https://pan.baidu.com/s/1hKlZJB3KrHcOuKWyV1xjKw?pwd6666 提取码&#xff1a;6666 项目名称 ava web个人网站项目 ea…

【C++11特性篇】C++11中の【override】【final】关键字——帮助用户检测是否重写

前言 大家好吖&#xff0c;欢迎来到 YY 滴C系列 &#xff0c;热烈欢迎&#xff01; 本章主要内容面向接触过C的老铁 主要内容含&#xff1a; 欢迎订阅 YY滴C专栏&#xff01;更多干货持续更新&#xff01;以下是传送门&#xff01; 目录 一.【override】【final】关键字——帮…

软件测试之鲁棒性测试

文章目录 前言一、鲁棒性测试是什么&#xff1f;二、鲁棒性测试的目的三、测试原理3.1 错误数据处理3.2 异常情况处理 前言 Bootloader软件刷写鲁棒性(Robustness)测试是指对Bootloader软件进行连续多次的刷写测试&#xff0c;且一次Fail都没发生&#xff0c;以此验证Bootload…

基于java+swing+mysq学生成绩管理系统(含课程报告)

基于javaswingmysq学生成绩管理系统_含课程报告 一、系统介绍二、功能展示三、项目相关3.1 乱码问题3.2 如何将GBK编码系统修改为UTF-8编码的系统&#xff1f; 四、其它1.其他系统实现 五、源码下载 一、系统介绍 本系统使用 Swing MySQL IntelliJ IDEA 开发。为管理人员提供…

【精选】计算机网络教程(第3章数据链路层)

目录 前言 第3章数据链路层 1、差错检测&#xff08;CRC&#xff09; 2、点对点协议&#xff08;了解应用场景&#xff09; 3、什么是碰撞域&#xff0c;什么是广播域 碰撞域&#xff08;Collision Domain&#xff09;&#xff1a; 广播域&#xff08;Broadcast Domain&a…