import { CCInteger, Collider2D, Component, Contact2DType, find, instantiate, Label, Node, Prefab, sp, tween, UITransform, v3, view, _decorator } from 'cc'; import { BaseLayer } from '../../common/BaseLayer'; import { cocosUtil } from '../../utils/cocosUtil'; import { constants } from '../data/constants'; import { msgac } from '../data/msgac'; import { audioManager } from '../manager/audioManager'; import { designManager } from '../manager/designManager'; import { eventManager } from '../manager/eventManager'; import { iconManager } from '../manager/iconManager'; import { levelManager } from '../manager/levelManager'; import { resManager } from '../manager/resManager'; import { playerModel } from '../model/playerModel'; const { ccclass, property } = _decorator; @ccclass('RoleItem') export class RoleItem extends Component { @property({ tooltip: "是否是BOSS" }) isBoss = false; @property({ type: CCInteger, tooltip: "打败怪物后掉落的宝箱金币数量或者宝箱金币数量" }) coin = 0; @property({ type: CCInteger, tooltip: "类型 -1:玩家 0:怪物 1:金币宝箱 2:商店 3:弓箭 4:战力倍增 5:装备 6:技能 7:大炮 8:滚石" }) roleType = 0; @property({ type: CCInteger, tooltip: "类型参数1" + "\n-1|0) 角色id" + "\n2) 0:装备商店 1:技能商店" + "\n3) 0:向右射箭 1:向左射箭" + "\n4) 0:加法 1:乘法" + "\n5) 1:武器 2:衣服" + "\n6) 技能id" + "\n7) 0:向右发射 1:向左发射" + "\n8) 0:向右滚动 1:向左滚动" }) roleTypeP1 = 0; @property({ type: CCInteger, tooltip: "类型参数2" + "\n2) 商店id" + "\n5) 装备等级" }) roleTypeP2 = 0; // 关卡主视图组件 levelLayer: BaseLayer; // 战力相关数值 atk: number = 0; valLabel: Label; // 所在层数 floor: number = 0; // 地板节点 groundNode: Node; // 战力变化特效支持 atkChangeInfo: any; atkNode: Node; atkBgNode: Node; bodyNode: Node; bodySkeleton: sp.Skeleton; // 弓箭节点 arrowsNode: Node; // 炮弹节点 bulletsNode: Node; // 机关是否已触发了 hasEffect: boolean = false; // 怪物是否已阵亡 dead: boolean = false; // 视频图标 adNode: Node; start() { if (this.roleType == constants.roleItemTypes.arrow) { this.arrowsNode = find("arrows", this.node); this.arrowsNode.active = false; let collider = this.arrowsNode.getComponent(Collider2D); collider.on(Contact2DType.BEGIN_CONTACT, this.onBeginContact, this); } else if (this.roleType == constants.roleItemTypes.dapao) { this.bulletsNode = find("bullets", this.node); this.bulletsNode.active = false; let collider = this.bulletsNode.getComponent(Collider2D); collider.on(Contact2DType.BEGIN_CONTACT, this.onBeginContact, this); } else if (this.roleType == constants.roleItemTypes.gunshi) { let collider = this.node.getComponent(Collider2D); collider.on(Contact2DType.BEGIN_CONTACT, this.onBeginContact, this); let bodyNode = find("body", this.node); let bodyPos = bodyNode.getPosition(); bodyPos.x = -15; if (this.roleTypeP1 == constants.arrowTypes.left) { bodyPos.x = 15; } this.bodyNode.position = bodyPos; } } init(groundNode: Node, floor: number, levelLayer: BaseLayer) { // 地板节点 this.groundNode = groundNode; // 所在层数 this.floor = floor; // 关卡主视图组件 this.levelLayer = levelLayer; let bodyNode = find("body", this.node); this.bodyNode = bodyNode; if (bodyNode) { this.bodySkeleton = bodyNode.getComponent(sp.Skeleton); } this.node["isBoss"] = this.isBoss; this.adNode = find("ad", this.node); // 战力 let atkNode = find("atk", this.node); if (atkNode) { this.valLabel = find("val", atkNode).getComponent(Label); let val = this.valLabel.string; if (val) { // 移除符号 val = val.replace(/-|x|\+|X/g, ""); this.atk = parseInt(val); } this.atkNode = atkNode; this.atkBgNode = find("bg", atkNode); } if (this.roleType == constants.roleItemTypes.equip) { // 装备图标替换 let row = designManager.instance.getRowById(constants.tableName.equip, this.getEquipId()); iconManager.instance.setSprite(bodyNode, row.icon); let bgNode = find("bg", this.node); bgNode.setPosition(0, bodyNode.getComponent(UITransform).height * 0.5); if (this.roleTypeP1 == constants.equipTypes.dress && this.roleTypeP2 == 1) { bodyNode.setScale(0.8, 0.8); } this.atkNode.setPosition(0, bodyNode.getComponent(UITransform).height + 20); // 上下动画 cocosUtil.tweenUpDown(bodyNode); cocosUtil.tweenRotate(bgNode, 4); if (this.adNode && this.adNode.active) { cocosUtil.tweenUpDown(this.adNode); } } if (this.roleType == constants.roleItemTypes.atk) { if (this.roleTypeP1 == constants.atkChangeTypes.add) { this.playAnimation("a", true); } else if (this.roleTypeP1 == constants.atkChangeTypes.multi) { this.playAnimation("b", true); } } else if (this.roleType == constants.roleItemTypes.coinBox) { if (this.isBoss) { this.playAnimation(constants.animations.standBy2, true); } else { this.playAnimation(constants.animations.standBy1, true); } } else { this.playAnimation(constants.animations.standBy, true); } if (this.roleType == constants.roleItemTypes.skill) { // 技能图标替换 let row = designManager.instance.getRowById(constants.tableName.skill, this.roleTypeP1); iconManager.instance.setSprite(bodyNode, row.icon); } levelLayer.addButtonListener(this.node); } onBeginContact(selfCollider: Collider2D, otherCollider: Collider2D) { let roleItem = null; if (selfCollider.node.name == "arrows" && otherCollider.node.name != "arrows") { roleItem = otherCollider.node.getComponent(RoleItem); } if (selfCollider.node.name == "bullets" && otherCollider.node.name != "bullets") { roleItem = otherCollider.node.getComponent(RoleItem); } if (selfCollider.node.name == "role_gunshi" && otherCollider.node.name != "role_gunshi") { roleItem = otherCollider.node.getComponent(RoleItem); } if (!roleItem || roleItem.roleType != constants.roleItemTypes.monster) { return; } roleItem.playAnimation(constants.animations.hit, false, () => { roleItem.playAnimation(constants.animations.standBy, true); }); roleItem.addAtk(-this.atk); } hasAd() { if (this.adNode && this.adNode.active) { return true; } return false; } hideAd() { if (this.adNode) { this.adNode.active = false; } } getEquipId() { let type = this.roleTypeP1; let lv = this.roleTypeP2; let roleId = playerModel.instance.getRoleId(); let id = type * 1000 + roleId * 10 + lv; return id; } setBodyScale(scaleX: number, scaleY: number) { this.bodyNode.setScale(scaleX, scaleY); } playAnimation(name: string, isLoop?: boolean, cbComplete?: Function, cbEnd?: Function) { if (this.isDead() && name != constants.animations.die) { // 已阵亡 return; } if (!this.bodySkeleton) { if (cbComplete) { cbComplete(); } return; } if (!isLoop) { isLoop = false; } if (name == constants.animations.hit) { let obj: any = {}; obj.pos = cocosUtil.convertToWorldSpace(this.node, true); eventManager.instance.send(msgac.showHitEffect, obj); } this.bodySkeleton.setAnimation(0, name, isLoop); this.bodySkeleton.setCompleteListener(() => { // 每次循环播放结束都会回调 if (cbComplete) { cbComplete(); } }); this.bodySkeleton.setEndListener(() => { // 首次播放结束才会回调 if (cbEnd) { cbEnd(); } }); audioManager.instance.onRolePlayAnimation(this, this.roleType, this.roleTypeP1, name); } // 玩家缩进传送门 startOpenPortal(cb?: Function) { tween(this.bodyNode).to(0.2, { scale: v3(0, 0, 1) }).start(); this.playAnimationPortal("1", cb); } // 玩家从传送门中跳出来 playerAppearFromPortal(cb?: Function) { this.playAnimationPortal("2"); this.playAnimation(constants.animations.chuansong, false, () => { if (cb) { cb(); } }); } playAnimationPortal(name: string, cb?: Function) { let portalNode = find("effect/portal", this.node); if (!portalNode) { if (cb) { cb(); } return; } portalNode.active = true; let height = this.bodyNode.getComponent(UITransform).height; let s = 0.1; if (name == "2") { s = 0.7; } let pos = portalNode.getPosition(); pos.y = height * s; portalNode.setPosition(pos); let portalSkeleton = portalNode.getComponent(sp.Skeleton); portalSkeleton.timeScale = 1.8; portalSkeleton.setAnimation(0, name, false); portalSkeleton.setCompleteListener(() => { if (cb) { cb(); } }); } // 金币宝箱掉落 createCoinBox(cb?: Function, obj?: any) { if (this.coin <= 0) { if (cb) { cb(); } return; } let bundle = constants.bundles.common; resManager.instance.loadAsset(bundle.name, bundle.roleBox, Prefab, () => { }, (err, prefab) => { let boxNode = instantiate(prefab); let parentNode = this.node.parent; let position = this.node.position; if (obj && obj.parentNode) { parentNode = obj.parentNode; } boxNode.parent = parentNode; if (obj && obj.worldPos) { position = cocosUtil.convertToNodeSpace(boxNode, obj.worldPos); } boxNode.position = position; let boxRoleItem = boxNode.getComponent(RoleItem); boxRoleItem.roleType = constants.roleItemTypes.coinBox; boxRoleItem.coin = this.coin; boxRoleItem.isBoss = this.isBoss; boxRoleItem.init(this.groundNode, this.floor, this.levelLayer); if (this.isBoss) { // 加个小手点击引导 cocosUtil.addHand(boxNode, boxNode, (handNode) => { boxRoleItem["handNode"] = handNode; // 根据实际情况再进行微调 let pos = handNode.getPosition(); pos.x += 55; pos.y -= 40; handNode.setPosition(pos); if (levelManager.instance.isSkip) { levelManager.instance.onClickRoleItem(boxRoleItem.node); } }); } if (cb) { cb(); } }); } // 获得玩家应该站立的世界坐标 getPlayerWorldPos(playerNode?: Node) { let pos = cocosUtil.convertToWorldSpace(this.node); let transform = this.node.getComponent(UITransform); // 额外增加的间距 let dx = 0; // 消除玩家不同角色立绘宽度差异 let dp = 0; // if (playerNode) { // let playerTf = playerNode.getComponent(UITransform); // dp = playerTf.width * (1 - playerTf.anchorX); // } if (this.isBodyScalePositive()) { pos.x -= (transform.width * transform.anchorX + dx + dp); } else { pos.x += (transform.width * transform.anchorX + dx + dp); } let posY = cocosUtil.convertToWorldSpace(this.groundNode).y; return v3(pos.x, posY, 0); } // 获得立绘是否按照图片正常显示,没有翻转 isBodyScalePositive() { let scale = this.bodyNode.getScale(); if (scale.x > 0) { return true; } return false; } // 增加战力,val如果为负数,就是减少战力 addAtk(val: number) { if (this.roleType != constants.roleItemTypes.player && this.roleType != constants.roleItemTypes.monster) { return; } if (this.atkChangeInfo) { // 上次还未完成的,直接刷新,并且丢弃掉,以最新的一个计数为准 this.setAtkVal(this.atk); if (this.atk <= 0) { this.showDeadEffect(); return; } } audioManager.instance.playEffect(constants.audioNames.figure); this.atkChangeInfo = {}; this.atkChangeInfo.atkStart = this.atk; // 先加上去,避免快速点击计算错误 this.atk += val; if (this.atk < 0) { this.atk = 0; } this.atkChangeInfo.change = 1; if (val < 0) { val = -val; this.atkChangeInfo.change = -1; } let dVal = 1; let duration = constants.atkChangeTimeGap * val; while (duration > constants.atkChangeTimeMax) { dVal++; duration = constants.atkChangeTimeGap * Math.ceil(val / dVal); } this.atkChangeInfo.change *= dVal; this.atkChangeInfo.val = val; this.atkChangeInfo.count = 0; } closeHand() { if (this["handNode"]) { this["handNode"].destroy(); delete this["handNode"]; } } openBoxAward(cb: Function) { if (this.isBoss) { this.playAnimation(constants.animations.open2, false, cb); } else { this.playAnimation(constants.animations.open1, false, cb); } } showDeadEffect(cb?: Function, obj?: any) { this.dead = true; this.playAnimation(constants.animations.die, false, () => { if (cb) { cb(); } this.createCoinBox(() => { if (!this.isPlayer()) { // 移除敌人 this.node.destroy(); // 判断一下如果敌人全部阵亡,则弹出狩猎成功的界面 eventManager.instance.send(msgac.judgeLevelSuccess); } }, obj); }); } isPlayer() { return this.roleType == constants.roleItemTypes.player; } setAtkVal(val?: number) { if (val == undefined) { val = this.atk; } this.valLabel.string = "" + val; if (this.isPlayer()) { let tf = this.atkBgNode.getComponent(UITransform); if (val >= 1000) { this.atkNode.setPosition(0, 240); tf.width = 120; tf.height = 120; } else if (val >= 100) { this.atkNode.setPosition(0, 230); tf.width = 90; tf.height = 90; } else { this.atkNode.setPosition(0, 220); tf.width = 70; tf.height = 70; } } } isDead(): boolean { if (this.roleType != constants.roleItemTypes.player && this.roleType != constants.roleItemTypes.monster) { return false; } if (this.dead || this.atk <= 0) { return true; } return false; } startGunShi(cb?: Function) { if (this.hasEffect) { return; } this.hasEffect = true; let posX = this.groundNode.getComponent(UITransform).width * 0.5; let toPos = this.node.getPosition(); toPos.x = posX; if (this.roleTypeP1 == constants.arrowTypes.left) { toPos.x = -posX; } tween(this.node).to(1.25, { position: toPos }).call(() => { this.node.destroy(); if (cb) { cb(); } }).start(); } /** * 发射大炮 */ shootBullets(cb?: Function) { if (this.hasEffect) { return; } this.hasEffect = true; this.bulletsNode.active = false; this.scheduleOnce(() => { this.bulletsNode.active = true; let pos = this.bulletsNode.getPosition(); let toPos = v3(view.getVisibleSize().width, 0, 0); if (this.roleTypeP1 == constants.arrowTypes.left) { toPos = v3(-view.getVisibleSize().width, 0, 0); pos.x = -190; } else { pos.x = 190; } this.bulletsNode.setPosition(pos); tween(this.bulletsNode).by(0.8, { position: toPos }).call(() => { this.node.destroy(); if (cb) { cb(); } }).start(); }, 0.5); } /** * 射出弓箭 */ shootArrows(cb?: Function) { if (this.hasEffect) { return; } this.hasEffect = true; let arrowNode = find("arrows", this.node); arrowNode.active = false; this.scheduleOnce(() => { arrowNode.active = true; let pos = arrowNode.getPosition(); pos.x += 50; arrowNode.setPosition(pos); let toPos = v3(view.getVisibleSize().width, 0, 0); if (this.roleTypeP1 == constants.arrowTypes.left) { toPos = v3(-view.getVisibleSize().width, 0, 0); } tween(this.arrowsNode).by(0.4, { position: toPos }).call(() => { this.node.destroy(); if (cb) { cb(); } }).start(); }, 0.5); } update(dt: number) { let info = this.atkChangeInfo; if (info) { info.count += dt; if (info.count >= constants.atkChangeTimeGap) { info.count -= constants.atkChangeTimeGap; let changeVal = info.change; if (changeVal > info.val) { changeVal = info.val; } info.atkStart += changeVal; this.setAtkVal(info.atkStart); info.val -= Math.abs(changeVal); if (info.val <= 0) { this.atkChangeInfo = null; this.setAtkVal(this.atk); } if (info.atkStart <= 0) { this.atkChangeInfo = null; // 阵亡 this.showDeadEffect(); } } } } }