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

news2024/11/6 3:15:06

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

文章目录

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

创建项目

这里用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
		} = data
		const {
			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.data
			if (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 = true
				app.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
		} = data

		const {
			list,
			width,
			distance
		} = this.data
		list.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) return
	const {
		birdData
	} = this.gameData
	birdData.climb = 20 //改变这个属性值,小鸟就会上升的
	const {
		game
	} = this
	//如果游戏没有运行,这里执行一下就开始游戏了
	if (!game.isRun()) game.run()
},

游戏测试

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

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

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

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

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

请添加图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

RIS 系列 Mask Grounding for Referring Image Segmentation 论文阅读笔记

RIS 系列 Mask Grounding for Referring Image Segmentation 论文阅读笔记 一、Abstract二、引言三、相关工作Architecture Design for RISLoss Design for RISMasked Language Modeling 四、方法4.1 结构4.2 Mask Grounding讨论 4.3 跨模态对齐模块4.4 跨模态对齐损失4.5 损失…

顺序表基本操作实现

#include <stdio.h>#define MAX_SIZE 100// 定义顺序表的元素类型 typedef int ElementType;// 定义顺序表结构体 typedef struct {ElementType data[MAX_SIZE];int length; } SeqList;// 初始化顺序表 void InitList(SeqList *L) {L->length 0; }// 插入操作 int Li…

BP网络识别26个英文字母matlab

wx供重浩&#xff1a;创享日记 对话框发送&#xff1a;字母识别 获取完整源码源工程文件 一、 设计思想 字符识别在现代日常生活的应用越来越广泛&#xff0c;比如车辆牌照自动识别系统&#xff0c;手写识别系统&#xff0c;办公自动化等等。本文采用BP网络对26个英文字母进行…

优化小地图(非RawImage方法,节省性能)

优化小地图&#xff08;非RawImage方法&#xff0c;节省性能&#xff09; 一、小地图设计二、功能实现1.截取俯视图2.创建Cube包裹住场地&#xff0c;并且创建一个子物体坐标为&#xff08;0,0,0&#xff09;**3.创建UI显示小地图坐标转换代码如下&#xff1a; 一、小地图设计 …

我是如何转行 AI 并且实现薪资翻倍的

大家好啊&#xff0c;我是董董灿。 熟悉我的小伙伴都知道&#xff0c;我之前在北京某211大学&#xff0c;本硕读了7年的机械专业&#xff0c;后来硕士毕业后&#xff0c;果断转行去做了嵌入式开发&#xff0c;随后瞅准了 AI 爆发的时机果断转行去做了AI。 这段经历已经过去了…

【python与机器学习3】,感知机和与非门

1 电子和程序里的与门&#xff0c;非门&#xff0c;或门&#xff0c;与非门 &#xff0c;或非门&#xff0c;异或门 1.1 基础电路 与门&#xff08;AND gate&#xff09;、或门&#xff08;OR gate&#xff09;和非门&#xff08;NOT gate&#xff09;是数字逻辑电路中的三种基…

本地搭建【文档助手】大模型版(LangChain+llama+Streamlit)

概述 本文的文档助手就是&#xff1a;我们上传一个文档&#xff0c;然后在对话框中输入问题&#xff0c;大模型会把问题的答案返回。 安装步骤 先下载代码到本地 LangChain调用llama模型的示例代码&#xff1a;https://github.com/afaqueumer/DocQA&#xff08;代码不是本人…

自动驾驶规划算法

本文将讲解BFS&#xff0c;Dijstra&#xff0c;A*&#xff0c;动态规划的算法原理&#xff0c;不正之处望读者指正&#xff0c;希望有兴趣的读者能在评论区提出一些这些算法的面试考点&#xff0c;共同学习&#xff0c;一起进步 0 图论基础 图有三种&#xff1a;无向图、有向…

SRE 与 DevOps:你知道它们之间区别吗?

公众号「架构成长指南」&#xff0c;专注于生产实践、云原生、分布式系统、大数据技术分享 DevOps专注于消除阻碍开发和运维之间协作的隔阂&#xff0c;而SRE致力于设计和实施可扩展、可靠的系统&#xff0c;确保最大可靠性。 这篇文章将探讨DevOps和SRE之间的差异&#xff0c…

