How can I make my group follow the player when within 400 pixels? I created code based on this tutorial (https://docs.idew.org/video-game/project-references/phaser-coding/enemy-behavior). My current code I have created is below,
//IN CREATE FUNCTION
Map.forEachTile(tile => {
//Generate sprites on specific map tiles
if (tile.index == 6) {
this.Demons.create(tile.pixelX + 8, tile.pixelY + 8, "demon")
.play('DemonStand')
.setSize(22, 30)
.setOffset(5, 7)
.setDepth(10);
this.physics.add.collider(this.Demons);
this.physics.add.collider(this.Demons, MapLayer);
MonsterCount++;
}
});
//IN UPDATE FUNCTION
PlayerX = Player.body.position.x;
PlayerY = Player.body.position.y;
//PLAYER MOVEMENT || PLAYER MOVEMENT || PLAYER MOVEMENT
this.Demons.forEachAlive(function (enemy) {
MonsterX = enemy.body.position.x;
MonsterY = enemy.body.position.y;
let DifferenceX=PlayerX-MonsterX;
let DifferenceY=PlayerY-MonsterY;
if (DifferenceX>=400 || DifferenceX<=400){
if (MonsterX<PlayerX){
enemy.body.setVelocityX(EnemySpeed);
enemy.setScale(1);
enemy.play("walk", true);
} else if (MonsterX>PlayerX) {
enemy.body.setVelocityX(-EnemySpeed);
enemy.setScale(-1,1);
enemy.play("walk", true);
} else {
enemy.body.setVelocityX(0);
}
}
if (DifferenceY>=400 || DifferenceY<=400){
if (MonsterY<PlayerY){
enemy.body.setVelocityY(EnemySpeed);
enemy.play("walk", true);
} else if (MonsterY>PlayerY) {
enemy.body.setVelocityY(-EnemySpeed);
enemy.play("walk", true);
} else {
enemy.body.setVelocityY(0);
}
}
});
My demon sprite is working correctly, but I just need to figure out the movement. Is their a better way to implement the follow like this.physics.moveToObject or another way I do not know?
MY FULL CODE (https://replit.com/@JackF99/test-2d-array#script.js),
//CREATE GAME SCENE || CREATE GAME SCENE || CREATE GAME SCENE
class GameScene extends Phaser.Scene {
constructor(config) {
super(config);
}
preload() {
//PRELOADING ASSETS || PRELOADING ASSETS || PRELOADING ASSETS
//SPRITES
this.load.spritesheet("player", "assets/sprites/player.png", {
frameWidth: 16,
frameHeight: 30
});
this.load.spritesheet("demon", "assets/sprites/demon.png", {
frameWidth: 32,
frameHeight: 36
});
this.load.spritesheet("spikes", "assets/sprites/spikes.png", {
frameWidth: MapTileWidth,
frameHeight: MapTileHeight
});
//TILES
this.load.image("floor", "assets/tiles/floor.png");
this.load.image("floor_1", "assets/tiles/floor_1.png");
this.load.image("floor_2", "assets/tiles/floor_2.png");
this.load.image("floor_3", "assets/tiles/floor_3.png");
this.load.image("floor_4", "assets/tiles/floor_4.png");
this.load.image("floor_5", "assets/tiles/floor_5.png");
this.load.image("floor_6", "assets/tiles/floor_6.png");
this.load.image("floor_7", "assets/tiles/floor_7.png");
this.load.image("floor_8", "assets/tiles/floor_8.png");
this.load.image("wallLeft", "assets/tiles/wallLeft.png");
this.load.image("wallRight", "assets/tiles/wallRight.png");
this.load.image("wallBottom", "assets/tiles/wallBottom.png");
this.load.image("wallTop", "assets/tiles/wallTop.png");
this.load.image("bg", "assets/tiles/bg.png");
//OTHER IMAGES
this.load.image("sword", "assets/images/sword.png");
//DECLARE KEYS USED
this.keys = this.input.keyboard.addKeys('SPACE,W,A,S,D,Q');
this.cursors = this.input.keyboard.createCursorKeys();
}
create() {
this.cameras.main.zoom = 5;
//CREATE ANIMATIONS || CREATE ANIMATIONS || CREATE ANIMATIONS
//PLAYER ANIMATIONS
this.anims.create({
key: 'stand',
frames: this.anims.generateFrameNumbers('player', {
frames: [0, 1, 2, 3]
}),
frameRate: 1,
repeat: -1
});
this.anims.create({
key: 'walk',
frames: this.anims.generateFrameNumbers('player', {
frames: [4, 5, 6, 7]
}),
frameRate: 10,
repeat: -1
});
//ENEMY ANIMATIONS
this.anims.create({
key: 'DemonStand',
frames: this.anims.generateFrameNumbers('demon', {
frames: [0, 1, 2, 3]
}),
frameRate: 1.5,
repeat: -1
});
this.anims.create({
key: 'DemonWalk',
frames: this.anims.generateFrameNumbers('demon', {
frames: [4, 5, 6, 7]
}),
frameRate: 10,
repeat: -1
});
//GAME OBJECT ANIMATIONS
this.anims.create({
key: 'spikes',
frames: this.anims.generateFrameNumbers('spikes', {
frames: [0, 1, 2, 3]
}),
frameRate: 2,
repeat: -1
});
//DECLARE GROUPS || DECLARE GROUPS || DECLARE GROUPS
this.Spikes = this.physics.add.staticGroup();
this.Demons = this.physics.add.staticGroup();
//GENERATE MAP || GENERATE MAP || GENERATE MAP
MapOutline = getMap();
Map = this.make.tilemap({
data: MapOutline,
tileWidth: MapTileWidth,
tileHeight: MapTileHeight
});
Map.addTilesetImage(0, 'bg', MapTileWidth, MapTileHeight, 0, 0, 0);
Map.addTilesetImage(1, 'floor', MapTileWidth, MapTileHeight, 0, 0, 1);
Map.addTilesetImage(2, 'wallLeft', MapTileWidth, MapTileHeight, 0, 0, 2);
Map.addTilesetImage(3, 'wallRight', MapTileWidth, MapTileHeight, 0, 0, 3);
Map.addTilesetImage(4, 'wallBottom', MapTileWidth, MapTileHeight, 0, 0, 4);
Map.addTilesetImage(5, 'wallTop', MapTileWidth, MapTileHeight, 0, 0, 5);
Map.addTilesetImage(6, 'floor', MapTileWidth, MapTileHeight, 0, 0, 6); //Monstor Spawn Square
Map.addTilesetImage(7, 'floor_1', MapTileWidth, MapTileHeight, 0, 0, 7);
Map.addTilesetImage(8, 'floor_2', MapTileWidth, MapTileHeight, 0, 0, 8);
Map.addTilesetImage(9, 'floor_3', MapTileWidth, MapTileHeight, 0, 0, 9);
Map.addTilesetImage(10, 'floor_4', MapTileWidth, MapTileHeight, 0, 0, 10);
Map.addTilesetImage(11, 'floor_5', MapTileWidth, MapTileHeight, 0, 0, 11);
Map.addTilesetImage(12, 'floor_6', MapTileWidth, MapTileHeight, 0, 0, 12);
Map.addTilesetImage(13, 'floor_7', MapTileWidth, MapTileHeight, 0, 0, 13);
Map.addTilesetImage(14, 'floor_8', MapTileWidth, MapTileHeight, 0, 0, 14);
Map.addTilesetImage(15, 'floor', MapTileWidth, MapTileHeight, 0, 0, 15);
MapLayer = Map.createLayer(0, Map.tilesets, 0, 0);
Map.forEachTile(tile => {
//Generate sprites on specific map tiles
if (tile.index == 16) {
this.Spikes.create(tile.pixelX + 8, tile.pixelY + 8, "spikes")
.play('spikes')
.setDepth(10);
}
});
Map.forEachTile(tile => {
//Generate sprites on specific map tiles
if (tile.index == 6) {
this.Demons.create(tile.pixelX + 8, tile.pixelY + 8, "demon")
.play('DemonStand')
.setSize(22, 30)
.setOffset(5, 7)
.setDepth(10);
this.physics.add.collider(this.Demons);
this.physics.add.collider(this.Demons, MapLayer);
MonsterCount++;
}
});
Map.setCollisionBetween(2, 5, true);
//CREATE PLAYER || CREATE PLAYER || CREATE PLAYER
Player = this.add.container(176, 816);
this.sword = this.add.sprite(4, 8, "sword");
this.player = this.add.sprite(0, 0, "player");
Player.setSize(16, 20);
Player.add([this.sword, this.player]);
this.physics.add.collider(Player, MapLayer);
this.cameras.main.startFollow(Player);
PlayerWeapon = this.add.container(0, 0);
PlayerWeapon.setSize(22, 22);
this.physics.add.existing(Player);
this.physics.add.existing(PlayerWeapon);
//FINAL CHANGES || FINAL CHANGES || FINAL CHANGES
this.sword.setOrigin(0.5, 1);
this.sword.angle = 20;
MonsterCount--;
Player.setDepth(100);
//Damage function
let CheckSpikeOverlap = this.physics.add.overlap(Player, this.Spikes, (player, spikeSprite) => {
if (spikeSprite.anims.currentFrame.index == 4) {
PlayerHealth -= EnemyDamage;
CheckSpikeOverlap.active = false;
this.time.addEvent({
delay: 1000,
callback: () => {
CheckSpikeOverlap.active = true;
},
});
}
});
let CheckEnemyOverlap = this.physics.add.overlap(Player, this.Demons, (player, enemy) => {
// if (enemy.anims.currentFrame.index==4 || enemy.anims.currentFrame.index==8){
PlayerHealth -= EnemyDamage;
CheckEnemyOverlap.active = false;
this.time.addEvent({
delay: 1000,
callback: () => {
CheckEnemyOverlap.active = true;
},
});
// }
});
let CheckWeaponOverlap = this.physics.add.overlap(PlayerWeapon, this.Demons, (weapon, enemy) => {
if (PlayerAttack == true) {
enemy.destroy();
MonsterCount--;
CheckWeaponOverlap.active = false;
this.time.addEvent({
delay: 1000,
callback: () => {
CheckWeaponOverlap.active = true;
},
});
}
});
}
update() {
PlayerX = Player.body.position.x;
PlayerY = Player.body.position.y;
//PLAYER MOVEMENT || PLAYER MOVEMENT || PLAYER MOVEMENT
this.Demons.forEachAlive(function (enemy) {
MonsterX = enemy.body.position.x;
MonsterY = enemy.body.position.y;
let DifferenceX=PlayerX-MonsterX;
let DifferenceY=PlayerY-MonsterY;
if (DifferenceX>=400 || DifferenceX<=400){
if (MonsterX<PlayerX){
enemy.body.setVelocityX(EnemySpeed);
enemy.setScale(1);
enemy.play("walk", true);
} else if (MonsterX>PlayerX) {
enemy.body.setVelocityX(-EnemySpeed);
enemy.setScale(-1,1);
enemy.play("walk", true);
} else {
enemy.body.setVelocityX(0);
}
}
if (DifferenceY>=400 || DifferenceY<=400){
if (MonsterY<PlayerY){
enemy.body.setVelocityY(EnemySpeed);
enemy.play("walk", true);
} else if (MonsterY>PlayerY) {
enemy.body.setVelocityY(-EnemySpeed);
enemy.play("walk", true);
} else {
enemy.body.setVelocityY(0);
}
}
});
//PLAYER ATTACK
if (this.keys.SPACE.isDown && PlayerAttackTimer == false) {
PlayerAttack = true;
}
if (PlayerAttack == true && PlayerAttackTimer == false) {
this.time.addEvent({
delay: 3,
callback: () => {
this.sword.angle += 2;
},
repeat: 35
});
this.time.addEvent({
delay: 295,
callback: () => {
this.time.addEvent({
delay: 3,
callback: () => {
this.sword.angle -= 2;
},
repeat: 35
});
},
});
PlayerAttackTimer = true;
this.time.addEvent({
delay: 400,
callback: () => {
PlayerAttack = false;
},
});
this.time.addEvent({
delay: 1500,
callback: () => {
PlayerAttackTimer = false;
},
});
}
//MOVE PLAYER WITH KEY PRESS
if (PlayerFlip == true) {
Player.setSize(-16, 15);
PlayerWeapon.x = PlayerX - 6;
PlayerWeapon.y = PlayerY + 6;
} else if (PlayerFlip == false) {
Player.setSize(16, 15);
PlayerWeapon.x = PlayerX + 23;
PlayerWeapon.y = PlayerY + 6;
}
if (this.cursors.left.isDown || this.keys.A.isDown) {
Player.body.setVelocityY(0);
Player.body.setVelocityX(-PlayerSpeed);
Player.setScale(-1, 1);
this.player.play("walk", true);
PlayerFlip = true;
} else if (this.cursors.right.isDown || this.keys.D.isDown) {
Player.body.setVelocityY(0);
Player.body.setVelocityX(PlayerSpeed);
Player.setScale(1);
this.player.play("walk", true);
PlayerFlip = false;
} else if (this.cursors.up.isDown || this.keys.W.isDown) {
Player.body.setVelocityX(0);
Player.body.setVelocityY(-PlayerSpeed);
this.player.play("walk", true);
} else if (this.cursors.down.isDown || this.keys.S.isDown) {
Player.body.setVelocityX(0);
Player.body.setVelocityY(PlayerSpeed);
this.player.play("walk", true);
} else {
this.player.play("stand", true);
Player.body.setVelocityX(0);
Player.body.setVelocityY(0);
}
}
}
There are several issues here, to look out for:
first the Demon, group cannot be static if you want to set a velocity
. You need to change this line of code
this.Demons = this.physics.add.staticGroup();
to this this.Demons = this.physics.add.group();
Than function this.Demons.forEachAlive(...);
does not exist (on groups), you would have to rewrite it to something like this
this.Demons.getChildren().forEach(function (enemy) {
if (!enemy.active ){
return;
}
...
});
and as mentioned by Sly_cardinal the check is not 100% correct.
After these changes the game should run.
Info/btw: Phaser has great utility / helper functions, that can't help with calculations. I would use the function
Phaser.Math.Distance.BetweenPoints(...)
orPhaser.Math.Distance.Between(...)
(link to the documentation) to messaure / check the distance between the player and enemy.The distance check could look something like this:
if(Phaser.Math.Distance.BetweenPoints(Player.body.position, enemy.body.position) < 400 ) { ... }