【飞翔的鸟】飞行游戏-uniapp项目开发流程详解

2023-12-24 21:12

本文主要是介绍【飞翔的鸟】飞行游戏-uniapp项目开发流程详解,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

小时候玩过的飞行游戏,叫什么名字来着,通过点击操作控制煽动翅膀来持续飞行,躲避障碍物,有多远就飞多远吧,现在想起来,其中的实现原理非常简单,感兴趣的话来一起看看,这里给大家讲一讲飞翔的小鸟游戏的开发过程。

文章目录

  • 创建项目
  • 页面布局
    • 初始页面
    • 游戏页面
    • 设置横屏
  • 游戏逻辑
    • 加载模块
    • 初始化画布
    • 初始化游戏数据
    • 绘制游戏状态
    • 绘制小鸟
    • 绘制障碍物
    • 开始游戏
    • 触摸事件
  • 游戏测试

创建项目

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

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

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

页面布局

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

初始页面

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

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

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

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

游戏页面

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

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

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

<!--pages/game/game.wxml-->
<view class="page"><canvas id="zs1028_csdn" canvas-id="zs1028_csdn" class="canvas" bindtouchstart="onTouchStart" :disable-scroll="true"/>
</view>

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

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

这是在游戏开始时,其它的物品还没有出现

设置横屏

竖屏这样玩是不是视野变窄了点,可以设置横屏的,

把项目根目录下的文件pages.json打开,

添加一个属性pageOrientation设置,代码如下

{//..."globalStyle": {//..."pageOrientation": "landscape"},
}

不知道这样设置有没有效果,H5版好像不行吧,手机浏览器上是跟随系统横屏的

游戏逻辑

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

加载模块

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

// pages/game/game.js
import ZS1028_CSDN from '../../utils/zs1028_CSDN.js'const app = getApp()Page({//.../*** 生命周期函数--监听页面初次渲染完成*/async onReady() {//...这里处理初始化},/*** 生命周期函数--监听页面卸载*/onUnload() {this.game?.destroy()},/*** 以下是通过canvas的触摸事件来调用*/onTouchStart(e) {...},
})

导入的一个模块 ZS1028_CSDN ,是一个游戏引擎框架模块,用上它让游戏实现变得简单;
话说这个游戏模块,是通过一层又一层的绘制来实现的,代码总才182行,这么少,这一看很快就读完;
继续往下看,就能大概知道怎样绘制游戏了

初始化画布

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

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

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

初始化游戏数据

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

//游戏状态数据
const gameState = {bottom: 50, //绘制游戏状态的底边间距timeCount: 0, //计时scope: 0, //计分
}
//小鸟的数据
const birdData = {width: 60, //定义小鸟宽度imgIndex: 0, //图片索引(至少要2张图片,才能绘制动画效果)climb: 0 //点击后,小鸟飞行上升的高度
}
Object.assign(birdData, {height: birdData.width / 1.4 //按照图片尺寸计算出小鸟的高度
})
//障碍物的数据
const barrierData = {width: birdData.width * 1.1, 宽度list: [] //存放的障碍物列表
}
Object.assign(barrierData, {minWidth: barrierData.width * 0.86, //计算最小的宽度,用于绘制distance: barrierData.width * 3 //计算上一个障碍物与下一个的间距
})

绘制游戏状态

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

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

const that = this
//绘制游戏标题层,在屏幕上面显示游戏状态
game.initTopBar({data: gameState, //把定义的游戏状态数据传入其中//重置事件reset() {Object.assign(this.data, {timeCount: 0, //计时重置scope: 0, //计分重置maxScope: app.getMaxScope()  //最高分})},//重绘事件redraw(data) {const {canvas,context: ctx} = dataconst {timeCount,scope,maxScope,bottom} = this.data//...这里处理更新计时timeCount//以下是绘制标题ctx.textAlign = 'center'ctx.font = `18px sans-serif`ctx.strokeStyle = '#ffffff'let text = `⏰x${timeCount}s 🪙x${scope} 🏆x${maxScope}`ctx.strokeText(text, canvas.width * 0.5, 30)ctx.fillText(text, canvas.width * 0.5, 30)}
})

绘制小鸟

接下来,绘制一只飞翔的鸟,在其上层的中间位置绘制,代码如下

