【JS球球大作战项目实战】+在线体验

news/2024/4/28 7:49:29/文章来源:https://blog.csdn.net/m0_68089732/article/details/137092651

在这里插入图片描述



个人名片:

在这里插入图片描述


🐼作者简介:一名大三在校生,喜欢AI编程🎋
🐻‍❄️个人主页🥇:落798.
🐼个人WeChat:hmmwx53
🕊️系列专栏:🖼️

  • 零基础学Java——小白入门必备🔥
  • 重识C语言——复习回顾🔥
  • 计算机网络体系———深度详讲
  • HCIP数通工程师-刷题与实战🔥🔥🔥
  • 微信小程序开发——实战开发🔥
  • HarmonyOS 4.0 应用开发实战——实战开发🔥🔥🔥
  • Redis快速入门到精通——实战开发🔥🔥🔥
  • RabbitMQ快速入门🔥
    🐓每日一句:🍭我很忙,但我要忙的有意义!
    欢迎评论 💬点赞👍🏻 收藏 📂加关注+


文章目录

  • BallBattle
    • 简介
    • 背景设定
    • 玩法
    • 主要功能
      • 匹配对战
      • 属性同步与保存
        • 房间属性
        • 玩家属性
      • 自定义事件
      • 其他功能
        • 消息处理控制
        • 移动同步
    • 项目结构
    • 欢迎添加微信,加入我的核心小队,请备注来意


BallBattle

简介

《球球大作战》是一款由巨人网络Superpop&Lollipop工作室自主研发,并且免费(不包括道具)的手机网络游戏。2015年5月27日由巨人网络在中国大陆发行。

在这里插入图片描述

游戏以玩家间的实时互动PK为设计宗旨,通过简单的规则将玩家操作直接转化为游戏策略,体验智谋碰撞的战斗乐趣。在这个球球的世界里,每个人都化身为一颗独特的球球,大球吃小球,努力生存下来就是唯一的目标。

线上体验

背景设定

在宇宙深处一片遍布着荆棘之花的神秘星云中,生活着一群名叫“波拉哩”(译名“球球”)的奇特生物。他们外表萌萌,却有着勇敢的心。他们是天生的战斗种族,为战斗而生,为战斗而亡。

传说中,这群波拉哩的共同祖先是一只叫“塔坦”的超级波拉哩,塔坦的职责就是守护宇宙瑰宝“荆棘之花”,它拥有强大的能量,会分出分身,变化万物,唯一的弱点就是贪吃。

一天,塔坦终于禁不住诱惑,偷食了“荆棘之花”,结果身体爆裂,成为了数以亿计的小波拉哩。从此,波拉哩的族群就受到了贪食的诅咒,只能在这片星云中无休止的战斗,如果停止战斗,生命便会流失,消亡在茫茫的星空之中。在漫漫的历史长河里,只有最强大的波拉哩才能冲过这片黑暗星云,打破命运的枷锁,去寻找那传说中的光明与和平。

为了那甜蜜的希望,波拉哩们战斗着。他们必须奋力奔跑,让自己变大变大再变大,才能对抗比自己更强的存在。哪怕经历无数失败也必须重新凝聚力量,直到成为最强壮的那个。

在这里插入图片描述

玩法

输入房间 ID,加入房间(如果没有此房间,则创建)。
用户 ID 随机生成。
使用 ⬆️⬇️⬅️➡️ 或 WSAD 来控制小球移动,吃掉场景中的食物(三角形,方形,六边形)则会增长体重(并减少速度);遇到其他球(玩家),碰撞之后,体重较大者获胜,较小者将会死亡并重生。
右侧面板显示当前房间的玩家体重排行榜。

主要功能

匹配对战

最基础的房间 ID 匹配。

更多关于房间匹配文档

属性同步与保存

这个 demo 使用的是 Master Client 机制,但由于 Master Client 可能存在掉线等异常情况,所以需要将房间和玩家的部分数据保存至 Room Properties 和 Player Properties。

更多关于属性同步文档

