|
|
|
import { AcGameObject } from "../ac_game_object/base.js";
|
|
|
|
|
|
|
|
export class Player extends AcGameObject {
|
|
|
|
constructor(root, info) {
|
|
|
|
super();
|
|
|
|
|
|
|
|
this.root = root;
|
|
|
|
this.id = info.id; // 人物id
|
|
|
|
this.x = info.x; // 人物坐标
|
|
|
|
this.y = info.y;
|
|
|
|
this.width = info.width; // 人物大小
|
|
|
|
this.height = info.height;
|
|
|
|
this.color = info.color; // 人物颜色
|
|
|
|
|
|
|
|
this.vx = 0; // 横纵方向的移动速度
|
|
|
|
this.vy = 0;
|
|
|
|
|
|
|
|
this.speedx = 400; // 水平速度初始速度
|
|
|
|
this.speedy = -1000; // 跳起的初始速度
|
|
|
|
|
|
|
|
this.gravity = 50; // 重力加速度
|
|
|
|
this.ctx = this.root.gamemap.ctx; // 获取canvas对象
|
|
|
|
|
|
|
|
|
|
|
|
this.direction = 1; // 1:向右 -1:向左
|
|
|
|
|
|
|
|
|
|
|
|
// 0:idle 1:向前 2:向后 3:跳跃 4:攻击 5:被打 6: 死亡
|
|
|
|
this.status = 3; // 人物当前状态(总共七种状态)
|
|
|
|
|
|
|
|
this.press_keys = this.root.gamemap.controller.press_keys; // 用户按下的所有键值
|
|
|
|
this.animations = new Map(); // 每个动作动画的配置
|
|
|
|
this.current_frame_cnt = 0; // 当前加载了多少帧
|
|
|
|
|
|
|
|
this.hp = 100; // 初始血量为100
|
|
|
|
this.$hp = this.root.$kof.find(`.kof-head-hp-${this.id}>div`); // 控制血槽
|
|
|
|
this.$hp_div = this.$hp.find('div');
|
|
|
|
|
|
|
|
this.damage = 20;
|
|
|
|
}
|
|
|
|
|
|
|
|
start() {
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
update_controll() {
|
|
|
|
let w, a, d, space;
|
|
|
|
// 两个用户使用不同的按键
|
|
|
|
if (this.id === 0) {
|
|
|
|
w = this.press_keys.has('w'); // 跳
|
|
|
|
a = this.press_keys.has('a'); // 左移
|
|
|
|
d = this.press_keys.has('d'); // 右移
|
|
|
|
space = this.press_keys.has(' '); // 停
|
|
|
|
} else {
|
|
|
|
w = this.press_keys.has('ArrowUp');
|
|
|
|
a = this.press_keys.has('ArrowLeft');
|
|
|
|
d = this.press_keys.has('ArrowRight');
|
|
|
|
space = this.press_keys.has('Enter');
|
|
|
|
}
|
|
|
|
|
|
|
|
// 0表示静止 1表示移动 3表示跳跃
|
|
|
|
if (this.status === 0 || this.status === 1) {
|
|
|
|
if (space) { // 攻击状态
|
|
|
|
this.status = 4;
|
|
|
|
this.vx = 0;
|
|
|
|
this.current_frame_cnt = 0;
|
|
|
|
}
|
|
|
|
else if (w) { // 如果按的是跳
|
|
|
|
if (d) {
|
|
|
|
this.vx = this.speedx;
|
|
|
|
} else if (a) {
|
|
|
|
this.vx = -this.speedx;
|
|
|
|
} else {
|
|
|
|
this.vx = 0;
|
|
|
|
}
|
|
|
|
this.vy = this.speedy;
|
|
|
|
this.status = 3;
|
|
|
|
this.current_frame_cnt = 0;
|
|
|
|
} else if (d) {
|
|
|
|
this.vx = this.speedx;
|
|
|
|
this.status = 1;
|
|
|
|
} else if (a) {
|
|
|
|
this.vx = -this.speedx;
|
|
|
|
this.status = 1;
|
|
|
|
} else {
|
|
|
|
this.vx = 0;
|
|
|
|
this.status = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
update_direction() { // 保证两个人物是对称的
|
|
|
|
if (this.status === 6) return; //如果人物已经gg,不再修改方向
|
|
|
|
let players = this.root.players;
|
|
|
|
if (players[0] && players[1]) {
|
|
|
|
let me = this, you = players[1 - this.id];
|
|
|
|
if (me.x < you.x) me.direction = 1; // 向右
|
|
|
|
else me.direction = -1; // 向左
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
update_move() {
|
|
|
|
this.vy += this.gravity;
|
|
|
|
|
|
|
|
// 改变x,y轴坐标
|
|
|
|
this.x += this.vx * this.time_delta / 1000;
|
|
|
|
this.y += this.vy * this.time_delta / 1000;
|
|
|
|
|
|
|
|
|
|
|
|
if (this.y > 300) {
|
|
|
|
this.y = 300;
|
|
|
|
if (this.status === 3) this.status = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (this.x < 0) {
|
|
|
|
this.x = 0;
|
|
|
|
} else if (this.x + this.width > this.root.gamemap.$canvas.width()) {
|
|
|
|
this.x = this.root.gamemap.$canvas.width() - this.width;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// 是否攻击到对方
|
|
|
|
is_collision(r1, r2) {
|
|
|
|
if (Math.max(r1.x1, r2.x1) > Math.min(r1.x2, r2.x2)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (Math.max(r1.y1, r2.y1) > Math.min(r1.y2, r2.y2)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 是否被攻击
|
|
|
|
is_attack() {
|
|
|
|
if (this.status === 6) return; //如果人物已经gg,不再受到攻击
|
|
|
|
this.status = 5;
|
|
|
|
this.current_frame_cnt = 0;
|
|
|
|
this.hp = Math.max(this.hp - this.damage, 0);
|
|
|
|
|
|
|
|
this.$hp_div.animate({
|
|
|
|
width: this.$hp.parent().width() * this.hp / 100
|
|
|
|
},300);
|
|
|
|
|
|
|
|
this.$hp.animate({
|
|
|
|
width: this.$hp.parent().width() * this.hp / 100
|
|
|
|
},600);
|
|
|
|
|
|
|
|
this.$hp_div.html(`${this.hp}`);
|
|
|
|
|
|
|
|
if (this.hp <= this.damage) {
|
|
|
|
this.$hp_div.css({"background-color":"red"});
|
|
|
|
}
|
|
|
|
if (this.hp === 0) {
|
|
|
|
this.status = 6; // gg
|
|
|
|
this.current_frame_cnt = 0;
|
|
|
|
this.vx = 0; // 被ko之后速度为0
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
update_attack() {
|
|
|
|
if (this.status === 4 && this.current_frame_cnt === 17) {
|
|
|
|
let me = this, you = this.root.players[1 - this.id];
|
|
|
|
let r1; // 自己的攻击矩形
|
|
|
|
if (me.direction > 0) {
|
|
|
|
r1 = {
|
|
|
|
x1: me.x + 120,
|
|
|
|
y1: me.y + 40,
|
|
|
|
x2: me.x + 120 + 105,
|
|
|
|
y2: me.y + 40 + 20,
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
r1 = {
|
|
|
|
x1: me.x - 105,
|
|
|
|
y1: me.y + 40,
|
|
|
|
x2: me.x - 105 + 105,
|
|
|
|
y2: me.y + 40 + 20,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// 对手的人物矩形
|
|
|
|
let r2 = {
|
|
|
|
x1: you.x,
|
|
|
|
y1: you.y,
|
|
|
|
x2: you.x + you.width,
|
|
|
|
y2: you.y + you.height,
|
|
|
|
}
|
|
|
|
|
|
|
|
if (this.is_collision(r1, r2)) {
|
|
|
|
you.is_attack(); // 成功攻击到对方
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
update() {
|
|
|
|
this.update_controll();
|
|
|
|
this.update_move();
|
|
|
|
this.update_direction();
|
|
|
|
this.update_attack();
|
|
|
|
|
|
|
|
this.render();
|
|
|
|
}
|
|
|
|
|
|
|
|
render() {
|
|
|
|
// this.ctx.fillStyle = this.color; // 画布的颜色
|
|
|
|
// this.ctx.fillRect(this.x, this.y, this.width, this.height); // 画人物
|
|
|
|
|
|
|
|
// this.ctx.fillStyle = "blue";
|
|
|
|
// this.ctx.fillRect(this.x,this.y,this.width,this.height);
|
|
|
|
|
|
|
|
|
|
|
|
// if (this.direction > 0) {
|
|
|
|
// this.ctx.fillStyle = "red";
|
|
|
|
// this.ctx.fillRect(this.x + 120,this.y + 40,105,20);
|
|
|
|
// }else {
|
|
|
|
// this.ctx.fillStyle = "green";
|
|
|
|
// this.ctx.fillRect(this.x - 105,this.y + 40,105,20);
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
|
|
let status = this.status;
|
|
|
|
|
|
|
|
if (this.status === 1 && this.direction * this.vx < 0) status = 2;
|
|
|
|
|
|
|
|
// 根据状态获取动画
|
|
|
|
let obj = this.animations.get(status);
|
|
|
|
if (obj && obj.loaded) {
|
|
|
|
if (this.direction > 0) {
|
|
|
|
let k = parseInt(this.current_frame_cnt / obj.frame_rate) % obj.frame_cnt; // 每5帧刷新一次
|
|
|
|
let image = obj.gif.frames[k].image; // 渲染第k张图片
|
|
|
|
this.ctx.drawImage(image, this.x, this.y + obj.offset_y, image.width * obj.scale, image.height * obj.scale);
|
|
|
|
} else {
|
|
|
|
this.ctx.save();
|
|
|
|
this.ctx.scale(-1, 1);
|
|
|
|
this.ctx.translate(-this.root.gamemap.$canvas.width(), 0);
|
|
|
|
|
|
|
|
let k = parseInt(this.current_frame_cnt / obj.frame_rate) % obj.frame_cnt; // 每5帧刷新一次
|
|
|
|
let image = obj.gif.frames[k].image; // 渲染第k张图片
|
|
|
|
this.ctx.drawImage(image, this.root.gamemap.$canvas.width() - this.x - this.width, this.y + obj.offset_y, image.width * obj.scale, image.height * obj.scale);
|
|
|
|
|
|
|
|
this.ctx.restore();
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if (status === 4 || status === 5 || status === 6) { // 动画演示完结束
|
|
|
|
if (this.current_frame_cnt === obj.frame_rate * (obj.frame_cnt - 1)) {
|
|
|
|
if (status === 6) {
|
|
|
|
this.current_frame_cnt--;
|
|
|
|
}
|
|
|
|
else this.status = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
this.current_frame_cnt++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|