import { _decorator, Component, Node } from 'cc'; import { NodeBase } from '../../base/NodeBase'; import { EventTouch, Vec3 } from 'cc'; import { GameGlobalData } from '../../global/GameGlobalData'; import { UmLog } from '../../../../cc-common/cc-util/UmLog'; import { ColliderObject } from '../../base/ColliderObject'; import { Collider2D } from 'cc'; import { ShootingBase } from '../bullet/ShootingBase'; import { EACTIVE_SKILL_TYPE, EPHYSIC_GROUP, GameDefine } from '../../config/GameDefine'; import { LayoutManager } from '../LayoutManager'; import { HeroDataInfo } from '../../global/GameInterface'; import { BulletBase } from '../bullet/BulletBase'; import { Color } from 'cc'; import { UmUtil } from '../../../../cc-common/cc-util/UmUtil'; import { Sprite } from 'cc'; import { math } from 'cc'; import { UmClientEvent } from '../../../../cc-common/cc-util/UmOneToMultiListener'; import { Label } from 'cc'; import { RigidBody2D } from 'cc'; const { ccclass, property } = _decorator; @ccclass('HeroBase') export class HeroBase extends NodeBase { @property(ColliderObject) colliderObject: ColliderObject = null!; @property(ColliderObject) sensor: ColliderObject = null!; @property(RigidBody2D) rigibodyComponent: RigidBody2D = null!; @property(ShootingBase) shooting: ShootingBase = null!; @property(Sprite) theme: Sprite = null!; @property(Label) skillLabel: Label = null!; originPoint = new Vec3(); isShootEnable = false; listEnemyTarget: Node[] = new Array(); listEnemyContact = new Map; currentColor: math.Color; effectColor: Color = Color.GREEN; specialSkill = -1; countImmuneDamageUsing: number = 0; TWEEN_TAG = 1001; isDestroying = false; get isImmuneDamage(): boolean { return this.countImmuneDamageUsing > 0; } protected onLoad(): void { this.TWEEN_TAG = UmUtil.getRandomInt(100000, Number.MAX_SAFE_INTEGER); this.isDestroying = false; } protected start(): void { UmClientEvent.on(GameDefine.EVENT_START_USE_SPECIAL_SKILL, this.onStartUseSpecialSkill.bind(this)); UmClientEvent.on(GameDefine.EVENT_END_USE_SPECIAL_SKILL, this.onEndUseSpecialSkill.bind(this)); UmClientEvent.on(GameDefine.EVENT_START_USE_ACTIVE_SKILL, this.onStartUseActiveSkill.bind(this)); UmClientEvent.on(GameDefine.EVENT_END_USE_ACTIVE_SKILL, this.onEndUseActiveSkill.bind(this)); this.isShootEnable = true; this.registerColliderContact(); this.registerSensor(); this.loadDataAndDisplay(); this.currentColor = new Color(this.theme.color); this.skillLabel.string = ""; } protected onDestroy(): void { UmClientEvent.off(GameDefine.EVENT_START_USE_SPECIAL_SKILL, this.onStartUseSpecialSkill.bind(this)); UmClientEvent.off(GameDefine.EVENT_END_USE_SPECIAL_SKILL, this.onEndUseSpecialSkill.bind(this)); UmClientEvent.off(GameDefine.EVENT_START_USE_ACTIVE_SKILL, this.onStartUseActiveSkill.bind(this)); UmClientEvent.off(GameDefine.EVENT_END_USE_ACTIVE_SKILL, this.onEndUseActiveSkill.bind(this)); } onStartUseSpecialSkill(skillId: number) { UmLog.log("onStartUseSpecialSkill => ", skillId); this.specialSkill = skillId; this.skillLabel.string = `USE SKILL_${skillId}`; } onEndUseSpecialSkill() { UmLog.log("onEndUseSpecialSkill"); this.specialSkill = -1; this.skillLabel.string = ""; } get heroData(): HeroDataInfo { return GameGlobalData.Instance.heroData.getHeroData(); } loadDataAndDisplay() { LayoutManager.instance.GameUI.getHeroHPBar().setMaxHPBar(this.heroData.hp); } protected registerColliderContact() { this.colliderObject.registerBeginContact(this.onBeginContact.bind(this), true); this.colliderObject.registerEndContact(this.onEndContact.bind(this), true); } protected offColliderContact() { this.colliderObject.offContact(); } protected registerSensor() { this.sensor.registerBeginContact(this.onSensorBegin.bind(this), false); this.sensor.registerEndContact(this.onSensorEnd.bind(this), false); } protected offSensor() { this.sensor.offContact(); } getTouchPointInParentNode(touchPoint): Vec3 { return this.node.parent?.getNodeTransform().convertToNodeSpaceAR(touchPoint.toVec3()); } onBeginContact(a: Collider2D, b: Collider2D) { var bGroup = b.group; // UmLog.log("HERO | onBeginContact = " + GameDefine.getPhysicGroupName(a.group), " vs ", GameDefine.getPhysicGroupName(bGroup)); if (b.group == Number(EPHYSIC_GROUP.SENSOR)) return; if (b.group == Number(EPHYSIC_GROUP.ENEMY)) { this.onEnemyStartContact(b.node); return; } if (bGroup == Number(EPHYSIC_GROUP.BULLET_ENEMY)) { this.onBulletContact(b.node); return; } } onEndContact(a: Collider2D, b: Collider2D) { if (b.group == Number(EPHYSIC_GROUP.ENEMY)) { this.onEnemyEndContact(b.node); return; } } onSensorBegin(a: Collider2D, b: Collider2D) { var bGroup = b.group; // UmLog.log("HERO | onSensor Begin = " + GameDefine.getPhysicGroupName(a.group), " vs ", GameDefine.getPhysicGroupName(b.group)); if (bGroup != EPHYSIC_GROUP.ENEMY) return; this.addEnemyTarget(b.node); } onSensorEnd(a: Collider2D, b: Collider2D) { var bGroup = b.group; // UmLog.log("HERO | onSensor End = " + GameDefine.getPhysicGroupName(a.group), " vs ", GameDefine.getPhysicGroupName(b.group)); GameDefine.getPhysicGroupName(bGroup); if (bGroup != EPHYSIC_GROUP.ENEMY) return; this.removeEnemyTarget(b.node); } protected update(dt: number): void { if (!GameGlobalData.Instance.isStatePlay()) return; if (this.isShootEnable) { var targetNode = this.findShootTarget(); this.shoot(targetNode); } this.calculateHitMeleeDamageUpdate(dt); } calculateHitMeleeDamageUpdate(dt: number) { //override } shoot(targetNode) { if (!targetNode) return; this.shooting.shooting(this.node, targetNode, this.heroData.shooting, this.specialSkill); } addEnemyTarget(enemy: Node) { UmLog.log("addEnemyTarget => ", enemy.name); this.listEnemyTarget.push(enemy); } removeEnemyTarget(enemy: Node) { UmLog.log("removeEnemyTarget => ", enemy.name); if (!this.listEnemyTarget?.length) return; let index = -1; for (var i = 0; i < this.listEnemyTarget.length; i++) { if (this.listEnemyTarget[i] && this.listEnemyTarget[i] == enemy) { index = i; break; } } if (index < 0) return; this.listEnemyTarget.splice(index, 1); } findShootTarget(): Node { // UmLog.log("FINE => ", this.listEnemyTarget.length); var min_distance = Number.MAX_VALUE; var heroPoint = this.node.worldPosition; var targetNode: Node = null; if (!this.listEnemyTarget.length) return null; for (var i = 0; i < this.listEnemyTarget.length; i++) { var point = this.listEnemyTarget[i].worldPosition; var check_distance = Vec3.distance(heroPoint, point); if (check_distance < min_distance) { min_distance = check_distance; targetNode = this.listEnemyTarget[i]; } } return targetNode; } onEnemyStartContact(enemy: Node) { this.listEnemyContact.set(enemy.name, {enemy: enemy, time: 0}); } onEnemyEndContact(enemy: Node) { this.listEnemyContact.delete(enemy.name); if (this.isImmuneDamage) return; } onBulletContact(bullet: Node) { var bulletComp = bullet.parent.getComponent(BulletBase); var damage = bulletComp?.damage | 0; bulletComp?.destroyNode(); this.effectColor = bulletComp.getColor(); this.onHitDamage(damage); } onHitDamage(damage: number) { if (this.isImmuneDamage || !damage) return; this.runHitEffect(); var hpBar = LayoutManager.instance.GameUI.getHeroHPBar(); hpBar?.decreaseHP(damage); if (hpBar?.currentHP <= 0) { this?.destroyNode(); LayoutManager.instance.GameUI.showGameLose(); } } runHitEffect() { this.theme.color = this.effectColor; UmUtil.stopAllTweenTag(this.TWEEN_TAG); UmUtil.delay(this.node, 0.2, () => { this.theme.color = this.currentColor; }, this.TWEEN_TAG); } setEnableRigibody(isEnable: boolean) { if (this.rigibodyComponent) this.rigibodyComponent.enabled = isEnable; } public destroyNode() { if (this.isDestroying) return; this.isDestroying = true; //must destroy on thread this.scheduleOnce(() => { this.setEnableRigibody(false); this.node?.destroy(); }, 0); } onStartUseActiveSkill(tag: number, manaUsed: number) { UmLog.log("HERO => onStartUseActiveSkill"); this.countImmuneDamageUsing += (tag != Number(EACTIVE_SKILL_TYPE.SKILL_2)) ? 1 : 0; this.shooting?.enableActiveSkill(tag, this.node); } onEndUseActiveSkill(tag: number, manaUsed: number) { UmLog.log("HERO => onEndUseActiveSkill"); this.countImmuneDamageUsing -= (tag != Number(EACTIVE_SKILL_TYPE.SKILL_2)) ? 1 : 0; this.countImmuneDamageUsing = Math.max(0, this.countImmuneDamageUsing); } }