房间属性
  • 房间用时
  • 战场的食物列表
  • 食物最大 ID

食物:

/*** 食物*/
cc.Class({extends: cc.Component,properties: {id: 0,type: 0},getProperties() {const id = this.id;const type = this.type;const { x, y } = this.node.position;return {id,type,x,y// 可能还会有能量值};}
});
玩家属性
  • 位置
  • 体重
  • 速度

球:

const Constants = require("Constants");
const Food = require("./Food");/*** 球*/
cc.Class({extends: cc.Component,properties: {nameLabel: {type: cc.Label,default: null},infoLabel: {type: cc.Label,default: null}},init(player) {this.player = player;},eat() {// 计算尺寸const { weight } = this.player.customProperties;const scale = Math.sqrt(weight) / Constants.BORN_SIZE;this.node.scale = cc.v2(scale, scale);},reborn() {// 计算尺寸const { weight, pos } = this.player.customProperties;const scale = Math.sqrt(weight) / Constants.BORN_SIZE;this.node.scale = cc.v2(scale, scale);// 位置const { x, y } = pos;this.node.position = cc.v2(x, y);},getId() {return this.player.actorId;},getSpeed() {const { speed } = this.player.customProperties;return speed;},getWeight() {const collider = this.node.getComponent(cc.CircleCollider);const { radius } = collider;const { scaleX, scaleY } = this.node;return Constants.PI * Math.pow(radius, 2) * scaleX * scaleY;},// LIFE-CYCLE CALLBACKS:start() {this.nameLabel.string = this.player.userId;},update(dt) {const { x, y } = this.node;this.infoLabel.string = `(${parseInt(x)}, ${parseInt(y)})`;},// 碰撞onCollisionEnter(other, self) {const { group: otherGroup } = other.node;if (otherGroup === Constants.FOOD_GROUP) {this._onCollideFood(other, self);} else if (otherGroup === Constants.BALL_GROUP) {this._onCollideBall(other, self);}},_onCollideFood(other, self) {// 球碰食物,客户端模拟const { node: foodNode } = other;const { x, y } = self.node.position;cc.log(`collide food: (${x}, ${y})`);const food = foodNode.getComponent(Food);foodNode.active = false;// 交由 Master 处理const event = new cc.Event.EventCustom(Constants.BALL_AND_FOOD_COLLISION_EVENT,true);event.detail = {ball: this,food};this.node.dispatchEvent(event);},_onCollideBall(other, self) {const { node: b1Node } = other;const { node: b2Node } = self;const event = new cc.Event.EventCustom(Constants.BALL_AND_BALL_COLLISION_EVENT,true);event.detail = {b1Node,b2Node};this.node.dispatchEvent(event);}
});

自定义事件

  • 玩家出生:对于当前玩家,执行战场初始化逻辑;对于其他玩家,执行增加玩家逻辑。
  • 吃食物:客户端移除内存中的食物节点,同步玩家体重。
  • 杀死玩家:用于同步节点间碰撞事件。
  • 玩家重生:用于重新初始化玩家数据。
  • 生成食物:同步房间内的食物数据。
  • 玩家离开:用于移除场景和 UI 对应节点。
  • 游戏结束:用于返回主菜单场景。

其他功能

消息处理控制

由于从主场景加载到战斗场景,存在异步的资源加载过程,所以需要暂停 / 恢复消息队列的处理。流程如下:

  • 加入房间
  • 暂停消息处理
  • 加载战斗场景
  • 初始化战场
  • 恢复消息队列。
移动同步

移动同步实现思路是玩家在运动状态改变时,将当前运动状态同步给其他客户端,其他客户端对玩家行为进行模拟。而在运动过程中,并不同步移动数据。

运动状态包括:

  • 位置
  • 移动方向
  • 时间戳

模拟步骤:

  • 在收到运动状态改变时,根据运动改变时的位置,方向,以及当前时间戳与运动改变时的时间戳的差值,计算出当前应该所在的位置 p0
  • 玩家节点当前实际所在位置 p1,p0 - p1(向量减法),即为校正后的运动路径
  • 对路径进行模拟,直至下次运动状态改变

球控制器,当前客户端需要添加组件,由用户输入直接移动,并触发移动同步

const Ball = require("Ball");
const Constants = require("../Constants");
const LeanCloud = require("../LeanCloud");const { getClient } = LeanCloud;/*** 球控制器,当前客户端需要添加组件,由用户输入直接移动,并触发移动同步*/
cc.Class({extends: cc.Component,properties: {},// LIFE-CYCLE CALLBACKS:onLoad() {cc.systemEvent.on(cc.SystemEvent.EventType.KEY_DOWN, this._onKeyDown, this);cc.systemEvent.on(cc.SystemEvent.EventType.KEY_UP, this._onKeyUp, this);this._ball = this.node.getComponent(Ball);this._direction = cc.Vec2.ZERO;},onDestroy() {cc.systemEvent.off(cc.SystemEvent.EventType.KEY_DOWN,this._onKeyDown,this);cc.systemEvent.off(cc.SystemEvent.EventType.KEY_UP, this._onKeyUp, this);},start() {this._cameraNode = cc.find("Canvas/Main Camera");},update(dt) {const speed = this._ball.getSpeed();const delta = this._direction.normalize().mul(speed * dt);const position = this.node.position.add(delta);const { x, y } = position;const { LEFT, RIGHT, TOP, BOTTOM } = Constants;const newPosition = cc.v2(Math.min(Math.max(x, LEFT), RIGHT),Math.min(Math.max(y, BOTTOM), TOP));this.node.position = newPosition;// 设置摄像机跟随this._cameraNode.position = this.node.position;},_onKeyDown(event) {this.running = true;let dir = this._direction.clone();switch (event.keyCode) {case cc.macro.KEY.a:case cc.macro.KEY.left:dir.x = -1;break;case cc.macro.KEY.d:case cc.macro.KEY.right:dir.x = 1;break;case cc.macro.KEY.w:case cc.macro.KEY.up:dir.y = 1;break;case cc.macro.KEY.s:case cc.macro.KEY.down:dir.y = -1;break;default:break;}this._synchMove(dir.normalize());},_onKeyUp(event) {let dir = this._direction.clone();switch (event.keyCode) {case cc.macro.KEY.a:case cc.macro.KEY.left:case cc.macro.KEY.d:case cc.macro.KEY.right:dir.x = 0;break;case cc.macro.KEY.w:case cc.macro.KEY.up:case cc.macro.KEY.s:case cc.macro.KEY.down:dir.y = 0;break;default:break;}this._synchMove(dir.normalize());},_synchMove(dir) {if (dir.fuzzyEquals(this._direction, 0.01)) {return;}this._direction = dir;const { x, y } = this.node.position;const { x: dx, y: dy } = this._direction;const client = getClient();client.player.setCustomProperties({move: { p: { x, y }, d: { x: dx, y: dy }, t: Date.now() }});}
});

项目结构

├── Animation 动画目录
├── Prefabs 预制目录,主要存放球,食物预制体
├── Scene 场景目录,主菜单场景,战斗场景
├── Script 脚本目录
│   ├── Battle 战斗相关脚本目录
│   │    ├── Ball.js 球节点控制脚本
│   │    ├── BallController.js 玩家控制球脚本,生成移动数据同步给其他客户端
│   │    ├── BallSimulator.js 玩家运动模拟脚本,根据玩家运动数据,模拟运动行为
│   │    ├── Battle.js 战场节点总控制器,用于接收并解析战斗中的自定义事件,驱动场景节点及 UI 节点变化
│   │    ├── BattleHelper.js 战场工具脚本
│   │    ├── Food.js 食物节点控制脚本
│   │    ├── Master.js 游戏逻辑脚本,用于区分 Master 客户端与普通客户端,Master 组件用于生成房间数据及逻辑判断,只有 Master 的客户端才拥有这个组件,包括最初的房间的创建者和切换后的新房主。
│   │    ├── PlayerInfoItem.js 玩家信息 UI 节点控制脚本
│   │    └── UI.js UI 控制脚本
│   ├── Menu主菜单相关脚本目录
│   │    └── Menu.js 主菜单脚本
│   ├── Constants.js 游戏中用到的常量
│   └── LeanCloud.js 全局存放 LeanCloud SDK 对象的脚本
├── Texture 素材资源目录
└── play.js LeanCloud 实时对战服务 SDK

添加wx/微信公众回复球球大作战获取完整代码

在线体验链接


欢迎评论 💬点赞👍🏻 收藏 📂加关注+



在这里插入图片描述

欢迎添加微信,加入我的核心小队,请备注来意

👇👇👇👇👇👇👇👇👇👇👇👇👇👇👇

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

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

相关文章

论文《Exploring to Prompt for Vision-Language Models》阅读

论文《Exploring to Prompt for Vision-Language Models》阅读 论文概况论文动机(Intro)MethodologyPreliminaryCoOp[CLASS]位置Context 是否跨 class 共享表示和训练 ExperimentsOverall ComparisonDomain GeneralizationContext Length (M) 和 backbon…

ChatGPT 商业金矿(上)

原文:ChatGPT Business Goldmines 译者:飞龙 协议:CC BY-NC-SA 4.0 第一章:为什么我写这本书 欢迎阅读《ChatGPT 多源收入:20 个利润丰厚的业务,任何人都可以在一周内使用 ChatGPT 开始》。我很高兴分享我…

Backend - gitea 首次建库(远端本地)

目录 一、建立远端储存库 1. 进入新增画面 2. 填写储存库名称(如book),点击“建立”即可 二、本地关联远端储存库 1. 本地初始化储存库代码 (1)新建文件夹 (2)获取远端储存库 2. 本地编写…

冒泡排序(六大排序)

冒泡排序 冒泡排序的特性总结: 1. 冒泡排序是一种非常容易理解的排序 2. 时间复杂度:O(N^2) 3. 空间复杂度:O(1) 4. 稳定性:稳定 动图分析: 代码实现: Swap(int*p1,int*p2) {int tmp *p1;*p1*p2…

Xcode 15 Sandbox: rsync(xxxx) deny(1) file-write-create

设置里面搜索user 把User Script Sanboxing 改为NO 新版本的Xcode 15 编译报该错误 右侧工具栏 项目的workspace 和 pod的 space 都选择为15.0 即可

Springboot整合瀚高

需要下载highgo驱动,然后将jar包打入进自己本地maven中 下载地址: highgi6.2.4 1.打开jar包所在的文件,然后在该文件夹中打开命令窗口(或者先打开命令窗口,然后cd到jar所在文件夹) install-file -Dfile:jar包名Dart…

想学网络安全,从哪里开始?网络安全的学习路线

网络安全学习路线: 想学习网络安全专业的知识,想当黑客,但是不知道该从哪里开始学。 我给你一个路线! 清晰图片和大纲:https://docs.qq.com/doc/DU1lpVFpSbWVrd2p3

.NET分布式Orleans - 2 - Grain的通信原理与定义

Grain 是 Orleans 框架中的基本单元,代表了应用程序中的一个实体或者一个计算单元。 每个Silo都是一个独立的进程,Silo负责加载、管理和执行Grain实例,并处理来自客户端的请求以及与其他Silo之间的通信。 通信原理 在相同的Silo中&#xff0…

SCI论文改写、防查重神器QuillBot如何付费高级版本?

写论文时候的修改软件QuillBot,正常的文献里的句子帖进去,直接给各种倒装和各种同义词替换至少10次,保证查不出来是别人的句子。 QuillBot是一个帮助改写内容的转述工具。 Quillbot让你的内容重组变得简单。 转述是指你用不同的词来表达&a…

短视频账号矩阵系统/开发 -- -- -- 路径积ai算法上线

短视频账号矩阵系统,短视频矩阵系统开发3年技术之路,目前已经在技术竞品出沉淀出来,近期技术迭代的新的功能同步喽: php7.4版本,自研框架,有开发文档,类laravel框架 近期剪辑迭代的技术算法&am…

【HTTP完全注解】一些神奇的URL

URL HTTP 请求的内容被称为"资源",‘资源’这一概念非常宽泛,它可以是一份文档,一张图片,或所有其他你能够想到的格式。每个资源的名称和位置由一个 URL(统一资源定位符,它是 URI 的一种&#x…

【计算机网络】http协议的原理与应用,https是如何保证安全传输的

✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 🏆 作者简介:景天科技苑 🏆《头衔》:大厂架构师,华为云开发者社区专家博主,…

广场舞团系统的设计与实现|Springboot+ Mysql+Java+ B/S结构(可运行源码+数据库+设计文档)

本项目包含可运行源码数据库LW,文末可获取本项目的所有资料。 推荐阅读100套最新项目持续更新中..... 2024年计算机毕业论文(设计)学生选题参考合集推荐收藏(包含Springboot、jsp、ssmvue等技术项目合集) 目录 1. 系…

【Web应用技术基础】CSS(6)——使用 HTML/CSS 实现 Educoder 顶部导航栏

第一题&#xff1a;使用flex布局实现Educoder顶部导航栏容器布局 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>Educoder</title><script src"https://cdn.staticfile.org/jquery/1.1…

linux 内存介绍

大致共有四类&#xff1a;VSS、RSS、PSS、USS &#xff0c;通常情况下&#xff0c;VSS > RSS > PSS > USS 1.VSS(Virtual Set Size)虚拟耗用内存&#xff08;包含共享库占用的内存&#xff09; VSS表示一个进程可访问的全部内存地址空间的大小。这个大小包括了进程已…

分布式之缓存详解

缓存设计 导流&#xff1a;将原本复杂的操作请求&#xff08;sql 大堆&#xff09;&#xff0c;引导到简单的请求上。前人栽树后人乘凉。 缓存&#xff1a;空间换时间的一个做法。 redis, memcached,localcache guava&#xff0c;客户端缓存&#xff0c; user_info_xxxx : …

Micron 256 GB DDR5-8800 MCR DIMM:适用于大型服务器的大型内存

美光本周宣布&#xff0c;它已经开始对其 256 GB multiplexer combined &#xff08;MCR&#xff09; DIMM 进行采样&#xff0c;这是该公司迄今为止容量最大的内存模块。这些全新的基于 DDR5 的 MCRDIMM 面向下一代服务器&#xff0c;特别是那些由英特尔至强可扩展“Granite R…

TrackballControls是Three.js中的一个相机控件,它允许用户通过鼠标拖拽、滚轮缩放以及键盘移动相机,实现类似于球形的相机旋转操作。

demo案例 TrackballControls是Three.js中的一个相机控件&#xff0c;它允许用户通过鼠标拖拽、滚轮缩放以及键盘移动相机&#xff0c;实现类似于球形的相机旋转操作。这个控件可以用于3D场景中&#xff0c;以提供更好的用户体验。以下是对TrackballControls的入参、出参、方法…

pulsar: kafka on pulsar之把pulsar当kafka用

一、下载协议包&#xff08;要和pulsar版本比较一致&#xff09; https://github.com/streamnative/kop/releases?q2.8.0&expandedtrue二、在pulsar的根目录创建一个protocols目录&#xff0c;将上述包放到这个目录里 三、编辑broker.conf(如果是集群)或者standalone.con…

振弦采集仪在预防地质灾害监测中的作用与应用前景

振弦采集仪在预防地质灾害监测中的作用与应用前景 振弦采集仪&#xff08;String Vibrating Sensor&#xff0c;简称SVM&#xff09;是一种用于地质灾害监测的重要仪器&#xff0c;它通过测量地面振动信号来预测和预警地质灾害的发生。SVM的作用在于提供实时、准确的地质灾害监…