Podman配置mongodb

文章目录 查询镜像拉取镜像查看镜像运行容器创建root用户 查询镜像 podman search mongo拉取镜像 podman pull docker.io/library/mongo查看镜像 podman images运行容器 podman run -d -p 27017:27017 --namemongodb-test docker.io/library/mongo创建root用户 podman exe…

SSH秘钥登录服务器

一、查看本机 ssh 公钥&#xff0c;生成公钥 1.通过命令窗口 a. 打开你的 git bash 窗口 b. 进入 .ssh 目录&#xff1a;cd ~/.ssh c. 找到 id_rsa.pub 文件&#xff1a;ls d. 查看公钥&#xff1a;cat id_rsa.pub 或者 vim id_rsa.pub git–查看本机 ssh 公钥&#xff0c…

小白--将笔记本上的代码或者项目上传到github上去教程(使用git命令)

文章目录 一、操作教程二、常见问题1. 问题12. 问题2 三、注意 一、操作教程 https://blog.csdn.net/Elon15/article/details/125705706?ops_request_misc%257B%2522request%255Fid%2522%253A%2522170340591716800215092652%2522%252C%2522scm%2522%253A%252220140713.130102…

第六部分 集合论

目录 主要内容 集合的基本概念 集合的基本运算 集合恒等式 初级运算 文氏图 集合的广义并与广义交 广义运算的性质 例1 A{{a},{a,b}} 集合算律 例2 判断下列命题是否为真 例3 设 例4 判断以下命题的真假&#xff0c;并说明理由. 解题思路 主要内容 集合的基本概念 属于、包含…

基于JAVA的超市账单管理系统 开源项目

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块三、系统设计3.1 总体设计3.2 前端设计3.3 后端设计在这里插入图片描述 四、系统展示五、核心代码5.1 查询供应商5.2 查询商品5.3 新增超市账单5.4 编辑超市账单5.5 查询超市账单 六、免责说明 一、摘要 1.1 项目介绍 基于…

【Postman】以命令行形式执行Postman脚本(使用newman)

一、背景 ​ Postman的操作离不开客户端。但是在一些情况下可能无法使用客户端去进行脚本执行。比如在服务端进行接口测试。由此我们引入了Newman。Newman基于Node.js开发&#xff0c;它使您可以直接从命令行轻松运行和测试Postman测试集。它在构建时考虑了可扩展性&#xff0c…

身为Java“搬砖”程序员,你掌握了多线程吗?

摘要&#xff1a;互联网的每一个角落&#xff0c;无论是大型电商平台的秒杀活动&#xff0c;社交平台的实时消息推送&#xff0c;还是在线视频平台的流量洪峰&#xff0c;背后都离不开多线程技术的支持。在数字化转型的过程中&#xff0c;高并发、高性能是衡量系统性能的核心指…

STM32实现流水灯

led.c #include"led.h"void Led_Init(void) {GPIO_InitTypeDef GPIO_VALUE; //???RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);//???GPIO_VALUE.GPIO_ModeGPIO_Mode_Out_PP;//???? ????GPIO_VALUE.GPIO_PinGPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_…

stm32 pwm输出

PWM 技术原理 CUBEMX PWM配置 pwm初始化 MX_TIM2_Init(); HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_4);设置pwm //pwmVal 0 ~ 1000 __HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_4, pwmVal);

2024苹果手机iOS管理软软件iMazing2.17永久免费版下载教程

iMazing2024是一款专业的苹果IOS设备管理器&#xff0c;强悍的性能远超苹果的iTunes&#xff0c;iMazing 能让广大果粉能已自己的方式管理苹果设备&#xff0c;无需iTunes即可畅快传输或者保存苹果设备中的音乐、消息、文件以及其他数据。 iMazing2Mac-最新绿色安装包下载如下&…

WORDPRESS付费会员插件Paid Memberships Pro v2.12.5 – Plugin + All Addons

WORDPRESS付费会员插件Paid Memberships Pro v2.12.5 – Plugin All Addons 简介&#xff1a; Paid Memberships Pro是一款功能强大的会员订阅和内容限制管理插件&#xff0c;适用于WordPress网站。它提供了丰富的特性和工具&#xff0c;帮助网站所有者轻松地创建和管理付费…