好嘞,游戏开发框架是js 开发的网页小游戏!
phaser这个框架。好我们先上图!
目前大概是这么一个样子。
然后防御塔功能呢。简单的说就是当人物进去的时候打他。人物扣血。
我们的小人物是这样的代码
遇到的问题如下;
小白刚开始开发游戏内存使用不当把浏览器给撑爆了。
人物进入防御塔后持续性的扣血。不是固定间隔打一下。
后面倒是都解决了;
人物的类
人物的类大概是这样的,有这个移动速度,有他底下的小角色,有他的health健康。当人物进入防御塔的时候要进行扣血。
export default class Player extends Phaser.GameObjects.Container {face: CircleMaskImage;static MinSpeed: number = 300;speed: number = Player.MinSpeed;user: User | undefined;children: Player[] = [];speedCoefficient: number = 0;sizeCoefficient: number = 0;line?: Phaser.GameObjects.Line;flash: Phaser.Tweens.Tween;flashStar: Phaser.GameObjects.Image;health:numberconstructor(public scene: Phaser.Scene,x: number,y: number,public team: Team,public parent?: Player) {super(scene, x, y);this.face = new CircleMaskImage(scene, 0, 0, "noFace").setOrigin(0);this.health = 500;this.add(this.face);this.scene.add.existing(this);this.scene.physics.add.existing(this);this.Body.setCollideWorldBounds(true);this.Body.setBounce(1, 1);this.setDepth(5000);if (parent) {this.createOrUpdateLine();}const vec = this.scene.physics.velocityFromAngle(Math.random() * 360,this.speed);this.Body.setVelocity(vec.x, vec.y);this.setFace("noFace");this.flashStar = this.scene.add.image(Game.BlockSize / 2, Game.BlockSize / 2, "star").setScale(2).setAlpha(0);this.add(this.flashStar);this.flash = this.scene.add.tween({targets: this.flashStar,duration: 100,scale: { from: 0, to: 2 },alpha: { from: 0, to: 1 },yoyo: 1,hold: 100,loop: 0,});this.flash.stop();}
简单介绍phaser框架
- 基于浏览器技术
Phaser 构建在现代 Web 技术之上,主要依赖于以下两个核心浏览器 API:
Canvas API:这是一个用于在网页上绘制图形的标准 API,允许开发者使用 JavaScript 创建动态、可交互的 2D 图像。当浏览器不支持或用户选择禁用 WebGL 时,Phaser 会退回到使用 Canvas 进行渲染。
WebGL API:作为一种更高级的图形接口,WebGL 允许在浏览器中直接操作 GPU(图形处理器),实现硬件加速的 2D/3D 图形渲染。对于性能要求较高的游戏场景,Phaser 利用 WebGL 提供更流畅、高效的视觉表现。
2… 游戏对象与组件系统
haser 提供了一套丰富的游戏对象体系,如精灵(Sprites)、组(Groups)、文本(Text)、动画(Animations)、粒子(Particles)等,这些都是构成游戏场景的基本元素。这些对象通常包含物理属性(如位置、速度、旋转等)、交互行为(如碰撞检测、输入响应)以及可定制的视觉样式。游戏对象之间可以组成层次结构或分组管理,便于进行批量操作和优化渲染。
3更新与渲染循环
Phaser 通过维护一个核心的游戏循环来驱动游戏逻辑的执行。这个循环包括两个主要阶段:
Update:在这个阶段,Phaser 会按照每帧(通常为1/60秒)的频率更新所有游戏对象的状态。这包括处理用户输入、更新对象的位置、执行游戏逻辑(如AI、计时器、物理模拟等)。开发者可以通过定义自己的 update 方法来插入自定义的游戏逻辑代码。
Render:在更新阶段完成后,Phaser 进入渲染阶段。此时,Pixi.js 被调用来重新绘制整个游戏画面,确保屏幕上的所有游戏对象都反映最新的状态。Phaser 会自动处理视口变换、层级排序等,确保正确的渲染顺序。
由update这个函数开始。
this.teams.forEach((team) => {team.players.children.each((player) => player.update());team.blocks.children.each((block) => block.update());//更新防御塔功能.team.update();});const currentTime = performance.now(); // 或者使用其他适合您游戏环境的当前时间获取方式// 更新防御塔功能,每 1 秒更新一次if (currentTime - this._lastTowerUpdateTime >= 2000 ) {this.teams.forEach((team) => {if (team.isDefensiveTower) {// console.log("更新",this._lastTowerUpdateTime)team.update();}});this._lastTowerUpdateTime = currentTime;}
会实时的更新。
就是写了一个函数然后去实时的计算防御塔的攻击范围里面有没有人。
防御塔类
//防御塔需要的变量;不要每次newthis.rangeCollider = new Phaser.Geom.Circle(332, 662, this.attackRange);this.attackRangeGraphics = this.scene.add.graphics({fillStyle: { color: 4790 }, // 初始颜色});this.attackRangeGraphics.fillCircle(332, 662, this.attackRange);
找寻附近的玩家
/*** 实现步骤估计得获取到所有的player,然后计算一下距离;,然后计算伤害。* @returns 获取防御塔附近的player*/private getNearbyPlayers(): Player[] {const nearbyPlayers: Player[] = [];// 创建一个临时的圆形碰撞体,代表防御塔的攻击范围(坐标加上范围)// const rangeCollider = new Phaser.Geom.Circle(332, 662, this.attackRange);// const attackRangeGraphics = this.scene.add.graphics({// fillStyle: { color: 100}, // 初始颜色// });// attackRangeGraphics.fillCircle(332, 662, this.attackRange);this.players.getChildren().forEach((child: Phaser.GameObjects.GameObject) => {if (child instanceof Player) {const player = child as Player;const playerCenter = player.getCenter(); if (Phaser.Geom.Circle.Contains(this.rangeCollider, playerCenter.x, playerCenter.y)) {nearbyPlayers.push(player);}}});return nearbyPlayers;}
对所有附近的玩家扣血
//给team添加了攻击的方法。update(): void {const nearbyPlayers = this.getNearbyPlayers(); // 获取处于攻击范围内的玩家列表// console.log("nearbyPlayers",nearbyPlayers)// nearbyPlayers.forEach((player) => {// console.log("nearbyPlayers",nearbyPlayers.length)// this.attack(player); // 对每个进入范围的玩家发起攻击// });nearbyPlayers.forEach((player) => {if (!this._lastAttackedPlayers.has(player)) {console.log("nearbyPlayers",nearbyPlayers.length)this.attack(player); // 对每个未被攻击过的玩家发起攻击this._lastAttackedPlayers.add(player);}});// 清理已离开攻击范围的玩家,防止缓存集合无限制增长this._lastAttackedPlayers.forEach((player) => {if (!nearbyPlayers.includes(player)) {this._lastAttackedPlayers.delete(player);}});}
玩家扣血的函数
attack(player: Player): void {const damage = this.calculateDamage(); // 计算防御塔造成的伤害player.takeDamage(damage); // 调用玩家的takeDamage方法,减少其生命值}
目前待改善
这个防御塔目前来说每秒都会好几个人物扣血。没有类似的抗塔机制。