【见缝插针】射击类游戏-微信小程序项目开发流程详解

news2024/11/18 17:52:22

还记得小时候玩过的见缝插针游戏吗,比一比看谁插得针比较多,可有趣了,当然了,通过它可以训练自己的手速反应,以及射击水平,把握时机,得分越高就越有成就感,相信小朋友们会喜欢它的,游戏实现原理看似简单,实则包含了数学中几何知识,接下来讲一讲实现过程吧。

这篇文章主要是用微信小程序项目做的,需要用微信开发者工具打开,

打开微信开发者工具,选择创建小程序,项目名称自己填写,例如miniprogram-shoot-scope

如下图,依次选择即可
tu1

  • AppID 选自己的测试号
  • 不使用云开发
  • JavaScript - JS 基础模板

如果要选创建小游戏项目来做,也是可以的,实现步骤大同小异,

可以将小程序的游戏源码改写到小游戏项目中,有兴趣可以看看笔者写得这篇文章来做

【贪吃蛇】微信小程序的游戏转到小游戏上实现方法详解)

游戏页面

接下来,创建一个游戏页面,文件路径是/pages/game/game,

打开布局文件/pages/game/game.wxml

在里面放一个画布组件(Canvas元素)就可以了,内容如下

<!--pages/game/game.wxml-->
<view class="page">
    <canvas class="canvas" type="2d" id="zs1028_csdn" bindtouchend="onTouchEnd"/>
</view>

游戏逻辑

打开逻辑文件/pages/game/game.js

在里面写游戏逻辑代码,先把画布组件的触摸事件和初始化方法都写好,

游戏引擎

写好的代码如下,从onReady()开始执行,绑定onTouchEnd()触摸事件

//导入一个模块,这是个小游戏引擎,或者框架
import ZS1028_CSDN from '../../utils/zs1028_CSDN.js'

const app = getApp()

Pages({
	/**
     * 生命周期函数--监听页面初次渲染完成
     */
    onReady() {
    	//选择查询画布组件实例
        wx.createSelectorQuery().select('#zs1028_csdn').fields({ size: true, node: true }, res => {
        	//查询结果从这里返回
            const { width, height, node: canvas } = res
            //将画布大小调整一下,保证宽高一致
            Object.assign(canvas, { width, height })

            // 创建一个游戏引擎,用这实现游戏会方便一些
            const engine = ZS1028_CSDN.createMiniGameEngine({
                canvas,
                // isTest: true, //测试的,去掉注释可以显示游戏动画帧率,数字越大越流畅
            })
			//这里处理初始化游戏数据...稍后讲
			const newShotData = {...}
			const shotsData = {...}
			const centerScopeData = {...}

			//将上面的定义游戏都缓存到
			this.gameData = {
			    centerScopeData,
			    shotsData,
			    newShotData
			}
            //把游戏引擎缓存到
            this.engine = engine
            
            //再把初始化游戏数据添加到游戏引擎对象中...稍后讲
			engine.addBgObject({
			    data: newShotData,
			    ...
			})
			engine.addBgObject({
			    data: shotsData,
			    ...
			})
			engine.addForeObject({
			    data: centerScopeData,
			    ...
			})

			//最后,调用此方法开始游戏
            this.restart()
        }).exec()
    },
    /**
    * 绑定画布的触摸结束事件
    */
	onTouchEnd() {
        if (this.isGameEnd) return
		//将底部的针箭的速度属性从0改为10,就可以发射
        const { newShotData } = this.gameData
        if (newShotData.speed > 0) return
        newShotData.speed = 10
    },
})

模块文件zs1028_CSDN.js由开发者实现,代码看起来可能复杂些,这里讲简单的实现思路,

接下来讲,怎么用这个模块来轻松实现游戏,

有JavaScript编程基础功底的学者可以研究这模块来学习,
文件代码不多,有150行

初始化数据

开始游戏前,需要向游戏引擎传入游戏的一些初始化数据,

在上面省略的初始化游戏数据代码位置开始着写,写好代码如下

//记录一个水平的中心点位置
const centerX = width / 2
//定义一个靶的中心数据,就是绘制大红点的
const centerScopeData = {
    x: centerX,
    y: centerX,
    r: centerX * 0.5,
    initTime: 0,
}
//定义一个针箭的数据
const shotsData = {
    x: centerX,
    y: centerX,
    r: centerX * 0.1,//针的尾部圆半径
    shots: [],//放置已钉上的列表
    speed: 1,//旋转速度
    angle: 0,//旋转角度
    offset: 0
}
//定义一个在底部的针箭数据
const newShotData = {
    y: -1,//上下的位置,在底部
    speed: 0,//射出的速度,为0就是待发的状态
}

将初始化好的一些游戏数据对象都放到this.gameData,后面有需要就取,
对照游戏界面看看,就知道只用这三个数据就可以了,

