Skip to content

Commit 8fe180b

Browse files
authored
Merge pull request #1257 from melonjs/deprecate-entity
[#1008] Deprecate Entity in favor of Sprite/Renderable + Body
2 parents c089b9e + 64cbddb commit 8fe180b

5 files changed

Lines changed: 659 additions & 121 deletions

File tree

Lines changed: 97 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,51 @@
1-
import { audio, collision, Entity, game, ParticleEmitter, Rect } from "melonjs";
1+
import {
2+
audio,
3+
Body,
4+
collision,
5+
game,
6+
ParticleEmitter,
7+
Rect,
8+
Sprite,
9+
} from "melonjs";
210
import { gameState } from "../gameState";
311

412
/**
5-
* An enemy entity
13+
* A base enemy entity using Sprite + Body
614
* follow a horizontal path defined by the box size in Tiled
715
*/
8-
class PathEnemyEntity extends Entity {
16+
class PathEnemyEntity extends Sprite {
17+
alive: boolean;
18+
startX: number;
19+
endX: number;
20+
walkLeft: boolean;
21+
isMovingEnemy: boolean;
22+
particleTint: string;
23+
924
/**
1025
* constructor
1126
*/
12-
constructor(x, y, settings) {
27+
constructor(x, y, settings, frameNames: string[]) {
1328
// save the area size defined in Tiled
1429
const width = settings.width || settings.framewidth;
1530

16-
// adjust the setting size to the sprite one
17-
settings.width = settings.framewidth;
18-
settings.height = settings.frameheight;
31+
// create the sprite from texture atlas animation frames
32+
super(x, y, {
33+
...gameState.texture.getAnimationSettings(frameNames),
34+
anchorPoint: { x: 0, y: 0 },
35+
});
1936

20-
// redefine the default shape (used to define path) with a shape matching the renderable
21-
settings.shapes[0] = new Rect(
22-
0,
23-
0,
24-
settings.framewidth,
25-
settings.frameheight,
26-
);
27-
28-
// call the super constructor
29-
super(x, y, settings);
37+
// add a physic body matching the sprite max frame dimensions
38+
this.body = new Body(this, new Rect(0, 0, this.width, this.height));
3039

3140
// set start/end position based on the initial area size
32-
this.startX = this.pos.x;
33-
this.endX = this.pos.x + width - settings.framewidth;
34-
this.pos.x = this.pos.x + width - settings.framewidth;
35-
36-
// enemies are not impacted by gravity
37-
this.body.gravityScale = 0;
41+
this.startX = x;
42+
this.endX = x + width - settings.framewidth;
43+
this.pos.x = x + width - settings.framewidth;
3844

3945
this.walkLeft = false;
4046

4147
// body walking & flying speed
42-
this.body.setMaxVelocity(settings.velX || 1, settings.velY || 0);
48+
this.body.setMaxVelocity(settings.velX || 1, settings.velY || 15);
4349

4450
// set a "enemyObject" type
4551
this.body.collisionType = collision.types.ENEMY_OBJECT;
@@ -55,6 +61,9 @@ class PathEnemyEntity extends Entity {
5561
// a specific flag to recognize these enemies
5662
this.isMovingEnemy = true;
5763

64+
// living state
65+
this.alive = true;
66+
5867
// default tint for particles
5968
this.particleTint = "#FFF";
6069
}
@@ -68,7 +77,7 @@ class PathEnemyEntity extends Entity {
6877
if (this.pos.x <= this.startX) {
6978
// if reach start position
7079
this.walkLeft = false;
71-
this.renderable.flipX(true);
80+
this.flipX(true);
7281
} else {
7382
this.body.force.x = -this.body.maxVel.x;
7483
}
@@ -78,7 +87,7 @@ class PathEnemyEntity extends Entity {
7887
if (this.pos.x >= this.endX) {
7988
// if reach the end position
8089
this.walkLeft = true;
81-
this.renderable.flipX(false);
90+
this.flipX(false);
8291
} else {
8392
this.body.force.x = this.body.maxVel.x;
8493
}
@@ -91,7 +100,12 @@ class PathEnemyEntity extends Entity {
91100
/**
92101
* collision handle
93102
*/
94-
onCollision(response) {
103+
onCollision(response, other) {
104+
if (other.body.collisionType === collision.types.WORLD_SHAPE) {
105+
// solid against world shapes (platforms, ground)
106+
return true;
107+
}
108+
95109
// res.y >0 means touched by something on the bottom
96110
// which mean at top position for this one
97111
if (this.alive && response.overlapV.y > 0 && response.a.body.falling) {
@@ -102,7 +116,7 @@ class PathEnemyEntity extends Entity {
102116
// make the body static
103117
this.body.setStatic(true);
104118
// set dead animation
105-
this.renderable.setCurrentAnimation("dead");
119+
this.setCurrentAnimation("dead");
106120

107121
const emitter = new ParticleEmitter(this.centerX, this.centerY, {
108122
width: this.width / 4,
@@ -129,84 +143,102 @@ class PathEnemyEntity extends Entity {
129143
}
130144

131145
/**
132-
* An Slime enemy entity
146+
* A Slime enemy entity
133147
* follow a horizontal path defined by the box size in Tiled
134148
*/
135149
export class SlimeEnemyEntity extends PathEnemyEntity {
136150
/**
137151
* constructor
138152
*/
139153
constructor(x, y, settings) {
140-
// super constructor
141-
super(x, y, settings);
142-
143-
// set a renderable
144-
this.renderable = gameState.texture.createAnimationFromName([
154+
// super constructor with slime frame names
155+
super(x, y, settings, [
145156
"slime_normal.png",
146157
"slime_walk.png",
147158
"slime_dead.png",
148159
]);
149160

150161
// custom animation speed ?
151162
if (settings.animationspeed) {
152-
this.renderable.animationspeed = settings.animationspeed;
163+
this.animationspeed = settings.animationspeed;
153164
}
154165

155-
// walking animatin
156-
this.renderable.addAnimation("walk", [
157-
"slime_normal.png",
158-
"slime_walk.png",
159-
]);
160-
// dead animatin
161-
this.renderable.addAnimation("dead", ["slime_dead.png"]);
166+
// walking animation
167+
this.addAnimation("walk", ["slime_normal.png", "slime_walk.png"]);
168+
// dead animation
169+
this.addAnimation("dead", ["slime_dead.png"]);
162170

163171
// set default one
164-
this.renderable.setCurrentAnimation("walk");
165-
166-
// set the renderable position to bottom center
167-
this.anchorPoint.set(0.5, 1.0);
172+
this.setCurrentAnimation("walk");
168173

169174
// particle tint matching the sprite color
170175
this.particleTint = "#FF35B8";
171176
}
172177
}
173178

174179
/**
175-
* An Fly enemy entity
180+
* A Fly enemy entity
176181
* follow a horizontal path defined by the box size in Tiled
177182
*/
178183
export class FlyEnemyEntity extends PathEnemyEntity {
184+
startY: number;
185+
endY: number;
186+
flyUp: boolean;
187+
179188
/**
180189
* constructor
181190
*/
182191
constructor(x, y, settings) {
183-
// super constructor
184-
super(x, y, settings);
185-
186-
// set a renderable
187-
this.renderable = gameState.texture.createAnimationFromName([
188-
"fly_normal.png",
189-
"fly_fly.png",
190-
"fly_dead.png",
191-
]);
192+
// super constructor with fly frame names
193+
super(x, y, settings, ["fly_normal.png", "fly_fly.png", "fly_dead.png"]);
194+
195+
// set vertical patrol range (bob up and down by half height)
196+
const bobRange = settings.height || this.height;
197+
this.startY = y;
198+
this.endY = y + bobRange;
199+
this.flyUp = true;
200+
201+
// allow vertical movement
202+
this.body.setMaxVelocity(settings.velX || 1, settings.velY || 1);
192203

193204
// custom animation speed ?
194205
if (settings.animationspeed) {
195-
this.renderable.animationspeed = settings.animationspeed;
206+
this.animationspeed = settings.animationspeed;
196207
}
197208

198-
// walking animatin
199-
this.renderable.addAnimation("walk", ["fly_normal.png", "fly_fly.png"]);
200-
// dead animatin
201-
this.renderable.addAnimation("dead", ["fly_dead.png"]);
209+
// walking animation
210+
this.addAnimation("walk", ["fly_normal.png", "fly_fly.png"]);
211+
// dead animation
212+
this.addAnimation("dead", ["fly_dead.png"]);
202213

203214
// set default one
204-
this.renderable.setCurrentAnimation("walk");
205-
206-
// set the renderable position to bottom center
207-
this.anchorPoint.set(0.5, 1.0);
215+
this.setCurrentAnimation("walk");
208216

209217
// particle tint matching the sprite color
210218
this.particleTint = "#000000";
211219
}
220+
221+
/**
222+
* manage the fly movement (horizontal + vertical bobbing)
223+
*/
224+
update(dt) {
225+
if (this.alive) {
226+
// vertical bobbing — apply force against gravity to fly
227+
if (this.flyUp) {
228+
if (this.pos.y <= this.startY) {
229+
this.flyUp = false;
230+
} else {
231+
this.body.force.y = -this.body.maxVel.y;
232+
}
233+
} else {
234+
if (this.pos.y >= this.endY) {
235+
this.flyUp = true;
236+
} else {
237+
this.body.force.y = this.body.maxVel.y;
238+
}
239+
}
240+
}
241+
242+
return super.update(dt);
243+
}
212244
}

0 commit comments

Comments
 (0)