import AccountModel from "../../../data/Account/AccountModel"; import npcHelper from "../../../dataManager/npcHelper"; import { AssetsHelper } from "../../../framework/asset/AssetsHelper"; import { BenzAssetManager } from "../../../framework/asset/BenzAssetManager"; import EventManager from "../../../framework/event/EventManager"; import AudioManager from "../../../framework/music/AudioManager"; import utils from "../../../framework/utils/utils"; import Utils from "../../../framework/utils/utils"; import effectManager from "../../../manager/effectManager"; import UITopMenu from "../../../ui/uiview/Interface/UITopMenu"; import LevelLogic from "../../levelLogic"; import gameData from "../../utrl/gameData"; import { ATTACK_MODE, EVENT_TYPE, GAME_OBJECT_TYPE, JOY_STATE, PLAYER_TYPE, ROLE_STATE, WEAPON_TYPE } from "../../utrl/gameEnum"; import gameEventManager from "../../utrl/gameEventManager"; import GameObject from "../gameObject"; import WeaponProp from "../tool/weaponProp"; import ZomBieObject from "../zombie/zombieObject"; import ZombieProp from "../zombie/zombieProp"; import zombieView from "../zombie/zombieView"; import dog_obj from "./dog_obj"; import NodeMove from "./nodeMove"; import PlayerProp from "./playerProp"; import PlayerView from "./playerView"; const { ccclass, requireComponent, property } = cc._decorator; /**玩家实体类 */ @ccclass @requireComponent(NodeMove) export default class PlayerObject extends GameObject { @property(PlayerView) /**视图逻辑 */ player_view: PlayerView = null; /**血条显示 */ @property(cc.Node) cur_hp_bar: cc.Node = null; /**逻辑方法组件 */ player_prop: PlayerProp = null; /**节点控制组件 */ private node_move: NodeMove = null; /**初始化完成 */ private inited = false; /**指令模式中 */ private in_cmd_mode = true; /**待机跟随距离 */ private track_dis_idle = 80; /**行走跟随距离 */ private track_dis_walk = 50; /**本身刚体 */ private rigid: cc.RigidBody = null; /**目标 */ private target: cc.Node = null; /**玩家类型 */ player_type = PLAYER_TYPE.normal; /**角色组,0玩家组,1僵尸组 */ private roles: cc.Node[][] = [[], []]; isDie: boolean = false; isPause = false; /** */ start() { this.node.$hp.$lv_bg.$lv_num.getComponent(cc.Label).string = this.player_prop.level.toString(); } onEnable() { if (this.node_move == null) { this.node_move = this.node.getComponent(NodeMove); } gameEventManager.on(EVENT_TYPE.attack_mode, this.refreshAttackMode, this); gameEventManager.on(EVENT_TYPE.joy_stick, this.onJoyStick, this); gameEventManager.on(EVENT_TYPE.CHANGE_STATUS, this.changeStatue, this) this.rigid = this.node.getComponent(cc.RigidBody); this.rigid.type = cc.RigidBodyType.Dynamic; } changeStatue(flag) { this.isPause = flag; } onDisable() { gameEventManager.off(EVENT_TYPE.joy_stick, this.onJoyStick, this); gameEventManager.off(EVENT_TYPE.CHANGE_STATUS, this.changeStatue, this) } //更新玩家血条 updateHpBar() { let p = this.player_prop.cur_hp / this.player_prop.total_hp; if (p == 1 || p == 0) { this.cur_hp_bar.parent.active = false; } else { this.cur_hp_bar.parent.active = true; this.cur_hp_bar.width = this.cur_hp_bar.parent.width * p; } } //刷新玩家动画状态 updateAnimState() { if (this.player_prop.refresh_cmd) { this.player_prop.refresh_cmd = false; this.player_view.cur_ani_state = null; let id = null; if (this.player_prop.cur_weapon != null) { id = this.player_prop.cur_weapon.id; } else if (this.player_prop.close_weapon != null) { id = this.player_prop.close_weapon.id; } switch (this.player_prop.cur_state) { case ROLE_STATE.idle: { this.player_view.playIdle(id); break; } case ROLE_STATE.walk: { this.player_view.playWalk(id); break; } } } } update(dt: number) { if (this.isPause) { return; } if (this.roles[0] == null || this.roles[1] == null) { return; } this.updateHpBar(); if (!this.inited || this.player_prop.cur_state == ROLE_STATE.die) { return; } //刷新迷你地图位置 if (this.player_prop.is_leader) { gameEventManager.emit(EVENT_TYPE.refresh_mini_map_pos, this.node.position); } this.updateAnimState(); let leader: cc.Node = null; for (let c of this.roles[0]) { if (!c.isValid) { continue; } if (c.getComponent(PlayerObject).player_prop.is_leader) { leader = c; break; } } this.target = null; this.target = this.runState(dt, this.roles[1], leader); if (this.target != null) { if (this.node.x < this.target.x) { this.player_view.node.scaleX = -1; this.player_view.node.$upgrade.scaleX = -1; } else { this.player_view.node.scaleX = 1; this.player_view.node.$upgrade.scaleX = 1; } } else if (!this.in_cmd_mode) { let o = 5 if (this.rigid.linearVelocity.x > o) { this.player_view.node.scaleX = -1; } else if (this.rigid.linearVelocity.x < -o) { this.player_view.node.scaleX = 1; } } if (this.node.parent.parent.name.indexOf('dungeon_') < 0) { let x = this.node.x; let y = this.node.y; this.player_prop.pos = cc.v3(x, y); } } /**初始化 */ init(playerID, roles: cc.Node[][]) { this.type = GAME_OBJECT_TYPE.player; if (this.player_prop == null) { this.player_prop = new PlayerProp(); } this.createDog(playerID); this.player_prop.init(playerID); this.roles = roles; this.isDie = false; //白壮汉跟黑壮汉特殊缩放 if (playerID == 16 || playerID == 17) { this.node.scale = 1.3; } this.inited = true; } createDog(id) { if (id == 12 && cc.isValid(this.node)) { let dogAss = BenzAssetManager.getInstance().getAsset(AssetsHelper.PREFAB_DOG); let dogNode = cc.instantiate(dogAss) as unknown as cc.Node; dogNode.parent = this.node.parent; dogNode.x = this.node.x; dogNode.y = this.node.y; dogNode.getComponent(dog_obj).setFollowTarget(this.node); } } /**设置成领队 * @param is_leader 是领队 */ setLeader(is_leader: boolean) { this.player_prop.is_leader = is_leader; this.node_move.enabled = this.player_prop.is_leader; // this.rigid.type = is_leader ? cc.RigidBodyType.Animated : cc.RigidBodyType.Dynamic; if (is_leader) { this.node.group = 'leader'; } else { this.node.group = 'normal'; } this.node.active = false; this.node.active = true; } /**玩家死亡 */ die() { if (this.player_prop.cur_state == ROLE_STATE.die) { return; } this.isDie = true; gameData.peopleDieNum += 1; this.playDieAnm(); this.player_prop.cur_state = ROLE_STATE.die; this.rigid.type = cc.RigidBodyType.Animated; this.node_move.enabled = false; gameData.curPeopleNum -= 1; if (this.player_prop.is_leader) { //console.log('发送随机领队事件') gameEventManager.emit(EVENT_TYPE.random_leader); } this.becomeZombie(); EventManager.emit(EVENT_TYPE.UPDATE_PEOPLE_NUM); gameEventManager.emit(EVENT_TYPE.player_die); } //变僵尸 becomeZombie() { this.scheduleOnce(() => { let id = this.player_view.getViewId(); //如果是英雄 直接移除 if (id >= 49 && id <= 52) { gameEventManager.emit(EVENT_TYPE.RECOVER_PLAYER, this.node); // this.node.destroy(); return; } let z_id = npcHelper.getZombieIdByPlayerId(id); let pos = this.node.position; //发送生成僵尸事件 gameEventManager.emit(EVENT_TYPE.add_zombie, z_id, pos); gameEventManager.emit(EVENT_TYPE.RECOVER_PLAYER, this.node); //this.node.destroy(); AudioManager.play('shift'); }, 2); } //播放死亡 playDieAnm() { let id = null; if (this.player_prop.cur_weapon != null) { id = this.player_prop.cur_weapon.id; } else if (this.player_prop.close_weapon != null) { id = this.player_prop.close_weapon.id; } this.player_view.playDie(id); } /**刷新攻击模式 */ private refreshAttackMode() { // console.log('切换攻击模式', gameData.cur_attack_mode); UITopMenu.getInstance().initSp(); if (gameData.cur_attack_mode == ATTACK_MODE.close) { this.player_prop.cur_weapon = this.player_prop.close_weapon; } else { this.player_prop.cur_weapon = this.player_prop.remote_weapon; } this.player_prop.refreshWeapon(); AudioManager.play('switchting'); } /**遥感回调 * @param state 当前遥感状态 * @param angle 当前遥感角度 * @param power 当前遥感力度 */ private onJoyStick(state: JOY_STATE, angle: number, power: number) { if (this.player_prop.cur_state == ROLE_STATE.die) { return; } switch (state) { case JOY_STATE.start: { this.in_cmd_mode = true; break; } case JOY_STATE.move: { if (this.target == null) { if (angle < 90 || angle > 270) { this.player_view.node.scaleX = -1; } else { this.player_view.node.scaleX = 1; } } if (!this.player_prop.is_leader) { return; } this.player_prop.cur_state = ROLE_STATE.walk; let id = null; if (this.player_prop.cur_weapon != null) { id = this.player_prop.cur_weapon.id; } else if (this.player_prop.close_weapon != null) { id = this.player_prop.close_weapon.id; } this.player_view.playWalk(id); break; } case JOY_STATE.end: { this.player_prop.cur_state = ROLE_STATE.idle; let id = null; if (this.player_prop.cur_weapon != null) { id = this.player_prop.cur_weapon.id; } else if (this.player_prop.close_weapon != null) { id = this.player_prop.close_weapon.id; } this.player_view.playIdle(id); this.rigid.linearVelocity = cc.v2(); this.in_cmd_mode = false; break; } } } /**运行状态机 */ private runState(dt: number, zombie_nds: cc.Node[], leader: cc.Node): cc.Node { let obj: cc.Node = null; if (gameData.cur_attack_mode == ATTACK_MODE.remote) { obj = this.useRemoteWeapon(dt, zombie_nds, leader); } else if (!this.in_cmd_mode) { this.useCloseWeapon(dt, zombie_nds, leader); } if (this.in_cmd_mode && !this.player_prop.is_leader) { this.moveToLeader(leader); } return obj; } //是否隔墙 isCloseWall(target) { let v_sub = target.position.sub(this.node.position.add(cc.v3(0, 30, 0))).normalize(); let rad = Math.acos(v_sub.x); if (v_sub.y < 0) { rad = Math.PI * 2 - rad; } let angle = rad / Math.PI * 180; let rayCast = Utils.getRayCast(this.node.getPosition(), target.getPosition(), cc.RayCastType.All); if (rayCast) { rayCast.sort((a, b) => { let aDis = target.position.sub(a.collider.node.position).mag(); let bDis = target.position.sub(b.collider.node.position).mag(); if (aDis < bDis) { return a - b; } }) for (let i = 0; i < rayCast.length; ++i) { if (rayCast[i].collider.node.name == 'player_object') { break; } if (rayCast[i].collider.node.name !== 'zombie_object') { return true } } return false; } } /**使用远程武器 */ private useRemoteWeapon(dt: number, zombie_nds: cc.Node[], leader: cc.Node): cc.Node { let obj: cc.Node = null; if (this.player_prop.remote_weapon != null) { let range = this.player_prop.remote_weapon.range; let target = this.getCloseTarget(zombie_nds, range); if (target != null) { if (!this.isCloseWall(target)) { this.player_view.AimZombie(target, this.player_prop.remote_weapon.id); this.remoteAttack(dt, target); obj = target; } } else { this.player_view.resetGunAngle(this.player_prop.cur_weapon.id); } if (!this.player_prop.is_leader) { this.moveToLeader(leader); } } else if (!this.in_cmd_mode) { this.useCloseWeapon(dt, zombie_nds, leader); } return obj; } /**使用近战武器 */ private useCloseWeapon(dt: number, zombie_nds: cc.Node[], leader: cc.Node) { let range = this.player_prop.search_range; let zombie = this.getCloseTarget(zombie_nds, range); if (zombie != null) { if (this.player_prop.close_weapon != null) { range = this.player_prop.close_weapon.range; let ts = this.getAliiCloseTargets(zombie_nds, range); if (ts.length > 0) { this.closeAttack(dt, ts, this.player_prop.close_weapon.damage + this.player_prop.base_damage); } else { this.moveToTarget(zombie); } } else { range = this.player_prop.hand_range; let ts = this.getAliiCloseTargets(zombie_nds, range); if (ts.length > 0) { this.closeAttack(dt, ts, this.player_prop.base_damage); } else { this.moveToTarget(zombie); } } } else { if (!this.player_prop.is_leader) { this.moveToLeader(leader); } this.player_prop.attack_timer = Number.MAX_VALUE; } } /**进行远程攻击 */ remoteAttack(dt: number, target: cc.Node) { let cbk = () => { let v_sub = target.position.sub(this.node.position.add(cc.v3(0, 30, 0))).normalize(); let rad = Math.acos(v_sub.x); if (v_sub.y < 0) { rad = Math.PI * 2 - rad; } let ev = EVENT_TYPE.bullet0; if (this.player_prop.remote_weapon.type == WEAPON_TYPE.gun1) { ev = EVENT_TYPE.bullet1; } let damage = this.player_prop.remote_weapon.damage; let player = this; //发送远程攻击事件生成对应子弹 gameEventManager.emit(ev, rad, damage, player); }; this.player_prop.attackRun(dt, cbk); } //怪物死亡加经验 addExp(exp: number) { //let lb = this.node.$hp.$lv_bg.$lv_num.getComponent(cc.Label); if (this.player_prop.level >= 4) { return; } let curExp = this.player_prop.exp += exp; let upgreadLimit = this.player_prop.upgradeCondition; if (curExp >= upgreadLimit) { this.player_prop.level += 1; this.player_prop.updateTotalHp(); AudioManager.play('lvup'); this.player_prop.exp = 0; effectManager.playEff(this.node.$view, 'upgrade', null, false); this.node.$hp.$lv_bg.$lv_num.getComponent(cc.Label).string = this.player_prop.level.toString(); } } /**进行近战攻击 */ private closeAttack(dt: number, ts: cc.Node[], damage: number) { let cbk = () => { //console.log('近战攻击', damage); var curLevel = AccountModel.getInstance().curLevel; this.scheduleOnce(() => { if (this.player_prop.cur_state == ROLE_STATE.die) return; for (let t of ts) { if (!t.isValid) { return; } let comp = t.getComponent(ZomBieObject); if(comp.isDie){ return; } let bDie = this.player_prop.attack(comp, damage); let zomView = t.getComponent(zombieView); zomView.hitEff(); if (bDie) { this.addExp(comp.zombie_prop.exp); effectManager.zombieDieEff(this.node.parent.parent.$eff_parent, t.getPosition()); let x = t.x; let y = t.y; let pos = cc.v3(x, y); if (curLevel > 1) { gameEventManager.emit(EVENT_TYPE.RESET_ZOMBIE, pos); // console.log('EVENT_TYPE.RESET_ZOMBIE') } t.active = false; gameEventManager.emit(EVENT_TYPE.RECOVER_ZOMBIE, t); AudioManager.play('zombiedie'); gameEventManager.emit(EVENT_TYPE.zombie_die); } } }, 0.2); this.player_prop.cur_state = ROLE_STATE.idle; let id = null; if (this.player_prop.cur_weapon != null) { id = this.player_prop.cur_weapon.id; } else if (this.player_prop.close_weapon != null) { id = this.player_prop.close_weapon.id; } this.player_view.playAttack(id); }; this.player_prop.attackRun(dt, cbk); } /**向领队移动 */ private moveToLeader(leader: cc.Node) { if (leader == null || !this.in_cmd_mode) { return; } this.player_view.node.scaleX = leader.getComponent(PlayerObject).player_view.node.scaleX; let len = leader.position.sub(this.node.position).mag(); if (this.player_prop.cur_state == ROLE_STATE.idle && len > this.track_dis_idle) { this.moveToTarget(leader); } else if (this.player_prop.cur_state == ROLE_STATE.walk && len > this.track_dis_walk) { this.moveToTarget(leader); } else { this.player_prop.cur_state = ROLE_STATE.idle; let id = null; if (this.player_prop.cur_weapon != null) { id = this.player_prop.cur_weapon.id; } else if (this.player_prop.close_weapon != null) { id = this.player_prop.close_weapon.id; } this.player_view.playIdle(id); } } /**范围内最近目标 */ private getCloseTarget(nds: cc.Node[], range: number): cc.Node { let target: cc.Node = null; for (let nd of nds) { if (!nd.isValid) { continue; } let len = nd.position.sub(this.node.position).mag(); if (len < range) { range = len; target = nd; } } return target; } /**范围内所有目标 */ private getAliiCloseTargets(nds: cc.Node[], range: number): cc.Node[] { let targets: cc.Node[] = []; for (let nd of nds) { if (!nd.isValid) { continue; } let len = nd.position.sub(this.node.position).mag(); if (len < range) { targets.push(nd); } } return targets; } /**向目标移动 * @param target 目标 */ private moveToTarget(target: cc.Node) { this.player_prop.cur_state = ROLE_STATE.walk; let v_sub = target.position.sub(this.node.position).normalize(); let rad = Math.acos(v_sub.x); if (v_sub.y < 0) { rad = Math.PI * 2 - rad; } this.setLinearVelocity(rad); let id = null; if (this.player_prop.cur_weapon != null) { id = this.player_prop.cur_weapon.id; } else if (this.player_prop.close_weapon != null) { id = this.player_prop.close_weapon.id; } this.player_view.playWalk(id); } /**设置刚体线性速度 * @param rad 弧度角 */ private setLinearVelocity(rad: number) { this.node.getComponent(cc.RigidBody).linearVelocity = cc.v2(Math.cos(rad), Math.sin(rad)).mul(this.node_move.move_speed); } }