//添加游戏前景层,绘制一只鸟
game.addForeObject({data: birdData,reset() {//...这里重置小鸟的数据,放屏幕中间位置},redraw(data) {const {canvas,context: ctx} = data//调用绘制小鸟的方法this.drawBird(ctx)},methods: {drawBird(ctx) {let {x,y,width,height,imgIndex,climb} = this.dataif (climb > 0) {//...y -= 2 //小鸟在上升} else {y += 2 //小鸟在滑翔}// 判断图片索引,决定让使用那个图片显示小鸟switch (imgIndex) {//...default:ctx.drawImage('./../../static/tu_03.png', x, y, width, height)}// 调用碰撞检测方法,如果碰到了障碍物,游戏就会结束if (this.crashDetection(y)) {game.stop()that.isGameEnd = trueapp.setMaxScope(gameState.scope)//...这里执行弹出游戏结束提示即可}// 记录时间变化let nowTime = Date.now()// 判断时间差,如果大于300毫秒就替换小鸟图片if (!this.preTime || (nowTime - this.preTime) > 300) {//...改变小鸟的图片,实现煽动翅膀动画效果this.data.imgIndex = (imgIndex + 1) % 2 }//...最后,记得更新一下小鸟变化后的数据},crashDetection(y) {//...这里实现碰撞检测for (let i = 0; i < barrierData.list.length; i++) {let barrier = barrierData.list[i]//...判断是否碰撞条件}return false}}
})

要运行的话,就能看到屏幕中间的小鸟在煽动翅膀,

绘制障碍物

接下来,绘制障碍物,要在屏幕最右边开始出现,

然后,障碍物在慢慢接近小鸟,实现代码如下

//添加背景层,绘制一些障碍物,绘制砖块,管道都可以
game.addBgObject({data: barrierData, //传入障碍物的数据reset() {this.data.list.length = 0 //重置就清空列表this.addBarrier() //这里执行添加一个障碍物方法},redraw(data) {const {canvas,context: ctx} = dataconst {list,width,distance} = this.datalist.forEach((item, index) => {//障碍物上下对称出现//先绘制上面的障碍物if (item.y > 0) this.drawBarrier(ctx, item.x, item.y)//再计算间距,绘制出下面的障碍物if (item.y + item.distance < canvas.height) this.drawBarrier(ctx, item.x, item.y + item.distance, true)item.x -= 1 //向水平方向移动})//...绘制其它边框//有障碍物的话,就处理if (list.length > 0) {if (list[0].x + width < 0) {//超出边界,就移出list.shift()//游戏加分gameState.scope++} else if (list[list.length - 1].x + width + distance < canvas.width) {//每隔一段距离,就出现一个this.addBarrier()}}},methods: {drawBarrier(ctx, x, y, isDown = false) {//...这里实现绘制障碍物即可,isDown是绘制下面的,否则绘制上面},addBarrier() {//...这里实现添加新的障碍物数据this.data.list.push({...}) //数据属性y和distance是随机变化的}}
})

开始游戏

初始化都写好了,最后要保存好数据,代码如下

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

那游戏开始了吗,看方法restart()代码是怎么样的

const {game
} = this
this.isGameEnd = false
game.reset()

这里发现,没有调用game.run()方法,因此,游戏还没有运行起来

触摸事件

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

开始触摸时,改一下小鸟的数据即可,

就通过触摸开始事件来处理,代码如下

onTouchStart(e) {if (this.isGameEnd) returnconst {birdData} = this.gameDatabirdData.climb = 20 //改变这个属性值,小鸟就会上升的const {game} = this//如果游戏没有运行,这里执行一下就开始游戏了if (!game.isRun()) game.run()
},

游戏测试

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

看看飞翔的小鸟游戏运行效果吧,运行动图如下请添加图片描述

游戏里有用了小鸟图片,图片是可以自己替换的,
替换直升机图片飞行吧,反正游戏体验效果都是一致的;
还没有背景音呢,想要就自己找个音乐文件加上吧

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

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

请添加图片描述

这篇关于【飞翔的鸟】飞行游戏-uniapp项目开发流程详解的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/533147

相关文章

uniapp接入微信小程序原生代码配置方案(优化版)

uniapp项目需要把微信小程序原生语法的功能代码嵌套过来,无需把原生代码转换为uniapp,可以配置拷贝的方式集成过来 1、拷贝代码包到src目录 2、vue.config.js中配置原生代码包直接拷贝到编译目录中 3、pages.json中配置分包目录,原生入口组件的路径 4、manifest.json中配置分包,使用原生组件 5、需要把原生代码包里的页面修改成组件的方

用Microsoft.Extensions.Hosting 管理WPF项目.

首先引入必要的包: <ItemGroup><PackageReference Include="CommunityToolkit.Mvvm" Version="8.2.2" /><PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" /><PackageReference Include="Serilog

eclipse运行springboot项目,找不到主类

解决办法尝试了很多种,下载sts压缩包行不通。最后解决办法如图: help--->Eclipse Marketplace--->Popular--->找到Spring Tools 3---->Installed。

十四、观察者模式与访问者模式详解

21.观察者模式 21.1.课程目标 1、 掌握观察者模式和访问者模式的应用场景。 2、 掌握观察者模式在具体业务场景中的应用。 3、 了解访问者模式的双分派。 4、 观察者模式和访问者模式的优、缺点。 21.2.内容定位 1、 有 Swing开发经验的人群更容易理解观察者模式。 2、 访问者模式被称为最复杂的设计模式。 21.3.观察者模式 观 察 者 模 式 ( Obser

【操作系统】信号Signal超详解|捕捉函数

🔥博客主页: 我要成为C++领域大神🎥系列专栏:【C++核心编程】 【计算机网络】 【Linux编程】 【操作系统】 ❤️感谢大家点赞👍收藏⭐评论✍️ 本博客致力于知识分享,与更多的人进行学习交流 ​ 如何触发信号 信号是Linux下的经典技术,一般操作系统利用信号杀死违规进程,典型进程干预手段,信号除了杀死进程外也可以挂起进程 kill -l 查看系统支持的信号

工作流Activiti初体验—流程撤回【二】

已经玩工作流了,打算还是研究一下撤回的功能。但是流程图里面并不带撤回的组件,所以需要自己动态改造一下,还是延续上一个流程继续试验撤回功能。《工作流Activiti初体验【一】》 完整流程图 我们研究一下分发任务撤回到发起任务,其他环节的撤回类似 撤回的原理大概如下: 将分发任务后面的方向清空,把发起任务拼接到原来的判断网关,然后结束分发任务,这样流程就到发起任务了 此时的流程如上图,

ROS话题通信流程自定义数据格式

ROS话题通信流程自定义数据格式 需求流程实现步骤定义msg文件编辑配置文件编译 在 ROS 通信协议中,数据载体是一个较为重要组成部分,ROS 中通过 std_msgs 封装了一些原生的数据类型,比如:String、Int32、Int64、Char、Bool、Empty… 但是,这些数据一般只包含一个 data 字段,结构的单一意味着功能上的局限性,当传输一些复杂的数据,比如:

vue项目集成CanvasEditor实现Word在线编辑器

CanvasEditor实现Word在线编辑器 官网文档:https://hufe.club/canvas-editor-docs/guide/schema.html 源码地址:https://github.com/Hufe921/canvas-editor 前提声明: 由于CanvasEditor目前不支持vue、react 等框架开箱即用版,所以需要我们去Git下载源码,拿到其中两个主

React+TS前台项目实战(十七)-- 全局常用组件Dropdown封装

文章目录 前言Dropdown组件1. 功能分析2. 代码+详细注释3. 使用方式4. 效果展示 总结 前言 今天这篇主要讲全局Dropdown组件封装,可根据UI设计师要求自定义修改。 Dropdown组件 1. 功能分析 (1)通过position属性,可以控制下拉选项的位置 (2)通过传入width属性, 可以自定义下拉选项的宽度 (3)通过传入classN

Jitter Injection详解

一、定义与作用 Jitter Injection,即抖动注入,是一种在通信系统中人为地添加抖动的技术。该技术通过在发送端对数据包进行延迟和抖动调整,以实现对整个通信系统的时延和抖动的控制。其主要作用包括: 改善传输质量:通过调整数据包的时延和抖动,可以有效地降低误码率,提高数据传输的可靠性。均衡网络负载:通过对不同的数据流进行不同程度的抖动注入,可以实现网络资源的合理分配,提高整体传输效率。增