加入游戏对象

继续写下去,将初始化数据添加到游戏引擎对象中,

钉上靶中的针箭

这里添加所有钉上针箭的对象,代码如下

//创建一个新的针箭对象
let shot = this.addNewShot()
//算出它的开始位置
const startY = canvas.height - shotsData.r - shot.data.linerLength - centerScopeData.r - centerScopeData.y
//使用游戏引擎的添加背景对象方法,绘制中心的所有针箭
engine.addBgObject({
    data: shotsData, //传入对象数据
    //实现重置数据方法
    reset() {
        const { shots } = this.data
        shots.length = 0 //重置时候,将所有钉上的针箭都清除
    },
    //实现绘制方法
    redraw(data) {
        const { canvas, context: ctx, topBar } = data
        let { x, y, r, shots, speed, angle } = this.data
        // 内边距上边距离
        let paddingTop = topBar?.bottom || 0
// 绘制所有钉上的针箭
        shots.forEach((item, index) => {
        	//夹角角度
            let deg = item.data.angle + angle
            //圆边弧度
            let radian = deg / 2 / Math.PI
            // 线段(针)长
            let c = item.data.linerLength + centerScopeData.r
            //使用数学中的勾股定理公式,求得线段的两点坐标
            let y2 = Math.sin(radian) * c + y + paddingTop
            let x2 = Math.cos(radian) * c + x
            //调用对象的绘制方法,传入的是针箭的两端坐标点
            item.redraw(x, y + paddingTop, x2, y2)
        })
        //旋转位置更新
        let offset = speed / 10
        this.data.offset = offset
        this.data.angle = (angle + offset) % 360
    }
})

在初中数学课上才有讲勾股定理哦,可见学好数学对做游戏来说是多么重要

底下待发的针箭

这里添加在底部针箭的对象,代码如下

const that = this
//调用引擎的添加背景对象方法,绘制底部的针箭
engine.addBgObject({
    data: newShotData,
    reset() {
        this.data.y = startY
        this.data.speed = 0 //重置时候,速度为0表示不动
        shot?.reset()
    },
    redraw(data) {
        const { canvas, topBar } = data
        //其中y就是移动位置,通过改变这个值可实现上下移动射击
        let { y, speed } = this.data
        let x1 = canvas.width / 2
        let y1 = y + centerScopeData.y + centerScopeData.r
        let y2 = y1 + shot.data.linerLength
        //调用对象的绘制方法
        shot.redraw(x1, y1, x1, y2)
        if (speed > 0) {
        	//当y的值还是大于0时,说明它还没有钉到靶中心,继续移动
            if (y >= (topBar?.bottom || 0)) {
                this.data.y -= speed
                return
            }
            //执行到这里,说明它刚刚钉上靶中心,就设置它在靶中心的角度以及偏移位置
            shot.data.angle = 90 - shotsData.angle - shotsData.offset * 10
            //这里用遍历,逐个判断这个针箭尾部的圆是否与已钉上的针箭相碰
            for (let i = 0; i < shotsData.shots.length; i++) {
                let item = shotsData.shots[i]
                if (item.x <= 0 || item.y <= 0) continue
                //计算两一个圆心之间的距离,这里用到数学的勾股定理公式:直角三角形三边关系
                let c = Math.sqrt(Math.pow(x1 - item.data.x, 2) + Math.pow(y2 - item.data.y, 2))
                //如果两个圆相交(互相碰到),那么就游戏结束
                if (c <= item.data.r + shot.data.r) {
                	//调用游戏引擎的停止方法
                    engine.stop()
                    //记录最高分
                    app.setMaxScope(shotsData.shots.length)
                    //弹出对话框提示游戏结束
                    that.showModalForGameEnd()
                    return
                }
            }
			//将新的针箭添加到
            shotsData.shots.push(shot)
			//重置一下
            this.data.y = startY
            this.data.speed = 0
			//重新添加
            shot = that.addNewShot()
        }
    }
})

💡直角三角形三边关系:假设直角的两边长是a和b,那么斜边长 c²=a²+b²

靶心中心

这里添加靶心的对象,代码如下

engine.addForeObject({
    data: centerScopeData,
    reset() {
        Object.assign(this.data,{
            initTime: Date.now()
        })
    },
    redraw(data) {
        const { canvas, context: ctx, topBar } = data
        let { x, y, r, initTime } = this.data
        let paddingTop = topBar?.bottom || 0
		//绘制靶心
        ctx.strokeStyle = 'black'
        ctx.fillStyle = 'red'
        ctx.lineWidth = 1
        ctx.beginPath()
        ctx.arc(x, y + paddingTop, r, 0, Math.PI * 2)
        ctx.fill()
        ctx.stroke()
		//绘制得分
        ctx.fillStyle = 'white'
        ctx.textAlign = 'center'
        ctx.baseTextAlign = 'middle'
        ctx.font = ctx.font.replace(/^\d+/, 38)
        ctx.fillText(`得分${shotsData.shots.length}`, x, y + paddingTop)
		//绘制计时
        let timer = Math.trunc((Date.now()-initTime)/1000)
        ctx.font = ctx.font.replace(/^\d+/, 32)
        ctx.fillText(`${timer}`, x, y + paddingTop + 48)
    }
})

