Files
Test/js/player/index.js

162 lines
3.9 KiB
JavaScript
Raw Permalink Normal View History

2025-12-10 17:47:15 +08:00
import Animation from '../base/animation';
import { SCREEN_WIDTH, SCREEN_HEIGHT } from '../render';
import Bullet from './bullet';
// 玩家相关常量设置
const PLAYER_IMG_SRC = 'images/turtle5.png';
const PLAYER_WIDTH = 80;
const PLAYER_HEIGHT = 80;
const EXPLO_IMG_PREFIX = 'images/explosion';
const PLAYER_SHOOT_INTERVAL = 20;
export default class Player extends Animation {
constructor() {
super(PLAYER_IMG_SRC, PLAYER_WIDTH, PLAYER_HEIGHT);
// 初始化坐标
this.init();
// 初始化事件监听
this.initEvent();
}
init() {
// 玩家固定在屏幕中心
this.x = SCREEN_WIDTH / 2 - this.width / 2;
this.y = SCREEN_HEIGHT / 2 - this.height / 2;
// 用于在手指移动的时候标识手指是否已经在飞机上了
this.touched = false;
this.isActive = true;
this.visible = true;
// 设置爆炸动画
this.initExplosionAnimation();
// 初始化子弹(鞭子)
this.angle = 0;
this.radius = PLAYER_WIDTH * 1.5; // 旋转半径
this.bullets = [];
// 创建两个子弹
for (let i = 0; i < 2; i++) {
const bullet = GameGlobal.databus.pool.getItemByClass('whip_bullet', Bullet);
bullet.init(this.x, this.y);
this.bullets.push(bullet);
GameGlobal.databus.bullets.push(bullet);
}
}
// 预定义爆炸的帧动画
initExplosionAnimation() {
const EXPLO_FRAME_COUNT = 19;
const frames = Array.from(
{ length: EXPLO_FRAME_COUNT },
(_, i) => `${EXPLO_IMG_PREFIX}${i + 1}.png`
);
this.initFrames(frames);
}
/**
* 判断手指是否在飞机上
* @param {Number} x: 手指的X轴坐标
* @param {Number} y: 手指的Y轴坐标
* @return {Boolean}: 用于标识手指是否在飞机上的布尔值
*/
checkIsFingerOnAir(x, y) {
const deviation = 30;
return (
x >= this.x - deviation &&
y >= this.y - deviation &&
x <= this.x + this.width + deviation &&
y <= this.y + this.height + deviation
);
}
/**
* 根据手指的位置设置飞机的位置
* 保证手指处于飞机中间
* 同时限定飞机的活动范围限制在屏幕中
*/
setAirPosAcrossFingerPosZ(x, y) {
const disX = Math.max(
0,
Math.min(x - this.width / 2, SCREEN_WIDTH - this.width)
);
const disY = Math.max(
0,
Math.min(y - this.height / 2, SCREEN_HEIGHT - this.height)
);
this.x = disX;
this.y = disY;
}
/**
* 玩家响应手指的触摸事件
* 改变战机的位置
*/
initEvent() {
wx.onTouchStart((e) => {
const { clientX: x, clientY: y } = e.touches[0];
if (GameGlobal.databus.isGameOver) {
return;
}
if (this.checkIsFingerOnAir(x, y)) {
this.touched = true;
this.setAirPosAcrossFingerPosZ(x, y);
}
});
wx.onTouchMove((e) => {
const { clientX: x, clientY: y } = e.touches[0];
if (GameGlobal.databus.isGameOver) {
return;
}
if (this.touched) {
this.setAirPosAcrossFingerPosZ(x, y);
}
});
wx.onTouchEnd((e) => {
this.touched = false;
});
wx.onTouchCancel((e) => {
this.touched = false;
});
}
update() {
if (GameGlobal.databus.isGameOver) {
return;
}
// 更新旋转角度
this.angle += 0.1; // 旋转速度
// 更新子弹位置
this.bullets.forEach((bullet, index) => {
// 两个子弹相差 180 度 (PI)
const currentAngle = this.angle + index * Math.PI;
const bulletX = this.x + this.width / 2 + Math.cos(currentAngle) * this.radius - bullet.width / 2;
const bulletY = this.y + this.height / 2 + Math.sin(currentAngle) * this.radius - bullet.height / 2;
bullet.setPos(bulletX, bulletY);
});
}
destroy() {
this.isActive = false;
this.playAnimation();
GameGlobal.musicManager.playExplosion(); // 播放爆炸音效
wx.vibrateShort({
type: 'medium'
}); // 震动
}
}