You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
437 lines
12 KiB
437 lines
12 KiB
class Robot {
|
|
constructor(height, width, x, y, scene, name = 'enemy', speed = SPEED_BEGIN, speedReload = SPEED_RELOAD_BEGIN, range = RANGE_BEGIN, damage = DAMAGE_BEGIN, lNode = []) {
|
|
this.speedBonus = 1;
|
|
this.attackBonus = 1;
|
|
this.name = name;
|
|
this.height = height;
|
|
this.width = width;
|
|
this.x = x;
|
|
this.y = y;
|
|
this.life = new HealthBar(scene, selectWord("LIFE", "VIE"), this.width * 2, this.width / 3, this.x, this.y - this.width, LIFE, 0x008000);
|
|
this.shield = new HealthBar(scene, selectWord("SHIELD", "BOUCLIER"), this.width * 2, this.width / 3, this.x, this.y - this.width * 1.5, SHIELD, 0x0000FF);
|
|
|
|
this.canAttack = true;
|
|
this.missile = new Missile(scene, 'bullet', this.width / 5, this.width / 4);
|
|
scene.add.existing(this.missile);
|
|
|
|
this.addScene(scene);
|
|
|
|
this.lNode = lNode;
|
|
|
|
this.setSpeed(speed);
|
|
this.setSpeedReload(speedReload);
|
|
this.setRange(range);
|
|
this.setDamage(damage);
|
|
|
|
this.setX(this.x);
|
|
this.setY(this.y);
|
|
|
|
this.team = undefined;
|
|
}
|
|
|
|
|
|
addScene(scene) {
|
|
this.scene = scene;
|
|
if (this.name === 'enemy') {
|
|
this.circle = this.scene.add.image(this.x, this.y, 'enemy').setOrigin(0.5, 0.5).setInteractive();
|
|
} else {
|
|
this.circle = this.scene.add.image(this.x, this.y, 'myBot').setOrigin(0.5, 0.5).setInteractive();
|
|
}
|
|
this.circle.displayWidth = this.width;
|
|
this.circle.displayHeight = this.height;
|
|
this.circle.on('pointerdown', () => this.click());
|
|
}
|
|
|
|
click() {
|
|
if (this.circleRange === undefined) {
|
|
this.drawRange();
|
|
} else {
|
|
this.eraseRange();
|
|
}
|
|
|
|
this.doEvent();
|
|
}
|
|
|
|
addEvent(eventClick, contextClick) {
|
|
this.eventClick = eventClick;
|
|
this.contextClick = contextClick;
|
|
}
|
|
|
|
doEvent() {
|
|
if (this.eventClick !== undefined && this.contextClick !== undefined) {
|
|
this.eventClick.call(this.contextClick, this);
|
|
}
|
|
}
|
|
|
|
addShield(shield) {
|
|
this.shield.increase(shield);
|
|
}
|
|
|
|
setX(x) {
|
|
this.x = x;
|
|
this.life.setX(this.x);
|
|
this.shield.setX(this.x);
|
|
this.circle.setX(this.x);
|
|
this.drawCircleRange();
|
|
}
|
|
|
|
setY(y) {
|
|
this.y = y;
|
|
let yLife = this.y - this.width;
|
|
let yShield = this.y - this.width * 1.5;
|
|
if (yLife < 0) {
|
|
yShield = this.y + this.width - this.shield.height;
|
|
yLife = this.y + this.width * 1.5 - this.shield.height;
|
|
} else {
|
|
if (yShield < 0) {
|
|
yShield = yLife;
|
|
yLife = this.y + this.width - this.shield.height;
|
|
}
|
|
}
|
|
this.life.setY(yLife);
|
|
this.shield.setY(yShield);
|
|
this.circle.setY(this.y);
|
|
this.drawCircleRange();
|
|
}
|
|
|
|
setTint(color) {
|
|
this.circle.setTint(color);
|
|
}
|
|
|
|
clearTint() {
|
|
this.circle.clearTint();
|
|
}
|
|
|
|
setTarget(target) {
|
|
this.target = target;
|
|
}
|
|
|
|
updateTarget() {
|
|
if (this.verifyTarget())
|
|
this.setTargetPos(this.target.x, this.target.y);
|
|
}
|
|
|
|
setTargetPos(x, y) {
|
|
}
|
|
|
|
setDamage(damage = this.damage) {
|
|
this.damage = damage + DAMAGE_BASE;
|
|
}
|
|
|
|
setRange(range = this.range) {
|
|
this.range = range + RANGE_BASE;
|
|
this.drawCircleRange();
|
|
}
|
|
|
|
setSpeed(speed = this.speed) {
|
|
this.speed = speed + SPEED_BASE;
|
|
}
|
|
|
|
setSpeedReload(speedReload = this.speedReload) {
|
|
this.speedReload = speedReload + SPEED_RELOAD_BASE;
|
|
}
|
|
|
|
setAttackBonus(amount) {
|
|
this.attackBonus = amount;
|
|
}
|
|
|
|
increaseSpeedBonus(amount) {
|
|
this.speedBonus += amount;
|
|
}
|
|
|
|
decreaseSpeedBonus(amount) {
|
|
this.speedBonus -= amount;
|
|
console.log(this.speed);
|
|
}
|
|
|
|
advanceToTarget() {
|
|
if (this.verifyTarget()) {
|
|
this.advanceTo(this.target);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
advanceTo(target) {
|
|
if (target.x !== this.x || target.y !== this.y) {
|
|
let x = false;
|
|
let y = false;
|
|
let velocity = this.getVelocity(target);
|
|
let newX = velocity[0] + this.x;
|
|
let newY = velocity[1] + this.y;
|
|
if ((velocity[0] >= 0 && newX >= target.x) || (velocity[0] <= 0 && newX <= target.x)) {
|
|
this.setX(target.x);
|
|
x = true;
|
|
} else
|
|
this.setX(this.x + velocity[0]);
|
|
|
|
if ((velocity[1] >= 0 && newY >= target.y) || (velocity[1] <= 0 && newY <= target.y)) {
|
|
this.setY(target.y);
|
|
y = true;
|
|
} else
|
|
this.setY(this.y + velocity[1]);
|
|
return !(x && y);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
fleeFromTarget() {
|
|
if (this.verifyTarget()) {
|
|
return this.fleeFrom(this.target)
|
|
}
|
|
return false;
|
|
}
|
|
|
|
fleeFrom(target) {
|
|
if (this.target.x !== this.x || this.target.y !== this.y) {
|
|
let velocity = this.getVelocity(target, true);
|
|
if (velocity[0] >= 0 && this.x - this.width / 2 <= 0) {
|
|
this.setX(this.width / 2);
|
|
} else if (velocity[0] <= 0 && this.x + this.width / 2 >= WIDTH_MAP)
|
|
this.setX(WIDTH_MAP - this.width / 2);
|
|
else
|
|
this.setX(this.x - velocity[0]);
|
|
|
|
if (velocity[1] >= 0 && this.y - this.width / 2 <= 0)
|
|
this.setY(this.height / 2);
|
|
else if (velocity[1] <= 0 && this.y + this.width / 2 >= WIDTH_MAP)
|
|
this.setY(WIDTH_MAP - this.height / 2);
|
|
else
|
|
this.setY(this.y - velocity[1]);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
getVelocity(target, calcul = false) {
|
|
let velocity = [];
|
|
let diffX = target.x - this.x;
|
|
let diffY = target.y - this.y;
|
|
if (diffX === 0 && diffY === 0) {
|
|
|
|
}
|
|
let hypot = Math.hypot(diffX, diffY);
|
|
velocity[0] = diffX / hypot * SPEED * this.speed * this.speedBonus * SPEED_GAME; // Velocity X
|
|
velocity[1] = diffY / hypot * SPEED * this.speed * this.speedBonus * SPEED_GAME; // Velocity Y
|
|
if (calcul) {
|
|
if (this.x + this.width / 2 + velocity[0] > WIDTH_MAP || this.x - this.width / 2 - velocity[0] < 0) {
|
|
velocity[1] += velocity[0] * Math.sign(velocity[1]);
|
|
velocity[0] = 0;
|
|
} else {
|
|
if (this.y + this.width / 2 - velocity[1] > WIDTH_MAP || this.y - this.width / 2 + velocity[1] < 0) {
|
|
velocity[0] += velocity[1] * Math.sign(-velocity[0]);
|
|
velocity[1] = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
return velocity;
|
|
}
|
|
|
|
|
|
attackTarget(percentBonus = 0) {
|
|
if (this.verifyTarget()) {
|
|
if (this.canAttack)
|
|
this.attack(this.target, percentBonus);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
verifyTarget() {
|
|
if (this.haveTarget()) {
|
|
if (!this.target.isAlive()) {
|
|
this.setTarget(null);
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
attack(target, percentBonus) {
|
|
this.canAttack = false;
|
|
|
|
this.missile.setPosition(this.x, this.y).setVisible(true);
|
|
|
|
this.missile.setRotation(Math.atan2(this.y - this.target.y, this.x - this.target.x) - 3.14 / 2);
|
|
|
|
this.scene.sound.play('shot');
|
|
|
|
let duration = this.calcDistance(this.target) * WIDTH_MAP / 1000 / SPEED_GAME;
|
|
|
|
this.scene.tweens.add({
|
|
targets: this.missile,
|
|
x: target.x,
|
|
y: target.y,
|
|
ease: 'Linear',
|
|
duration: duration,
|
|
onComplete: () => this.finishAttack(target, percentBonus)
|
|
});
|
|
|
|
this.scene.time.addEvent({
|
|
delay: SPEED_RELOAD / this.speedReload / SPEED_GAME,
|
|
callback: this.reload,
|
|
callbackScope: this
|
|
});
|
|
}
|
|
|
|
finishAttack(target, percentBonus) {
|
|
if (target.beAttack(this.damage * this.attackBonus * DAMAGE * percentBonus, this.team)) {
|
|
this.setTarget(null);
|
|
}
|
|
this.missile.setVisible(false);
|
|
if (this.attackBonus !== 1) {
|
|
this.setAttackBonus(1);
|
|
}
|
|
}
|
|
|
|
reload() {
|
|
this.canAttack = true;
|
|
}
|
|
|
|
beAttack(damage, team) {
|
|
let diff = this.shield.decrease(damage);
|
|
|
|
let style = {font: HEIGHT_DAMAGE.toString() + 'px stencil', fill: "#ffff00"};
|
|
let text = this.scene.add.text(this.x, this.y, damage.toString(), style).setOrigin(0, 1);
|
|
|
|
this.scene.tweens.add({
|
|
targets: text,
|
|
x: this.x + 30,
|
|
y: this.y - 50,
|
|
alpha: 0,
|
|
duration: DURATION_DAMAGE,
|
|
ease: 'Sine.easeOut',
|
|
onComplete: () => text.destroy()
|
|
})
|
|
|
|
this.scene.sound.play('hit');
|
|
console.log('HIT');
|
|
|
|
if (diff > 0) {
|
|
console.log("Shield Broken");
|
|
this.life.decrease(diff);
|
|
}
|
|
this.addScore(team)
|
|
return this.die();
|
|
}
|
|
|
|
addScore(team) {
|
|
if (team !== undefined) {
|
|
team.addScore(SCORE_HIT);
|
|
if (this.life.value === 0) {
|
|
team.addScore(SCORE_KILL);
|
|
}
|
|
}
|
|
}
|
|
|
|
isTargetInRange(percentRange = 1) {
|
|
if (this.haveTarget()) {
|
|
return this.calcDistance(this.target) <= this.range * RANGE * percentRange;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
calcDistance(robot) {
|
|
return Math.hypot(robot.x - this.x, robot.y - this.y);
|
|
}
|
|
|
|
isAlive() {
|
|
return this.life.value > 0;
|
|
}
|
|
|
|
die() {
|
|
if (this.life.value === 0) {
|
|
if (this.circleRange !== undefined)
|
|
this.circleRange.destroy();
|
|
this.circle.destroy();
|
|
this.shield.destroy();
|
|
this.life.destroy();
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
haveTarget() {
|
|
return this.target != null;
|
|
}
|
|
|
|
read() {
|
|
this.verifyTarget();
|
|
for (let i = 0; i < this.lNode.length; i++) {
|
|
if (this.lNode[i].do(this)) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
addNode(node) {
|
|
this.lNode.push(node);
|
|
}
|
|
|
|
drawRange() {
|
|
this.circleRange = this.scene.add.graphics();
|
|
|
|
this.drawCircleRange();
|
|
}
|
|
|
|
eraseRange() {
|
|
this.circleRange.clear();
|
|
this.circleRange = undefined;
|
|
}
|
|
|
|
drawCircleRange() {
|
|
if (this.circleRange !== undefined) {
|
|
|
|
this.circleRange.clear();
|
|
|
|
let color = COLOR_GREEN;
|
|
let thickness = 4;
|
|
let alpha = 1 / 3;
|
|
this.circleRange.lineStyle(thickness, color, alpha);
|
|
let radius = this.range * RANGE;
|
|
this.circleRange.strokeCircle(this.x, this.y, radius);
|
|
|
|
color = COLOR_ORANGE;
|
|
alpha = 2 / 3;
|
|
this.circleRange.lineStyle(thickness, color, alpha);
|
|
radius = this.range * RANGE * 2 / 3;
|
|
this.circleRange.strokeCircle(this.x, this.y, radius);
|
|
|
|
color = COLOR_RED;
|
|
alpha = 1;
|
|
this.circleRange.lineStyle(thickness, color, alpha);
|
|
radius = this.range * RANGE / 3;
|
|
this.circleRange.strokeCircle(this.x, this.y, radius);
|
|
}
|
|
}
|
|
|
|
|
|
cleanNodes() {
|
|
this.lNode = [];
|
|
}
|
|
|
|
setNodes(lNode) {
|
|
this.cleanNodes();
|
|
lNode.forEach(node => this.addNode(node));
|
|
}
|
|
|
|
setVisible(boolean) {
|
|
this.circle.setVisible(boolean);
|
|
this.life.setVisible(boolean);
|
|
this.shield.setVisible(boolean);
|
|
if (this.circleRange !== undefined) {
|
|
this.circleRange.setVisible(boolean);
|
|
}
|
|
}
|
|
|
|
getTreeJson() {
|
|
let json = '{' + toJson("type", "waria");
|
|
json += '"lNode":[';
|
|
this.lNode.forEach(node => json += node.getTreeJson() + ',');
|
|
json = endLineJson(json);
|
|
json += ']}';
|
|
return json;
|
|
}
|
|
}
|