鸿蒙开发游戏(三)---大鱼吃小鱼(放置NPC)
效果图
添加了一个NPC(小红鱼),玩家控制小黄鱼
鸿蒙开发游戏(三)---大鱼吃小鱼(放置NPC)
鸿蒙开发游戏(四)---大鱼吃小鱼(互吃升级)
鸿蒙开发游戏(五)---大鱼吃小鱼(添加音效)
鸿蒙开发游戏(六)---大鱼吃小鱼(称霸海洋)
前两篇文章我们做了摇杆控制小鱼移动,这篇将会添加一个NPC,让其自动在海洋里游荡,然后玩家控制吃掉它。在这之前我们想思考一些问题,
NPC如何生成?NPC有哪些属性?NPC是如何控制的?如何做到随机转方向?
这是该篇的难点,这里还用到了一些数学知识,包括sin,cos,弧度与角度的计算等,还是比较麻烦的,但是等你看到代码又会发现代码量很少,又会觉得如此简单,好了,看例子。
1、开始游戏
这里我们需要添加一个开始游戏按钮,因为只有玩家开始了游戏,我们启动一个计时器才会变得顺理成章,不然的话,上来就启动计时器会很好资源的。
export struct FishPage {
@State isBegin: boolean = false
}
这里我们默认是false,未启动状态
build() {
Row() {
Stack() {
// 背景
Image($r("app.media.bg_fish"))
if (this.isBegin == false) {
Button('开始游戏')
.backgroundColor('#36d')
.onClick(() => {
//这里把设置成true
this.isBegin = true
})
} else {
//渲染小鱼
}
}
}
2、添加NPC小鱼
我们在开始之前就已经开始思考了,NPC应该有什么属性,起始位置,方向,速度,等,这里暂时不需要等级,下篇互吃逻辑写。
//NPC
@State npcSpeed: number = 3
@State npcFishX: number = 300
@State npcFishY: number = 200
@State npcAngle: number = 0
@State intervalIdNPC_1: number = 1
@State npcSin: number = 1
@State npcCos: number = 1
npc显示需要写在else里面,也就是点击开始游戏后,isBegin=true时
if (this.isBegin == false) {
Button('开始游戏')
.backgroundColor('#36d')
.onClick(() => {
this.isBegin = true
})
} else {
Image($r("app.media.icon_fish_right"))
.position({ x: this.xFish - this.fishRadius, y: this.yFish - this.fishRadius })
.rotate({ angle: this.angle, centerX: '50%', centerY: '50%' })
.width(40)
.height(40)
Image($r("app.media.icon_npc_2"))
.position({ x: this.npcFishX - this.fishRadius, y: this.npcFishY - this.fishRadius })
.rotate({ angle: this.npcAngle, centerX: '50%', centerY: '50%' })
.objectFit(ImageFit.ScaleDown)
.width(40)
.height(40)
}
ok,第一个image是玩家控制的小鱼,第二个image是NPC。
3、NPC动起来
问题来了,NPC如何自己动起来了,这就又用到了计时器,这里如果有其他好的方法也评论区打出来哈。当玩家点击开始游戏按钮时启动计时器,
if (this.isBegin == false) {
Button('开始游戏')
.backgroundColor('#36d')
.onClick(() => {
this.isBegin = true
clearInterval(this.intervalIdNPC_1)
this.intervalIdNPC_1 = setInterval(() => {
//设置小鱼的移动位置,
this.npcFishX += this.npcSpeed * this.npcCos
this.npcFishY += this.npcSpeed * this.npcSin
this.npcFishX = this.getNPCBorderX(this.npcFishX)
this.npcFishY = this.getNPCBorderY(this.npcFishY)
}, 40)
})
}
这里需要说一下,启动一个计时器,内部是不断地计算npc的位置,getNPCBorderX这个是防止走出屏幕的宽度和高度设置的,当触碰到边框要改变方向。难点也在这
getNPCBorderX(x: number) {
if (x <= this.fishRadius) {
x = this.fishRadius + 10
this.getRandom()
}
if (x > this.screenWidth - this.fishRadius) {
x = this.screenWidth - this.fishRadius - 15
this.getRandom()
}
return x
}
getNPCBorderY(y: number) {
if (y <= this.fishRadius) {
y = this.fishRadius + 10
this.getRandom()
}
if (y > this.screenHeight - this.fishRadius) {
y = this.screenHeight - this.fishRadius - 10
this.getRandom()
}
return y
}
那一个x方向说吧,当x<=小鱼的半径时说明,小鱼已经贴左边了,大于屏幕宽度时贴右边了,这时我们要改变方向,getRandom()就是改变方向用的,至于x=this.fishRadius +10 这个主要是当贴边后,小鱼还在走,就会触发多次if语句,生成多次方向,也就是说会出现抖动现象,感兴趣去掉赋值可以试试。
4、NPC方向生成
这一块是最麻烦的,
弧度 = 角度 * π / 180
角度 = 弧度 * 180 / π
我们认识到的Math.sin,cos,tan等一般都是传入一个弧度,而不是角度(我传入角度老是有问题,这里传入弧度就解决了)
/*随机获取一个角度*/
getRandom() {
this.npcAngle= this.selectFrom(-179,180)
// let angle = Math.random()+Math.random()+Math.random()
// this.npcAngle = angle * 180 / Math.PI
//这是是求弧度,弧度 = 角度 * π / 180
this.npcSin = Math.sin(this.npcAngle * Math.PI /180)
this.npcCos = Math.cos(this.npcAngle * Math.PI /180)
console.log("角度"+this.npcAngle)
}
selectFrom(startNumber, endNumber) {
let choice = endNumber - startNumber + 1;
return Math.floor(Math.random() * choice + startNumber)
}
首先我们需要随机生成一个角度,比如说90度,50度,-120度等
角度是作为鱼头方向用的,我们按照speed速度去计算该方向的值
那么x轴上的值就是x = speed * cos值,如下
this.intervalIdNPC_1 = setInterval(() => {
//设置小鱼的移动位置,
this.npcFishX += this.npcSpeed * this.npcCos
this.npcFishY += this.npcSpeed * this.npcSin
this.npcFishX = this.getNPCBorderX(this.npcFishX)
this.npcFishY = this.getNPCBorderY(this.npcFishY)
}, 40)
5、关闭计时器
onPageHide() {
clearInterval(this.intervalIdNPC_1)
}
记住页面消失时,或者游戏结束时需要关闭计时器
好了,到这NPC防止就完成了。
鸿蒙开发游戏(三)---大鱼吃小鱼(放置NPC)的更多相关文章
- 【C语言探索之旅】 第三部分第二课:SDL开发游戏之创建窗口和画布
内容简介 1.第三部分第二课: SDL开发游戏之创建窗口和画布 2.第三部分第三课预告: SDL开发游戏之显示图像 第三部分第二课:SDL开发游戏之创建窗口和画布 在上一课中,我们对SDL这个开源库做 ...
- 【C语言探索之旅】 第三部分第一课:SDL开发游戏之安装SDL
内容简介 1.课程大纲 2.第三部分第一课: SDL开发游戏之安装SDL 3.第三部分第二课预告: SDL开发游戏之创建窗口和画布 课程大纲 我们的课程分为四大部分,每一个部分结束后都会有练习题,并会 ...
- HTML5 Canvas游戏开发(三)lufylegend开源库件(上)
lufylegend可以解决HTML5开发游戏中会遇到的一些问题: 1.各种浏览器对于JavaScript和HTML的解析是不一致的. 2.手机浏览器和PC浏览器的区别. 3.JavaScript并非 ...
- 使用 Unity 3D 开发游戏的架构设计难点
Unity 3D 引擎对于开发者来说,入手非常快,因为它采用的是 C# 作为开发语言,这也大大降低了开发者的门槛.但凡只要懂一门编程语言的人都能使用 Unity 3D 引擎开发,另外 Unity 3D ...
- GJM : 各大开发游戏引擎
感谢您的阅读.喜欢的.有用的就请大哥大嫂们高抬贵手"推荐一下"吧!你的精神支持是博主强大的写作动力以及转载收藏动力.欢迎转载! 版权声明:本文原创发表于 [请点击连接前往] ,未经 ...
- MS CRM 2011的自定义和开发(11)——插件(plugin)开发(三)
http://www.cnblogs.com/StoneGarden/archive/2012/02/06/2340661.html MS CRM 2011的自定义和开发(11)——插件(plugin ...
- Qt移动应用开发(三):使用精灵图片实现帧动画
Qt移动应用开发(三):使用精灵图片实现帧动画 上一篇博文讲到了Qt Quick对于动画的一般支持.动画的形式多样,配合不同的插值函数,能够差点儿实现全部想要的动画效果,而对于游戏的一些特殊的效果比方 ...
- 使用Photon引擎进行unity网络游戏开发(三)——网络游戏大厅及房间
使用Photon引擎进行unity网络游戏开发(三)--网络游戏大厅及房间 Photon PUN Unity 网络游戏开发 连接到Photon ConnectUsingSettings 设置你的客户端 ...
- Kinect for Windows SDK开发入门(三):基础知识 下
原文来自:http://www.cnblogs.com/yangecnu/archive/2012/04/02/KinectSDK_Application_Fundamentals_Part2.htm ...
- Java开发学习(三十七)----SpringBoot多环境配置及配置文件分类
一.多环境配置 在工作中,对于开发环境.测试环境.生产环境的配置肯定都不相同,比如我们开发阶段会在自己的电脑上安装 mysql ,连接自己电脑上的 mysql 即可,但是项目开发完毕后要上线就需要该配 ...
随机推荐
- spring--CGLIB动态代理的实现原理
CGLIB(Code Generation Library)是一个强大的.高性能.高质量的代码生成库,它可以在运行时扩展 Java 类和实现 Java 接口.CGLIB 动态代理是基于继承的方式来实现 ...
- 搭建 github 报错 Permission denied (publickey)
将 key 加入 github 出现如下问题 这是本地仓 user.name user.email 与 github 注册信息不一致造成 将本地仓 user 信息与 github 修改一致,出现如下问 ...
- [转帖]一份完整的阿里云 Redis 开发规范,值得收藏!
https://blog.csdn.net/NicolasLearner/article/details/117449847 作者:付磊-起扬 http://yq.aliyun.com/article ...
- [转帖]pyinstaller实现将python程序打包成exe文件
https://www.cnblogs.com/blogzyq/p/13939739.html 如果我们想要在一个没有python以及很多库环境的电脑上使用我们的小程序该怎么办呢? 我们想到,在Win ...
- 【转帖】nginx变量使用方法详解-2
https://www.diewufeiyang.com/post/576.html 关于 Nginx 变量的另一个常见误区是认为变量容器的生命期,是与 location 配置块绑定的.其实不然.我们 ...
- [转帖]从DDR到DDR4,内存核心频率基本上就没太大的进步!
https://zhuanlan.zhihu.com/p/84194049 从2001年DDR内存面世以来发展到2019年的今天,已经走过了DDR.DDR2.DDR3.DDR4四个大的规格时代了(DD ...
- [转帖]Docker、containerd的关系
Docker.containerd的关系 containerd囊括了单机运行一个容器时所需要的一切: 为了能够支持多种OCI Runtime,containerd 内部使用containerd-shi ...
- SAP FICO 前台财务过账、预制功能分开
最近遇到一个变态要求,FB01 等涉及过账功能 要求根据'权限'判断用户是否有过账的功能.以下实现会有遗漏场景: 实现:hide 'SAVE'按钮 (ok_code = 'BU'). 根据状态栏设置' ...
- vue3动态组件的展示
需求描述 有些时候,我们需要做这样的处理. 点击A按钮的时候,出现组件A 点击B按钮的时候,出现组件B 点击C按钮的时候,出现组件C 这个时候,我们就可以使用动态组件了 动态组件 <templa ...
- js循环之map在工作中的使用
map函数会返回一个全新的数组哈(重要 在实际中很有用) map循环空那个数组时,不会报错的. 使用map的优势 可以返回一个全新的数组 可以用于过滤 ps==>:map里面不要有判断,否者会返 ...