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' }); // 震动 } }