就连这个方法addNewShot()实现也很简单,代码如下

/**
*	添加新的针箭对象
*/
addNewShot(){
	const { gameData, engine } = this
    //调用引擎创建的一个对象方法    
    let shot = engine.createObject({
	//...
	return shot
}

在这里会发现,引擎添加的游戏对象,都有data,reset(),redraw()的属性和方法,都看懂了吧,
实现过程都写在游戏引擎模块文件里,怎样实现的呢,对此感兴趣的可以看看项目源码研究看看

开始游戏

调用方法restart(),整个游戏就能运行起来了,如下代码
代码如下

/**
*	重新开始游戏
*/
restart(){
	const { engine } = this
	//重置游戏对象
    engine.reset()
	//运行游戏
    engine.run()
    //重置游戏结束状态
    this.isGameEnd = false
}

游戏引擎会处理其它实现的细节,基本的绘制流程无需我们操心,这样用实现起来会方便一些,

游戏项目

写完整个项目,就可以运行测试了,

运行效果动图如下,点击屏幕任意位置就可以发射
请添加图片描述
想看项目源码 请点击这里,在资源一栏下有个名称为 见缝插针游戏源码,

请放心下载,感谢支持❤

如果是在手机上浏览此文章的,可能看不到资源一栏下的项目源码,在电脑上浏览器看就能看到了

tu2

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

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

相关文章

pointnetgpd复现

参考&#xff1a; Installation Instructions — Dex-Net 0.2.0 documentation Install git clone https://github.com/lianghongzhuo/PointNetGPD.git 添加环境变量 gedit ~/.bashrc #添加下面这一行 export PointNetGPD_FOLDER$HOME/code/PointNetGPD #然后source source…

k8s 1.28.3 使用containerd

文章目录 环境说明最终结果环境配置时钟同步 主机名称配置主机名解析关闭swap安装ipvs 安装containerd安装containerd生成配置修改配置开启containerd服务 安装runc安装k8s安装kubelet kubeadm kubectl获取kubernetes 1.28组件容器镜像 拉取镜像初始化集群方法一&#xff08;不…

【4】Gradle-快速入门使用【Gradle多模块项目详解】

目录 【4】Gradle-快速入门使用【Gradle多模块项目详解】创建多项目构建添加子项目命名建议 项目依赖项项目路径不同模块的build.gradle配置 子项目之间共享构建逻辑公约插件跨项目配置buildSrc开发公约插件 调整多模块项目配置修改项目树的元素 了解Gralde配置时间和执行时间并…

API 集成测试工具Hitchhiker 0.1.1 正式发布

Hitchhiker 是一款开源的 Restful Api 集成测试工具&#xff0c;你可以在轻松部署到本地&#xff0c;和你的 team 成员一起管理 Api。 能做什么 * Team 协作开发 Api * Api 历史修改记录及支持 diff 展示 * 支持多环境变量及运行时变量 * 支持 Schedule 及批量 run * 不同…

Ubuntu诞生已经19年了

导读2004 年 10 月 20 日&#xff0c;Ubuntu 4.10 正式发布&#xff0c;代号‘Warty Warthog’。 2004 年 10 月 20 日&#xff0c;Ubuntu 4.10 正式发布&#xff0c;代号‘Warty Warthog’。 ▲ Ubuntu 4.10 与最新版 Ubuntu 23.10 的对比 作为 Ubuntu 第一个版本&#xff0…

[mysql]索引优化-2

目录 一、分页查询优化1.根据自增且连续的主键排序的分页查询2.根据非主键字段排序的分页查询 二、Join关联查询优化1.嵌套循环连接 Nested-Loop Join(NLJ) 算法2.基于块的嵌套循环连接 Block Nested-Loop Join(BNL)算法 三、count(*)查询优化1.查询mysql自己维护的总行数2.sho…

PySide/PYQT如何用Qt Designer和代码来设置文字属性,如何设置文字颜色?

文章目录 📖 介绍 📖🏡 环境 🏡📒 实现方法 📒📝 Qt Designer设置📝 代码📖 介绍 📖 本人介绍如何使用Qt Designer/代码来设置字体属性(包含字体颜色) 🏡 环境 🏡 本文使用Pyside6来进行演示📒 实现方法 📒 📝 Qt Designer设置 首先打开Qt De…

Langchain-Chatchat环境安装

目录 一、简介 二、环境安装 三、使用Langchain-Chatchat 3.1、下载模型 3.2、设置配置文件 3.3、执行 一、简介 基于 ChatGLM 等大语言模型与 Langchain 等应用框架实现&#xff0c;开源、可离线部署的检索增强生成(RAG)大模型知识库项目。 &#x1f916;️ 一种利用 l…

通用结构化剪枝DepGraph

文章目录 0. 前言一. 第一部分: Torch-Pruning1.1 传统的剪枝流程 - ResNet-18结构化剪枝1.2 Torch-Pruning剪枝 - ResNet-18结构化剪枝1.3 Torch-Pruning剪枝 - 遍历所有分组1.4 Torch-Pruning剪枝 - 剪枝器 High-level Pruners1.5 Torch-Pruning剪枝 - 拓展到更复杂的神经网…

中国电子学会2023年09月份青少年软件编程Python等级考试试卷六级真题(含答案)

2023-09 Python六级真题 分数&#xff1a;100 题数&#xff1a;38 测试时长&#xff1a;60min 一、单选题(共25题&#xff0c;共50分) 1. 以下选项中&#xff0c;不是tkinter变量类型的是&#xff1f;&#xff08;D &#xff09;(2分) A.IntVar() B.StringVar() C.Do…

高效简洁的文档翻译网站

一款简单而强大的文档翻译网站 一款文字/文件翻译的网站,支持多个领域的翻译&#xff0c;支持常见的语言翻译(韩/日/法/英/俄/德…),最大百分比的保持原文排版(及个别除外基本100%还原)。 新用户注册就有100页的免费额度&#xff0c;每月系统还会随机赠送翻译额度&#xff0c;…

ssh开启,centOS7

1、先确定虚拟机是否装了openssh-server&#xff0c;执行 yum list installed |grep openssh-server 查看是否安装 [rootlocalhost ~]# yum list installed |grep openssh-server Repodata is over 2 weeks old. Install yum-cron? Or run: yum makecache fast openssh-serve…

C语言--每日五道选择题--Day9

第一题 1、如下程序的运行结果是&#xff08; &#xff09; char c[5]{a, b, \0, c, \0}; printf("%s", c); A: a b B: ab\0c\0 C: ab c D: ab 答案及解析 D 首先这是一个字符数组&#xff0c;我们要知道无论是字符串还是字符数组&#xff0c;它们遇到ASCII值为0就…

第6 章 布局管理及多窗口技术

6.1 控件布局技术 所谓GUI界面&#xff0c;归根结底&#xff0c;就是一堆可视化控件的叠加。创建一个窗口&#xff0c;把按钮放上面&#xff0c;把图标放上面&#xff0c;这样就成了一个界面。在放置时&#xff0c;控件的位置尤为重要。我们必须指定控件放在哪里&#xff0c;以…

vue3项目常用功能分享

Vue3常用功能分享 本文主要分享一下在使用vue3开发项目时的一些常用功能 一、自动注册全局组件 自动注册components目录下所有vue组件并以组件的文件名为组件的名称 // components/index.tsimport { type App, defineAsyncComponent } from vue const components Object.e…

Leetcode—剑指OfferII LCR 019.验证回文串II【简单】

2023每日刷题&#xff08;二十七&#xff09; Leetcode—剑指OfferII LCR 019.验证回文串II 实现代码 class Solution { public:bool judgeFunc(string s, int left, int right) {while(left < right) {if(s[left] ! s[right]) {return false;}left;right--;}return true;…

【数据结构】拓扑序列求法

概念不多说了&#xff0c;有疑问的搜一下&#xff0c;这里直接放求法&#xff1a; 找到入度为0的节点输出并删除该节点&#xff0c;并删除与该点链接的边重复第一步 例子 输出a&#xff0c;删除a输出b&#xff0c;删除b输出c&#xff0c;删除c 最终结果为abcdef 注意 拓扑排…

WorkPlus IM即时通讯软件:私有化部署、安全加密、信创适配

WorkPlus IM即时通讯软件是一款具备私有化部署、安全加密和信创适配功能的高效沟通工具。下面我们将详细介绍WorkPlus IM的功能和特点。 WorkPlus支持私有化部署&#xff0c;这意味着企业可以完全掌控数据的存储与传输。企业可以选择将该软件部署在自己的本地服务器上&#xff…

文件上传 [ACTF2020 新生赛]Upload1

打开题目&#xff0c;发现是一道文件上传题目 随便上传个一句话木马上去 发现网站前端有白名单限制&#xff0c;只能上传含有jpg&#xff0c;png&#xff0c;gif的后缀文件 最开始我想到的做法是先上传htaccess文件&#xff0c;bp修改文件头&#xff0c;上传成功后然后再上传以…