/** * 代码描述 */ import { Audio } from "../../common/src/Audio"; import { GameDataCenter } from "../../common/src/GameDataCenter"; import { LevelConfig } from "../../common/src/LevelConfig"; import { UIManager } from "../../common/src/UIManager"; import { Utils } from "../../common/src/Utils"; const { ccclass, property } = cc._decorator; @ccclass export class BobbleGamePanel extends cc.Component { @property({ type: cc.Node, tooltip: '反弹界面节点' }) walls: cc.Node = null; @property({ type: cc.Graphics, tooltip: '射线节点' }) ray: cc.Graphics = null; @property({ type: cc.Node, tooltip: '地图节点' }) map: cc.Node = null; @property({ type: cc.Node, tooltip: '角色节点' }) player: cc.Node = null; @property({ type: cc.Node, tooltip: 'ui节点' }) ui: cc.Node = null; @property({ type: cc.Prefab, tooltip: '泡泡预制体' }) bubble: cc.Prefab = null; @property({ type: cc.Prefab, tooltip: '射线预制体' }) rayPrefab: cc.Prefab = null; @property({ type: cc.Prefab, tooltip: '激励预制体' }) appraisePrefab: cc.Prefab = null; @property({ type: cc.Prefab, tooltip: '发射小球预制体' }) shootBubblePre: cc.Prefab = null; @property({ type: cc.Prefab, tooltip: '激光预制体' }) laser_gj: cc.Prefab = null; @property({ type: cc.Prefab, tooltip: '闪电预制体' }) thunder_gj: cc.Prefab = null; @property({ type: cc.Prefab, tooltip: '总分预制体' }) scorePrefab: cc.Prefab = null; @property({ type: cc.Prefab, tooltip: '箭头预制体' }) arrows: cc.Prefab = null; @property({ type: [cc.SpriteFrame], tooltip: '普通泡泡纹理集合\n0.紫色\n1.绿色\n2.蓝色\n3.黄色\n4.红色' }) bubbleSpriteFrame: cc.SpriteFrame[] = []; @property({ type: [cc.SpriteFrame], tooltip: '特殊泡泡纹理集合\n0.炸弹\n1.激光\n2.七色\n3.闪电' }) specialBubbleSpriteFrame: cc.SpriteFrame[] = []; @property({ type: [cc.SpriteFrame], tooltip: '图标集合\n0.广告\n1.无限\n2.金币\n3.暗星\n4.亮星' }) iconSpriteFrame: cc.SpriteFrame[] = []; @property({ type: [cc.Prefab], tooltip: '特殊球待机动画预制体\n0.炸弹\n1.激光\n2.七色\n3.闪电' }) specialBubbleEffect: cc.Prefab[] = []; //线段颜色 private rayColor: cc.Color[] = [cc.color('#a600e6' as any), cc.color('#0ca600' as any), cc.color('#10c8e3' as any), cc.color('#f77916' as any), cc.color('#cd1904' as any)]; /**特殊球颜色 */ private specialColor: cc.Color[][] = [[cc.color('#fdce25' as any), cc.color('#f48118' as any), cc.color('#f48118' as any), cc.color('#fdce25' as any)], [cc.color('#f0e288' as any), cc.color('#d999d1' as any), cc.color('#92e7fc' as any)], [cc.color('#48adf7' as any), cc.color('#fdde52' as any), cc.color('#f77923' as any), cc.color('#d7008e' as any)], [cc.color('#073dd3' as any), cc.color('#ffffff' as any), cc.color('#073dd3' as any)]]; /**总分评价 */ private appraise: string[] = ['bksy', 'tbl', 'bc']; //发射坐标 private startPos: cc.Vec2 = cc.v2(); //射线节点坐标 private rayPos: cc.Vec2[] = []; private pathPos: cc.Vec2[] = []; //射线节点半径 private r: number = 0; //放大缩小方向 private op: number = 1; //是否隐藏 private isHide: boolean = true; //泡泡半径 private bubbleR: number = 30; //地图高度 private screenH: number = 0; //地图宽度 private screenW: number = 0; /** 当前发射小球 */ public shootBubble: cc.Node; /** 预发射小球 */ public preBubble: cc.Node; /** 特殊小球 */ public specialBubble: cc.Node; /**校正之后泡泡的位置 */ private bubbleIndex: cc.Vec2 = null; /**小球数量 */ private bubbleCount: number = 0; /**连击数 */ private combo: number = 0; /**是否在准备泡泡 */ private isReady: boolean = false; /**场上小球的颜色数量 */ private colorCount: number[] = [0, 0, 0, 0, 0, 0]; /**特殊球类型 */ private specialBubbleType: number = 0; /**特殊球消除位置 */ private specialBubbleIndex: cc.Vec2[] = []; /**激光终点向量 */ private laserVec: cc.Vec2 = null; /**闪电爆炸位置 */ private thunderIndex: cc.Vec2 = null; /**游戏是否结束 */ private isWin: boolean = false; /**得分 */ private score: number = 0; /**三星分数 */ private perfectScore: number = 0; /**星星数 */ private star: number = 0; /**首次出现冰球的关卡 */ private iceTips: number = 31; /**在线时间 */ private onlineTime: number = 0; /*要显示的排数*/ private showCount: number = 10; private callBack: Function = null; private isPress: boolean = false; onLoad() { Audio.playMusicByPath('game:res/snd/bgm'); cc.director.getPhysicsManager().enabled = true; } onEnable() { this.scheduleOnce(() => { this.init(); }, 0.5); let specialBubble = this.ui.getChildByName('specialBubble'); for (let i = 0; i < specialBubble.childrenCount; i++) { specialBubble.children[i].on('click', this.onSpecialBubble, this); } this.player.getChildByName('icon').on('click', this.onSwitchBubble, this) this.ui.getChildByName('cancel').on('click', this.onCancel, this); this.ui.getChildByName('topPanel').getChildByName('pauseButton').on('click', this.onPause, this); this.ui.getChildByName('topPanel').getChildByName('coin').getChildByName('addButton').on('click', this.onCoinStore, this); this.ui.getChildByName('online').on('click', this.onOnline, this); this.ui.getChildByName('ten').on('click', () => { cc.systemEvent.emit('updateBubble', 10); }, this); cc.systemEvent.on('restart', this.onRestart, this); cc.systemEvent.on('updateBubble', this.onUpdateBubble, this); cc.systemEvent.on('updateUI', this.onUpdateUI, this); cc.systemEvent.on('startTimer', this.onStartTimer, this); cc.systemEvent.on('showTenButton', (isShow: boolean) => { this.ui.getChildByName('ten').active = isShow }, this); this.node.on(cc.Node.EventType.TOUCH_START, this.onTouchStart, this); this.node.on(cc.Node.EventType.TOUCH_MOVE, this.onTouchMoved, this); this.node.on(cc.Node.EventType.TOUCH_END, this.onTouchEnded, this); this.node.on(cc.Node.EventType.TOUCH_CANCEL, this.onTouchCancelled, this); } onDisable() { this.node.off(cc.Node.EventType.TOUCH_START, this.onTouchStart, this); this.node.off(cc.Node.EventType.TOUCH_MOVE, this.onTouchMoved, this); this.node.off(cc.Node.EventType.TOUCH_END, this.onTouchEnded, this); this.node.off(cc.Node.EventType.TOUCH_CANCEL, this.onTouchCancelled, this); } /**点击特殊球 */ private onSpecialBubble(button): void { if (GameDataCenter.gameLevel == 12) { this.ui.getChildByName('colorTip').active = false; GameDataCenter.tipType = 2; UIManager.open('tip:TipPanel'); } if (!this.isReady || this.isWin) return; this.isPress = true; Audio.playSoundByPath('game:res/snd/click'); if (button.node.getChildByName('null').active == true && GameDataCenter.coin < 100) { switch (button.node.name) { case 'bombBubble': this.specialBubbleCallback(1); break; case 'laserBubble': this.specialBubbleCallback(2); break; case 'omnipotentBubble': this.specialBubbleCallback(3); break; case 'lightningBubble': this.specialBubbleCallback(4); break; } return; } switch (button.node.name) { case 'bombBubble': this.specialBubbleType = 1; break; case 'laserBubble': this.specialBubbleType = 2; break; case 'omnipotentBubble': this.specialBubbleType = 3; break; case 'lightningBubble': this.specialBubbleType = 4; break; } this.player.getChildByName('icon').active = false; let specialBubble = this.ui.getChildByName('specialBubble'); for (let i = 0; i < specialBubble.childrenCount; i++) { specialBubble.children[i].getComponent(cc.Button).interactable = false; } this.switchSpecialBubble(1); } /**点击取消 */ private onCancel(): void { Audio.playSoundByPath('game:res/snd/click'); this.specialBubbleType = 0; this.switchSpecialBubble(-1); this.isPress = false; } /**暂停界面 */ private onPause(): void { Audio.playSoundByPath('game:res/snd/click'); UIManager.open('pause:PausePanel'); } /**金币商店 */ private onCoinStore(): void { Audio.playSoundByPath('game:res/snd/click'); UIManager.open('coinStore:CoinStorePanel'); } /**点击切换小球 */ private onSwitchBubble(button): void { if (!this.isReady || this.isWin) return; Audio.playSoundByPath('game:res/snd/click'); this.isReady = false; button.node.getComponent(cc.Button).interactable = false; if (button.node.children[0].name == '0') { this.callBack = () => { button.node.children[0].getComponent(cc.Sprite).spriteFrame = this.iconSpriteFrame[1]; button.node.children[0].name = '1'; let pos = this.player.convertToNodeSpaceAR(this.startPos); cc.tween(this.shootBubble).to(0.2, { position: cc.v3(pos.x + 60, pos.y - 60), scale: 0.75 }).start(); cc.tween(this.preBubble).to(0.2, { position: cc.v3(pos.x, pos.y), scale: 1 }).call(() => { let node: cc.Node = null; node = this.shootBubble; this.shootBubble = this.preBubble; this.preBubble = node; this.scheduleOnce(() => { this.isReady = true; }, 0); this.ray.fillColor = this.rayColor[this.shootBubble.getComponent('Bubble').color - 1]; button.node.getComponent(cc.Button).interactable = true; }).start(); } this.scheduleOnce(() => { button.node.getComponent(cc.Button).interactable = true; this.isReady = true; this.callBack(); }, 1); return; } let pos = this.player.convertToNodeSpaceAR(this.startPos); cc.tween(this.shootBubble).to(0.2, { position: cc.v3(pos.x + 60, pos.y - 60), scale: 0.75 }).start(); cc.tween(this.preBubble).to(0.2, { position: cc.v3(pos.x, pos.y), scale: 1 }).call(() => { let node: cc.Node = null; node = this.shootBubble; this.shootBubble = this.preBubble; this.preBubble = node; this.scheduleOnce(() => { this.isReady = true; }, 0); this.ray.fillColor = this.rayColor[this.shootBubble.getComponent('Bubble').color - 1]; button.node.getComponent(cc.Button).interactable = true; }).start(); } /**在线奖励面板 */ private onOnline(): void { Audio.playSoundByPath('game:res/snd/click'); if (this.onlineTime > 0) { this.creatLabel(`再多玩一会吧,在线时间还不够哦~`); return; } else { GameDataCenter.rewarded = [`${Math.floor(Math.random() * 4)}:1`, '4:80']; UIManager.open('rewarded:RewardedPanel'); cc.systemEvent.emit('startTimer'); } } /**再来一次 */ private onRestart(): void { this.isReady = false; this.initMap(true); } /**更新泡泡数量 */ private onUpdateBubble(num: number): void { this.isReady = false; let count: number = this.bubbleCount; this.bubbleCount += num; for (let i = 0; i < num; i++) { this.scheduleOnce(() => { count++; this.player.getChildByName('bubbleCount').getComponent(cc.Label).string = `${count}` }, i * 0.1); } this.scheduleOnce(() => { this.isReady = true; }, 0.5); } /**更新UI数量 */ private onUpdateUI(type: string, num: number) { this.changeUi(type, num); } /**开始在线奖励倒计时 */ private onStartTimer(): void { let node = this.ui.getChildByName('online').getChildByName('gift'); cc.Tween.stopAllByTarget(node); node.scale = 1; node.angle = 0; this.onlineTime = 120; this.ui.getChildByName('online').getChildByName('time').getComponent(cc.Label).string = '02;00'; this.ui.getChildByName('online').getChildByName('time').active = true; this.ui.getChildByName('online').getChildByName('name').getChildByName('label').getComponent(cc.Label).string = `在线奖励`; this.ui.getChildByName('online').getChildByName('name').getChildByName('label').x -= 14; this.ui.getChildByName('online').getChildByName('name').getChildByName('videoIcon').active = false; // this.ui.getChildByName('online').getComponent(cc.Button).interactable = false; this.schedule(this.online, 1); } private specialBubbleCallback(type) { this.specialBubbleType = type; this.player.getChildByName('icon').active = false; let specialBubble = this.ui.getChildByName('specialBubble'); for (let i = 0; i < specialBubble.childrenCount; i++) { specialBubble.children[i].getComponent(cc.Button).interactable = false; } this.switchSpecialBubble(1); this.changeUi(`special${this.specialBubbleType}`, 1); } /** * 场景动画更新前回调 * @param dt 游戏帧时长 */ update(dt: number) { if (!this.isHide) { this.updateRay(dt); } } /** touch事件回调 */ onTouchStart(event: cc.Event.EventTouch) { this.isPress = true; if (GameDataCenter.gameLevel == 1) { if (this.ui.getChildByName('tip').getChildByName('tip1').activeInHierarchy == true) { cc.Tween.stopAllByTarget(this.ui.getChildByName('tip').getChildByName('tip1').getChildByName('finger')); this.ui.getChildByName('tip').getChildByName('tip1').active = false; } } if (GameDataCenter.gameLevel == 2) { if (this.ui.getChildByName('tip').getChildByName('tip3').activeInHierarchy == true) { this.ui.getChildByName('tip').getChildByName('tip3').active = false; this.node.getChildByName('effect').removeAllChildren(); } } // if (GameDataCenter.gameLevel == 11) { // if (this.ui.getChildByName('tip').getChildByName('tip4').activeInHierarchy == true) { // this.ui.getChildByName('tip').getChildByName('tip4').active = false; // } // } if (!this.isReadyRay(event)) { return; } this.topTween(0); this.rayPos = []; this.pathPos = [this.ray.node.convertToNodeSpaceAR(this.startPos)]; const pos = event.getLocation(); this.drawRayCast(this.startPos, pos.subSelf(this.startPos).normalizeSelf(), this.ray); } onTouchMoved(event: cc.Event.EventTouch) { if (!this.isReadyRay(event)) { return; } this.topTween(0); this.rayPos = []; this.pathPos = [this.ray.node.convertToNodeSpaceAR(this.startPos)]; const pos = event.getLocation(); this.drawRayCast(this.startPos, pos.subSelf(this.startPos).normalizeSelf(), this.ray); } onTouchEnded(event: cc.Event.EventTouch) { this.isPress = false; if (this.isHide) { return; } this.topTween(1); this.ray.clear(); for (let i = 0; i < this.ray.node.childrenCount; i++) { this.ray.node.children[i].getComponent(cc.Graphics).clear(); } this.isReady = false; this.laserVec = event.getLocation(); this.shootBubble.getChildByName('trailing_normal').active = true; switch (this.specialBubbleType) { case 0: Audio.playSoundByPath('game:res/snd/shoot'); break; case 1: Audio.playSoundByPath('game:res/snd/bomb'); break; case 2: Audio.playSoundByPath('game:res/snd/laser'); break; case 3: Audio.playSoundByPath('game:res/snd/omnipotent'); break; case 4: Audio.playSoundByPath('game:res/snd/lightning'); break; } this.ui.getChildByName('cancel').active = false; this.bubbleMove(1); this.isHide = true; } onTouchCancelled(event: cc.Event.EventTouch) { this.isPress = false; this.ray.clear(); for (let i = 0; i < this.ray.node.childrenCount; i++) { this.ray.node.children[i].getComponent(cc.Graphics).clear(); } this.isHide = true; } /**初始化 */ private init(): void { if (!GameDataCenter.isInitSpecial) { GameDataCenter.isInitSpecial = true; cc.systemEvent.emit('updateUI', 'special1', 1); cc.systemEvent.emit('updateUI', 'special2', 1); cc.systemEvent.emit('updateUI', 'special3', 1); cc.systemEvent.emit('updateUI', 'special4', 1); } if (GameDataCenter.gameLevel >= 8) { //签到 if (!GameDataCenter.isSignIn) { this.scheduleOnce(() => { UIManager.open('attendance:AttendancePanel'); }, 0.1) } } //初始化ui this.onStartTimer(); this.changeUi('coin'); this.changeUi('special0'); this.changeUi('ingot'); //初始化初始发射点 this.startPos = this.node.convertToWorldSpaceAR(cc.v2(this.player.position.x, this.player.position.y)); //初始化泡泡半径 this.bubbleR = Math.floor(this.node.getContentSize().width / 11 / 2); //初始化地图宽度 this.screenW = this.node.getContentSize().width; //设置地图大小 // this.map.setContentSize(this.screenW, this.node.getContentSize().height * 3 / 7); //初始化地图高度 this.screenH = this.map.getContentSize().height; //初始化地图 this.scheduleOnce(() => { this.createShootBubble(true); this.createShootBubble(); this.initMap(true); }, 0.5); } /**初始化地图 */ private initMap(isInit: boolean = false): void { this.ui.getChildByName('ten').active = false; GameDataCenter.bubbles = []; this.map.removeAllChildren(); //初始化广告图片 let icon = this.player.getChildByName('icon'); icon.zIndex = 100; icon.children[0].getComponent(cc.Sprite).spriteFrame = this.iconSpriteFrame[0]; icon.children[0].name = '0'; this.colorCount = [0, 0, 0, 0, 0, 0]; this.specialBubbleType = 0; this.combo = 0; this.star = 0; this.isWin = false; this.ui.getChildByName('topPanel').getChildByName('score').getChildByName('levelLabel').getComponent(cc.Label).string = `第${GameDataCenter.gameLevel}关` this.map.position = cc.v3(0, -this.node.getContentSize().height); this.walls.getChildByName('top').position = this.walls.convertToNodeSpaceAR(this.map.convertToWorldSpaceAR(cc.v3(this.map.position.x, this.map.getContentSize().height + this.walls.getChildByName('top').getContentSize().height / 2))); let length = Object.keys(LevelConfig.level).length; let gameLevel = LevelConfig.level[GameDataCenter.gameLevel > length ? Math.floor(Math.random() * length) + 1 : GameDataCenter.gameLevel] let bubbleCount = this.bubbleCount; let count = 0; this.bubbleCount = isInit ? gameLevel.bubbleCount : gameLevel.bubbleCount + 1; for (let i = 0; i < Math.max(gameLevel.bubbleCount - bubbleCount, 0); i++) { this.scheduleOnce(() => { bubbleCount++; this.player.getChildByName('bubbleCount').getComponent(cc.Label).string = `${bubbleCount}` }, i * 0.05); } let data = gameLevel.map; let time: number = 0; for (let i = 0; i < data.length; i++) { GameDataCenter.bubbles[i] = []; for (let j = 0; j < data[i].length; j++) { let type = data[i][j]; if (type == 0) continue; this.scheduleOnce(() => { this.creatBubble(i, j, type); count++; }, time * 0.01); time = (time++) / 5; } } this.scheduleOnce(() => { this.changeUi('score', 0); this.perfectScore = count * 40; GameDataCenter.bubbles[data.length] = []; let t = ((1.5 * this.node.getContentSize().height - 210) / (this.bubbleR * Math.sqrt(3))) + Math.max(GameDataCenter.bubbles.length - 10, 0) this.setMapPosition(t); this.scheduleOnce(() => { if (GameDataCenter.gameLevel == 2) { this.ui.getChildByName('tip').getChildByName('tip3').active = true; Utils.openPanel(this.ui.getChildByName('tip').getChildByName('tip3')); this.rayPos = []; this.drawRayCast(this.startPos, cc.v2(this.startPos.x - 100, this.startPos.y + 140).subSelf(this.startPos).normalizeSelf(), this.ray); let rayPos = this.rayPos; for (let i = 0; i < rayPos.length - 2; i++) { let node = cc.instantiate(this.arrows); let angle = this.vectorsToDegree(rayPos[i], rayPos[i + 1]); if (angle != this.vectorsToDegree(rayPos[i + 1], rayPos[i + 2])) { cc.tween(node) .to(0.5, { opacity: 0 }) .call(() => { node.opacity = 255; }) .union() .repeatForever() .start(); } if (i == rayPos.length - 3) { cc.tween(node) .to(0.5, { opacity: 0 }) .call(() => { node.opacity = 255; }) .union() .repeatForever() .start(); } node.parent = this.node.getChildByName('effect'); node.position = cc.v3(rayPos[i].x, rayPos[i].y); node.angle += angle; cc.tween(node) .to(0.5, { position: cc.v3(rayPos[i + 1].x, rayPos[i + 1].y) }) .call(() => { node.position = cc.v3(rayPos[i].x, rayPos[i].y); }) .union() .repeatForever() .start(); } } this.switchShootBubble(); }, 0.03 * t + 0.1); if (GameDataCenter.gameLevel == 1) { this.ui.getChildByName('tip').getChildByName('tip1').active = true; cc.tween(this.ui.getChildByName('tip').getChildByName('tip1').getChildByName('finger')) .by(0.3, { x: -100 }) .by(0.6, { x: 200 }) .by(0.3, { x: -100 }) .union() .repeatForever() .start(); } if (GameDataCenter.gameLevel >= 3) { this.ui.getChildByName('specialBubble').active = true; } if (GameDataCenter.gameLevel >= 8) { //签到 if (!GameDataCenter.isSignIn && GameDataCenter.gameLevel < 16) { this.scheduleOnce(() => { UIManager.open('attendance:AttendancePanel'); }, 0.1); } } // if (GameDataCenter.gameLevel == 11) { // this.ui.getChildByName('tip').getChildByName('tip4').active = true; // } if (GameDataCenter.gameLevel == 12) { this.ui.getChildByName('colorTip').active = true; cc.systemEvent.emit('updateUI', `special3`, 1); } if (GameDataCenter.gameLevel == 13) { if (this.onlineTime == 0) { this.onOnline(); } } if (GameDataCenter.gameLevel == this.iceTips || GameDataCenter.gameLevel == 11) { GameDataCenter.tipType = 2; UIManager.open('tip:TipPanel'); } }, time * 0.01 + 1); } /**判断射线出现 */ private isReadyRay(event): boolean { let pos = this.player.parent.convertToNodeSpaceAR(event.getLocation()); if (pos.y < Math.tan(cc.misc.degreesToRadians(20)) * (Math.abs(pos.x)) + this.player.position.y || !this.isReady) { this.ray.clear(); this.topTween(1); for (let i = 0; i < this.ray.node.childrenCount; i++) { this.ray.node.children[i].getComponent(cc.Graphics).clear(); } this.node.getChildByName('tipRay').getComponent(cc.Graphics).clear(); this.isHide = true; return false; } this.isHide = false; return true; } /** * @description 计算射线 * @param startLocation 起始位置 世界坐标系 * @param vector_dir 单位方向向量 */ private drawRayCast(startLocation: cc.Vec2, vector_dir: cc.Vec2, graphic: cc.Graphics): void { if (this.specialBubbleType == 2) { this.specialBubbleIndex = []; const endLocation = startLocation.add(vector_dir.mul(1500)); const results = cc.director.getPhysicsManager().rayCast(startLocation, endLocation, cc.RayCastType.AllClosest); this.drawAimLine(startLocation, results[results.length - 1].point, graphic); //计算激光经过的泡泡 let result1 = cc.director.getPhysicsManager().rayCast(startLocation.sub(cc.v2(this.bubbleR - 1)), endLocation.sub(cc.v2(this.bubbleR - 1)), cc.RayCastType.AllClosest); for (let i in result1) { if (result1[i].collider.node.name == 'bubble') { let hitBubble = result1[i].collider.node.parent.getComponent('Bubble'); this.specialBubbleIndex.push(cc.v2(hitBubble.i, hitBubble.j)); } } let result2 = cc.director.getPhysicsManager().rayCast(startLocation.sub(cc.v2(-this.bubbleR + 1)), endLocation.sub(cc.v2(-this.bubbleR + 1)), cc.RayCastType.AllClosest); for (let i in result2) { if (result2[i].collider.node.name == 'bubble') { let hitBubble = result2[i].collider.node.parent.getComponent('Bubble'); this.specialBubbleIndex.push(cc.v2(hitBubble.i, hitBubble.j)); } } if (result1[result1.length - 1].collider.node.name != 'bubble' && result2[result2.length - 1].collider.node.name != 'bubble') { this.node.getChildByName('tipRay').getComponent(cc.Graphics).clear(); } //加入点位 if (this.specialBubbleIndex.length > 0) { let tipRay = this.node.getChildByName('tipRay').getComponent(cc.Graphics); tipRay.clear(); this.unique(); for (let i = 0; i < this.specialBubbleIndex.length; i++) { let pos = this.convertRowColToPos(this.specialBubbleIndex[i].x, this.specialBubbleIndex[i].y); pos = this.node.convertToNodeSpaceAR(this.map.convertToWorldSpaceAR(pos)) tipRay.circle(pos.x, pos.y, this.bubbleR); } tipRay.stroke(); } } else { const endLocation = startLocation.add(vector_dir.mul(10000)); const results = cc.director.getPhysicsManager().rayCast(startLocation, endLocation, cc.RayCastType.Closest); const result = results[0]; // 指定射线与穿过的碰撞体在哪一点相交。 const point = result.point; this.drawAimLine(startLocation, point, graphic); //碰撞体 const collider = result.collider.node.name; // 画入射线段 if (collider == 'left' || collider == 'right') { // 指定碰撞体在相交点的表面的法线单位向量。 const vector_n = result.normal; const vector_r = vector_dir.sub(vector_n.mul(2 * vector_dir.dot(vector_n))); this.drawRayCast(point, vector_r, graphic); } else { let hitBubble = result.collider.node.parent; if (collider == 'bubble') { this.bubbleIndex = this.setBubble(hitBubble.getComponent('Bubble').i, hitBubble.getComponent('Bubble').j, this.map.convertToNodeSpaceAR(point)); } if (collider == 'top') { this.bubbleIndex = this.setBubble(-1, -1, this.map.convertToNodeSpaceAR(point)); } this.specialBubbleIndex = []; switch (this.specialBubbleType) { case 1: this.bombBubble(); break; case 3: this.omnipotentBubble(); break; case 4: this.lightningBubble(hitBubble, collider == 'top' ? true : false); break; } let tipRay = this.node.getChildByName('tipRay').getComponent(cc.Graphics); tipRay.clear(); // this.specialBubbleIndex.push(cc.v2(this.bubbleIndex.x, this.bubbleIndex.y)); this.unique(); for (let i = 0; i < this.specialBubbleIndex.length; i++) { let pos = this.convertRowColToPos(this.specialBubbleIndex[i].x, this.specialBubbleIndex[i].y); pos = this.node.convertToNodeSpaceAR(this.map.convertToWorldSpaceAR(pos)) tipRay.circle(pos.x, pos.y, this.bubbleR); } tipRay.stroke(); } } } /** * @description 画瞄准线 * @param startLocation 起始位置 世界坐标系 * @param endLocation 结束位置 世界坐标系 */ private drawAimLine(startLocation: cc.Vec2, endLocation: cc.Vec2, graphic: cc.Graphics): void { const graphic_startLocation = graphic.node.convertToNodeSpaceAR(startLocation); const graphic_endLocation = graphic.node.convertToNodeSpaceAR(endLocation); graphic.moveTo(graphic_startLocation.x, graphic_startLocation.y); /*画间隔圆线*/ //圆与圆之间的间隔 let delta = 60; //直线方向 const vector_dir = endLocation.sub(startLocation); //圆的数量 const total_count = Math.floor(vector_dir.mag() / delta); //每次间隔向量 vector_dir.normalizeSelf().mulSelf(delta); for (let index = 0; index < total_count; index++) { graphic_startLocation.addSelf(vector_dir); this.rayPos.push(cc.v2(graphic_startLocation.x, graphic_startLocation.y)); } this.rayPos.push(cc.v2(graphic_endLocation.x, graphic_endLocation.y)); this.pathPos.push(cc.v2(graphic_endLocation.x, graphic_endLocation.y)); } /**更新射线 */ private updateRay(dt): void { this.ray.clear(); for (let i = 0; i < this.ray.node.childrenCount; i++) { this.ray.node.children[i].getComponent(cc.Graphics).clear(); } // (0.4:min+5:max)/2 let offset: number = 10; for (let i = 0; i < this.rayPos.length; i++) { if (i % 2 == 0) { this.ray.circle(this.rayPos[i].x, this.rayPos[i].y, offset + this.r); for (let j = 0; j < this.ray.node.childrenCount; j++) { this.ray.node.children[j].getComponent(cc.Graphics).circle(this.rayPos[i].x, this.rayPos[i].y, offset + this.r - (j + 1) * 3); } } else { this.ray.circle(this.rayPos[i].x, this.rayPos[i].y, offset - this.r); for (let j = 0; j < this.ray.node.childrenCount; j++) { this.ray.node.children[j].getComponent(cc.Graphics).circle(this.rayPos[i].x, this.rayPos[i].y, offset - this.r - (j + 1) * 3); } } } this.r += this.op * 10 * dt; if (Math.abs(this.r) > 3) { this.op = -this.op; } this.ray.fill(); for (let i = 0; i < this.ray.node.childrenCount; i++) { this.ray.node.children[i].getComponent(cc.Graphics).fill(); } } /**创建小球 */ private creatBubble(i: number, j: number, color: number): void { let node = cc.instantiate(this.bubble); node.position = this.convertRowColToPos(i, j); if (this.specialBubbleType == 0) { node.getComponent(cc.Sprite).spriteFrame = this.bubbleSpriteFrame[color - 1]; } else { node.getComponent(cc.Sprite).spriteFrame = this.specialBubbleSpriteFrame[color - 1]; } node.parent = this.map; node.getComponent('Bubble').init(i, j, color); node.setContentSize(this.bubbleR * 2, this.bubbleR * 2); node.children[0].getComponent(cc.PhysicsCircleCollider).radius = this.bubbleR; node.children[0].getComponent(cc.PhysicsCircleCollider).apply(); GameDataCenter.bubbles[i][j] = node; if (color >= 1 && color <= 6) { this.colorCount[color - 1]++; } } /**创建预发射小球 */ private createShootBubble(isInit: boolean = false): void { if (!isInit) { this.shootBubble = this.preBubble; this.ray.fillColor = this.rayColor[this.shootBubble.getComponent('Bubble').color - 1]; this.bubbleCount--; if (this.bubbleCount == 0) { GameDataCenter.tipType = 0; UIManager.open('tip:TipPanel'); } if (this.bubbleCount == 3) { GameDataCenter.tipType = 3; UIManager.open('tip:TipPanel'); } if (this.bubbleCount == 10) { GameDataCenter.tipType = 1; UIManager.open('tip:TipPanel'); } } let node = cc.instantiate(this.shootBubblePre); let pos = this.player.convertToNodeSpaceAR(this.startPos); let color = this.randNum(); node.position = cc.v3(pos.x + 60, pos.y - 60); node.parent = this.player; node.getChildByName('sprite').getComponent(cc.Sprite).spriteFrame = this.bubbleSpriteFrame[color - 1]; node.setContentSize(this.bubbleR * 2, this.bubbleR * 2); node.getComponent('Bubble').color = color; node.scale = 0; this.preBubble = node; } /**发射小球切换动画 */ private switchShootBubble(): void { this.scheduleOnce(() => { this.specialBubbleType = 0; let pos = this.player.convertToNodeSpaceAR(this.startPos); if (this.colorCount[this.shootBubble.getComponent('Bubble').color - 1] == 0) { let color = this.randNum(); this.shootBubble.getComponent('Bubble').color = color; this.shootBubble.getChildByName('sprite').getComponent(cc.Sprite).spriteFrame = this.bubbleSpriteFrame[color - 1]; } cc.tween(this.shootBubble).to(0.5, { position: cc.v3(pos.x, pos.y), scale: 1 }).start(); cc.tween(this.preBubble).to(0.5, { scale: 0.75 }).start(); this.ray.fillColor = this.rayColor[this.shootBubble.getComponent('Bubble').color - 1]; this.player.getChildByName('bubbleCount').getComponent(cc.Label).string = `${this.bubbleCount}` this.scheduleOnce(() => { this.isReady = true; }, 0.5); this.player.getChildByName('icon').active = true; }, 0.1); } /**特殊球切换 */ private switchSpecialBubble(op: number): void { let specialBubble = this.ui.getChildByName('specialBubble'); for (let i = 0; i < specialBubble.childrenCount; i++) { cc.tween(specialBubble.children[i]) .by(0.5, { y: op * -200, opacity: op * -255 }) .call(() => { if (op == 1) { this.ui.getChildByName('cancel').active = true; specialBubble.children[i].getComponent(cc.Button).interactable = true; } }) .start(); } if (op == 1) { this.setspecialColor(); let node = cc.instantiate(this.shootBubblePre); let pos = this.player.convertToNodeSpaceAR(this.startPos); node.position = cc.v3(pos.x, pos.y); node.parent = this.player; node.getChildByName('sprite').getComponent(cc.Sprite).spriteFrame = this.specialBubbleSpriteFrame[this.specialBubbleType - 1]; node.setContentSize(this.bubbleR * 2, this.bubbleR * 2); node.scale = 0; let effect = cc.instantiate(this.specialBubbleEffect[this.specialBubbleType - 1]); effect.parent = node; this.specialBubble = node; cc.tween(this.specialBubble) .to(0.3, { scale: 1 }) .start(); cc.tween(this.shootBubble) .to(0.3, { scale: 0, opacity: 0 }) .call(() => { this.shootBubble.active = false; this.shootBubble.opacity = 255; this.shootBubble.scale = 0; this.shootBubble.position = cc.v3(pos.x + 60, pos.y - 60); }) .start(); cc.tween(this.preBubble) .to(0.3, { scale: 0 }) .start(); } else { this.ray.node.removeAllChildren(); this.specialBubble.destroy(); this.shootBubble.active = true; cc.tween(this.shootBubble).to(0.3, { scale: 0.75 }).start(); if (!this.isWin) { this.switchShootBubble(); } this.ui.getChildByName('cancel').active = false; } } /**小球运动 */ private bubbleMove(i): void { // let pos: cc.Vec2 = this.player.convertToNodeSpaceAR(this.ray.node.convertToWorldSpaceAR(this.rayPos[i])); // let end: cc.Vec2 = this.player.convertToNodeSpaceAR(this.ray.node.convertToWorldSpaceAR(this.rayPos[i - 1])); let pos: cc.Vec2 = this.player.convertToNodeSpaceAR(this.ray.node.convertToWorldSpaceAR(this.pathPos[i])); let end: cc.Vec2 = this.player.convertToNodeSpaceAR(this.ray.node.convertToWorldSpaceAR(this.pathPos[i - 1])); if (this.specialBubbleType == 2) { this.combo++; this.node.getChildByName('tipRay').getComponent(cc.Graphics).clear(); let node = cc.instantiate(this.laser_gj); node.parent = this.specialBubble; node.angle = this.vectorsToDegree(this.startPos, this.laserVec); for (let i in this.specialBubbleIndex) { let color = GameDataCenter.bubbles[this.specialBubbleIndex[i].x][this.specialBubbleIndex[i].y].getComponent('Bubble').color; if (color >= 1 && color <= 6) { this.colorCount[color - 1]--; } GameDataCenter.bubbles[this.specialBubbleIndex[i].x][this.specialBubbleIndex[i].y].getComponent('Bubble').playDeathAnimation(this.combo, this.specialBubbleType); this.changeUi('score', this.combo * 10); } this.isSuspension(); return; } cc.tween(this.specialBubbleType == 0 ? this.shootBubble : this.specialBubble) .to(Math.floor(pos.sub(end).mag()) / (1000 * 2), { position: cc.v3(pos.x, pos.y, 0) }) .call(() => { if (i < this.pathPos.length - 1) { this.bubbleMove(i + 1); } else { if (this.specialBubbleType == 0) { this.creatBubble(this.bubbleIndex.x, this.bubbleIndex.y, this.shootBubble.getComponent('Bubble').color); this.crashTween(this.bubbleIndex.x, this.bubbleIndex.y); this.shootBubble.destroy(); this.isElimination(); } else { this.combo++; this.node.getChildByName('tipRay').getComponent(cc.Graphics).clear(); if (this.specialBubbleType == 4) { if (!GameDataCenter.bubbles[this.thunderIndex.x][this.thunderIndex.y]) { this.creatBubble(this.thunderIndex.x, this.thunderIndex.y, this.specialBubbleType); this.specialBubbleIndex.push(cc.v2(this.thunderIndex.x, this.thunderIndex.y)); } let node = cc.instantiate(this.thunder_gj); node.parent = GameDataCenter.bubbles[this.thunderIndex.x][this.thunderIndex.y]; node.position = node.parent.convertToNodeSpaceAR(this.map.convertToWorldSpaceAR(cc.v3(0, this.convertRowColToPos(this.thunderIndex.x, this.thunderIndex.y).y))); let children = node.getChildByName('qiu') children.position = node.convertToNodeSpaceAR(this.map.convertToWorldSpaceAR(this.convertRowColToPos(this.thunderIndex.x, this.thunderIndex.y))); } else { this.creatBubble(this.bubbleIndex.x, this.bubbleIndex.y, this.specialBubbleType); this.specialBubbleIndex.push(cc.v2(this.bubbleIndex.x, this.bubbleIndex.y)); } for (let i in this.specialBubbleIndex) { let color = GameDataCenter.bubbles[this.specialBubbleIndex[i].x][this.specialBubbleIndex[i].y].getComponent('Bubble').color; if (color >= 1 && color <= 6) { this.colorCount[color - 1]--; } GameDataCenter.bubbles[this.specialBubbleIndex[i].x][this.specialBubbleIndex[i].y].getComponent('Bubble').playDeathAnimation(this.combo, this.specialBubbleType); this.changeUi('score', this.combo * 10); } this.isSuspension(); this.specialBubble.destroy(); } } }) .start(); } /**更新地图大小及位置 */ private setMapPosition(op: number = 1): void { let offset: number = this.bubbleR * Math.sqrt(3); cc.tween(this.map) .by(Math.max(0.03 * op, 0.3), { y: op * offset }) .call(() => { for (let i = 0; i < this.map.childrenCount; i++) { this.map.children[i].children[0].position = cc.v3(0, 0, 0); this.map.children[i].children[0].getComponent(cc.RigidBody).syncPosition(false); } }) .start(); cc.tween(this.walls.getChildByName('top')) .by(Math.max(0.03 * op, 0.3), { y: op * offset }) .start(); // this.schedule(() => { // this.showBubble(); // }, 0.1, Math.ceil(Math.max(0.02 * op, 0.3) / 0.1) + 1); } /**泡泡位置校正 */ private setBubble(i: number, j: number, position: cc.Vec2): cc.Vec2 { let mag: number = 99999; let index: cc.Vec2 = cc.v2(); if (i == -1 && j == -1) { index.x = 0; for (let k = 0; k < 11; k++) { if (GameDataCenter.bubbles[0][k]) { continue; } let t: cc.Vec3 = this.convertRowColToPos(0, k); let p: cc.Vec2 = cc.v2(t.x, t.y); if (p.sub(position).mag() < mag) { mag = p.sub(position).mag(); index.y = k; } } } else { this.traversal(i, j, (row: number, col: number) => { if (GameDataCenter.bubbles[row][col]) return true; let t: cc.Vec3 = this.convertRowColToPos(row, col); let p: cc.Vec2 = cc.v2(t.x, t.y); if (p.sub(position).mag() < mag) { mag = p.sub(position).mag(); index.x = row; index.y = col; } }) } return index; } /**检测泡泡是否消除 */ private isElimination(): void { // 记录消除行列值 let record: cc.Vec2[] = []; let color = this.shootBubble.getComponent('Bubble').color; GameDataCenter.bubbles[this.bubbleIndex.x][this.bubbleIndex.y].getComponent('Bubble').isVisited = true; record.push(cc.v2(this.bubbleIndex.x, this.bubbleIndex.y)); this.traversalAll(this.bubbleIndex.x, this.bubbleIndex.y, (row: number, col: number) => { // if (row < GameDataCenter.bubbles.length - this.showCount - 1) return true; let nodeData = GameDataCenter.bubbles[row][col].getComponent('Bubble'); // 如果被访问过 if (nodeData.isVisited) return true; // 如果颜色不同 if (nodeData.color !== color) return true; // 符合条件 nodeData.isVisited = true; record.push(cc.v2(row, col)); }) let count: number = 0; for (let row = 0; row < GameDataCenter.bubbles.length; row++) { for (let col = 0; col < GameDataCenter.bubbles[row].length; col++) { if (!GameDataCenter.bubbles[row][col]) continue; if (GameDataCenter.bubbles[row][col].getComponent('Bubble').isVisited) { GameDataCenter.bubbles[row][col].getComponent('Bubble').isVisited = false; count++; } } } if (count >= 3) { this.combo++; // 执行消除 for (let i in record) { this.scheduleOnce(() => { this.isIceBubble(record[i].x, record[i].y, GameDataCenter.bubbles[record[i].x][record[i].y].getComponent('Bubble').color); this.colorCount[GameDataCenter.bubbles[record[i].x][record[i].y].getComponent('Bubble').color - 1]--; GameDataCenter.bubbles[record[i].x][record[i].y].getComponent('Bubble').playDeathAnimation(this.combo); }, +i * (0.04 - record.length * 0.001)); } this.scheduleOnce(() => { this.changeUi('score', 10 * this.combo * count); // this.scheduleOnce(() => { // Audio.playSoundByPath('game:res/snd/score'); // }, 0.5); //分数激励 let node = cc.instantiate(this.scorePrefab); node.parent = this.node; let pos = this.convertRowColToPos(this.bubbleIndex.x, this.bubbleIndex.y); pos = this.node.convertToNodeSpaceAR(this.map.convertToWorldSpaceAR(pos)); node.position = cc.v3(pos.x, pos.y - 100); node.children[0].getComponent(cc.Label).string = `${count * this.combo * 10}`; node.getChildByName(this.appraise[Math.floor(Math.random() * 3)]).active = true; cc.tween(node) .by(0.5, { y: 100 }) .removeSelf() .start(); if (count > 10) { node = cc.instantiate(this.appraisePrefab); node.parent = this.node; node.scale = 0; node.children[Math.floor(Math.random() * 3)].active = true; } cc.tween(node) .to(0.2, { scale: 1 }) .delay(1) .to(0.2, { scale: 0 }) .removeSelf() .start(); this.isSuspension(); }, record.length * (0.04 - record.length * 0.001)); } else { this.combo = 0; //数组变化及地图移动 if (this.bubbleIndex.x >= GameDataCenter.bubbles.length - 1) { GameDataCenter.bubbles[GameDataCenter.bubbles.length] = [] if (GameDataCenter.bubbles.length > 10) { this.setMapPosition(); } } //创建下一个小球 this.scheduleOnce(() => { this.createShootBubble(); this.switchShootBubble(); }, 0); } } /**悬空检测 */ private isSuspension(): void { this.scheduleOnce(() => { for (let i = 0; i < GameDataCenter.bubbles[0].length; i++) { // 执行最上的一排泡泡 if (!GameDataCenter.bubbles[0][i]) continue; this.traversalAll(0, i, (row: number, col: number) => { let nodeData = GameDataCenter.bubbles[row][col].getComponent('Bubble'); if (nodeData.isVisited) return true; // 符合条件 nodeData.isVisited = true; nodeData.isLinked = true; }, true); } let count: number = 0; for (let row = 0; row < GameDataCenter.bubbles.length; row++) { for (let col = 0; col < GameDataCenter.bubbles[row].length; col++) { if (!GameDataCenter.bubbles[row][col]) continue; if (!GameDataCenter.bubbles[row][col].getComponent('Bubble').isLinked) { this.scheduleOnce(() => { let color = GameDataCenter.bubbles[row][col].getComponent('Bubble').color; if (color >= 1 && color <= 6) { this.colorCount[color - 1]--; } GameDataCenter.bubbles[row][col].getComponent('Bubble').playDownAnimation(this.combo * 2, this.map.convertToNodeSpaceAR(this.startPos)); }, count * 0.02); count++; } else { GameDataCenter.bubbles[row][col].getComponent('Bubble').isVisited = false; GameDataCenter.bubbles[row][col].getComponent('Bubble').isLinked = false; } } } this.scheduleOnce(() => { if (count > 0) { this.changeUi('score', 10 * this.combo * count * 2); } this.removeEmpty(); }, count * 0.02 + count > 0 ? 1.5 : 0); }, 0); } /**冰球检测*/ private isIceBubble(i: number, j: number, color: number): void { this.traversal(i, j, (row: number, col: number) => { if (!GameDataCenter.bubbles[row] || !GameDataCenter.bubbles[row][col]) return true; if (GameDataCenter.bubbles[row][col].getComponent('Bubble').color == 6) { GameDataCenter.bubbles[row][col].destroy(); Audio.playSoundByPath('game:res/snd/ice'); this.colorCount[5]--; this.creatBubble(row, col, color); } }) } /**碰撞动画 */ private crashTween(i: number, j: number): void { this.traversal(i, j, (row: number, col: number) => { if (!GameDataCenter.bubbles[row] || !GameDataCenter.bubbles[row][col]) return true; let start = this.convertRowColToPos(i, j); let end = this.convertRowColToPos(row, col); let dir = end.sub(start); cc.tween(GameDataCenter.bubbles[row][col]) .by(0.1, { position: dir.normalize().mul(10) }) .by(0.1, { position: dir.normalize().mul(-10) }) .start(); }) } /**炸弹 */ private bombBubble(): void { this.traversal(this.bubbleIndex.x, this.bubbleIndex.y, (row: number, col: number) => { this.traversal(row, col, (i, j) => { if (!GameDataCenter.bubbles[i] || !GameDataCenter.bubbles[i][j]) return true; this.specialBubbleIndex.push(cc.v2(i, j)); }) }) } /**七色 */ private omnipotentBubble(): void { this.traversal(this.bubbleIndex.x, this.bubbleIndex.y, (row: number, col: number) => { if (!GameDataCenter.bubbles[row] || !GameDataCenter.bubbles[row][col]) return true; let color = GameDataCenter.bubbles[row][col].getComponent('Bubble').color; this.traversalAll(row, col, (i: number, j: number) => { let nodeData = GameDataCenter.bubbles[i][j].getComponent('Bubble'); // 如果被访问过 if (nodeData.isVisited) return true; // 如果颜色不同 if (nodeData.color !== color) return true; // 符合条件 nodeData.isVisited = true; }) }); for (let row = 0; row < GameDataCenter.bubbles.length; row++) { for (let col = 0; col < GameDataCenter.bubbles[row].length; col++) { if (!GameDataCenter.bubbles[row][col]) continue; if (GameDataCenter.bubbles[row][col].getComponent('Bubble').isVisited) { GameDataCenter.bubbles[row][col].getComponent('Bubble').isVisited = false; this.specialBubbleIndex.push(cc.v2(row, col)); } } } } /**闪电 */ private lightningBubble(hitBubble: cc.Node, isTop: boolean): void { if (isTop) { this.thunderIndex = cc.v2(this.bubbleIndex.x, this.bubbleIndex.y); } else { this.thunderIndex = cc.v2(hitBubble.getComponent('Bubble').i, hitBubble.getComponent('Bubble').j); } for (let i = 0; i < GameDataCenter.bubbles[this.thunderIndex.x].length; i++) { let node = GameDataCenter.bubbles[this.thunderIndex.x][i] if (!node) { continue; } this.specialBubbleIndex.push(cc.v2(node.getComponent('Bubble').i, node.getComponent('Bubble').j)); } } /**清空空数组 */ private removeEmpty(): void { let removeCount: number = 0; for (let i = GameDataCenter.bubbles.length - 2; i >= 0; i--) { let count = 0; for (let j = 0; j < GameDataCenter.bubbles[i].length; j++) { if (GameDataCenter.bubbles[i][j]) { count++; } } if (count == 0) { GameDataCenter.bubbles.length--; if (GameDataCenter.bubbles.length >= 10) { removeCount++; } } } this.setMapPosition(-removeCount); let sum: number = 0; for (let i = 0; i < this.colorCount.length; i++) { sum += this.colorCount[i]; } let count = 0; if (sum == 0) { this.isWin = true; Audio.playSoundByPath('game:res/snd/victory'); GameDataCenter.gameLevel++; for (let i = 0; i < GameDataCenter.bubbles.length; i++) { for (let j = 0; j < GameDataCenter.bubbles[i].length; j++) { if (!GameDataCenter.bubbles[i][j]) { continue; } this.scheduleOnce(() => { GameDataCenter.bubbles[i][j].getComponent('Bubble').playDownAnimation(this.combo * 2, this.map.convertToNodeSpaceAR(this.startPos)); }, count * 0.01); count++; } } if (count > 0) { this.scheduleOnce(() => { this.changeUi('score', this.combo * 2 * count * 10); }, count * 0.01); } this.scheduleOnce(() => { this.initMap(); }, 2 + count * 0.01); } this.scheduleOnce(() => { if (this.specialBubbleType == 0) { this.scheduleOnce(() => { this.createShootBubble(); this.switchShootBubble(); }, this.isWin ? 3 : 0); } else { if (GameDataCenter.specialBubbles[this.specialBubbleType - 1] > 0) { this.changeUi(`special${this.specialBubbleType}`, -1); } else if (GameDataCenter.coin >= 100) { this.changeUi('coin', -100); } this.scheduleOnce(() => { this.switchSpecialBubble(-1); }, this.specialBubbleType == 2 ? 1 : 0); } }, count * 0.01); } /**传入二维数组行列, 返回对应位置坐标 */ private convertRowColToPos(row: number, col: number): cc.Vec3 { let posX: number = this.bubbleR * ((row % 2) + 1) + col * this.bubbleR * 2 - this.screenW / 2; let posY: number = this.screenH - (this.bubbleR + this.bubbleR * row * Math.sqrt(3)); return cc.v3(posX, posY); } /**计算向量与y轴之间的夹角 */ private vectorsToDegree(comVec, dirVec) { // 求方向向量与对比向量间的弧度 let dir = comVec.sub(dirVec); let radian = dir.signAngle(cc.v2(1, 0)); // 将弧度转换为角度 let degree = cc.misc.radiansToDegrees(radian); return Math.round(-(degree - 90)); } /**随机颜色函数 */ private randNum(): number { if (GameDataCenter.gameLevel == 1) { if (LevelConfig.level[1].index < 4) { return LevelConfig.level[1].bubble[LevelConfig.level[1].index++]; } } let color: number[] = []; for (let i = 0; i < this.colorCount.length - 1; i++) { if (this.colorCount[i] != 0) { color.push(i + 1); } } let min: number = 0; let max: number = color.length - 1; // random 0 - 1 不包括 1 let random = min + Math.floor((max - min + 1) * Math.random()) if (color.length == 0) { min = 1; max = this.colorCount.length - 1 random = min + Math.floor((max - min + 1) * Math.random()) return random; } return color[random]; } /**特殊消除球向量数组去重 */ private unique(): void { let array: cc.Vec2[] = [] for (let i in this.specialBubbleIndex) { let isExit = false; for (let j in array) { if (this.specialBubbleIndex[i].x == array[j].x && this.specialBubbleIndex[i].y == array[j].y) { isExit = true; break; } } if (!isExit) { array.push(cc.v2(this.specialBubbleIndex[i].x, this.specialBubbleIndex[i].y)) } } this.specialBubbleIndex = array; } /**设置特殊球瞄准线线段颜色 */ private setspecialColor(): void { let specialColor = this.specialColor[this.specialBubbleType - 1]; this.ray.fillColor = specialColor[0]; for (let i = 1; i < specialColor.length; i++) { let node = cc.instantiate(this.rayPrefab); node.parent = this.ray.node; let graphic = node.getComponent(cc.Graphics); graphic.fillColor = specialColor[i]; } } /**ui变化 */ private changeUi(type: string, num: number = 0): void { if (type == 'coin') { this.ui.getChildByName('topPanel').getChildByName('coin').getChildByName('num').children[0].getComponent(cc.Label).string = `${GameDataCenter.coin}`; if (num == 0) { return; } let t: number = GameDataCenter.coin; GameDataCenter.coin += num; for (let i = 0; i < Math.abs(GameDataCenter.coin - t); i++) { this.scheduleOnce(() => { num > 0 ? t++ : t--; this.ui.getChildByName('topPanel').getChildByName('coin').getChildByName('num').children[0].getComponent(cc.Label).string = `${t}`; }, 0.002 * i); } let specialBubble = this.ui.getChildByName('specialBubble'); for (let i = 0; i < specialBubble.childrenCount; i++) { specialBubble.children[i].getChildByName('null').getChildByName('icon').getComponent(cc.Sprite).spriteFrame = GameDataCenter.coin >= 100 ? this.iconSpriteFrame[2] : this.iconSpriteFrame[0]; specialBubble.children[i].getChildByName('null').getChildByName('label').getComponent(cc.Label).string = GameDataCenter.coin >= 100 ? '100' : ':1'; } } else if (type == 'score') { if (num == 0) { this.score = 0; this.ui.getChildByName('topPanel').getChildByName('score').getChildByName('scoreLabel').getComponent(cc.Label).string = `得分:${this.score}`; this.ui.getChildByName('topPanel').getChildByName('score').getChildByName('progressBar').getComponent(cc.ProgressBar).progress = 0; for (let i = 1; i <= 3; i++) { this.ui.getChildByName('topPanel').getChildByName('score').getChildByName(`star${i}`).getComponent(cc.Sprite).spriteFrame = this.iconSpriteFrame[3]; } return; } let t = this.score; this.score += num; for (let i = 0; i < Math.abs(this.score - t); i++) { this.scheduleOnce(() => { num > 0 ? t++ : t--; this.ui.getChildByName('topPanel').getChildByName('score').getChildByName('scoreLabel').getComponent(cc.Label).string = `得分:${t}`; this.ui.getChildByName('topPanel').getChildByName('score').getChildByName('progressBar').getComponent(cc.ProgressBar).progress = t / this.perfectScore; }, 0.5 * i / num); } this.scheduleOnce(() => { if (this.score >= this.perfectScore && this.star == 2) { this.ui.getChildByName('topPanel').getChildByName('score').getChildByName('star3').getComponent(cc.Sprite).spriteFrame = this.iconSpriteFrame[4]; this.star++; } if (this.score >= this.perfectScore * 0.7 && this.star == 1) { this.ui.getChildByName('topPanel').getChildByName('score').getChildByName('star2').getComponent(cc.Sprite).spriteFrame = this.iconSpriteFrame[4]; this.star++; } if (this.score >= this.perfectScore * 0.2 && this.star == 0) { this.ui.getChildByName('topPanel').getChildByName('score').getChildByName('star1').getComponent(cc.Sprite).spriteFrame = this.iconSpriteFrame[4]; this.star++; } }, 0.5); } else if (type.substring(0, type.length - 1) == 'special') { let specialBubble = this.ui.getChildByName('specialBubble'); let enableSwitch: Function = (i) => { specialBubble.children[i].getChildByName('num').active = GameDataCenter.specialBubbles[i] <= 0 ? false : true; specialBubble.children[i].getChildByName('null').active = GameDataCenter.specialBubbles[i] <= 0 ? true : false; specialBubble.children[i].getChildByName('null').getChildByName('icon').getComponent(cc.Sprite).spriteFrame = GameDataCenter.coin >= 100 ? this.iconSpriteFrame[2] : this.iconSpriteFrame[0]; specialBubble.children[i].getChildByName('null').getChildByName('label').getComponent(cc.Label).string = GameDataCenter.coin >= 100 ? '100' : ':1'; specialBubble.children[i].getChildByName('null').getChildByName('icon').setContentSize(GameDataCenter.coin >= 100 ? cc.size(40, 40) : cc.size(40, 30)); } for (let i = 0; i < specialBubble.childrenCount; i++) { specialBubble.children[i].getChildByName('num').getChildByName('label').getComponent(cc.Label).string = `${GameDataCenter.specialBubbles[i]}`; enableSwitch(i); } let specialBubbleType = (+type[type.length - 1]) - 1; if (specialBubbleType < 0 || num == 0) { return; } let t: number = GameDataCenter.specialBubbles[specialBubbleType]; let array = GameDataCenter.specialBubbles; array[specialBubbleType] += num; GameDataCenter.specialBubbles = array; for (let i = 0; i < Math.abs(GameDataCenter.specialBubbles[specialBubbleType] - t); i++) { this.scheduleOnce(() => { num > 0 ? t++ : t--; specialBubble.children[specialBubbleType].getChildByName('num').getChildByName('label').getComponent(cc.Label).string = `${t}`; }, 0.1 * i); } enableSwitch(specialBubbleType); } else if (type == 'ingot') { } } /**遍历小球一周 */ private traversal(i: number, j: number, callback: Function): void { let judge: Function = (row: number, col: number) => { let leftTop = col; // 根据不同的行做偏移 if (row % 2 === 0) { leftTop = col - 1; } // 每个泡泡周围有6个,依次检测 // 左上 test(row - 1, leftTop); //右上 test(row - 1, leftTop + 1); //左 test(row, col - 1); //右 test(row, col + 1); //左下 test(row + 1, leftTop); //右下 test(row + 1, leftTop + 1); } let test: Function = (row: number, col: number) => { if (row < 0) return; if (col < 0 || col >= 11) return; if (row % 2 == 1 && (col < 0 || col >= 10)) { return; } if (callback(row, col)) return; } judge(i, j); } /**遍历所有小球 */ private traversalAll(i: number, j: number, callback: Function, isDFS: boolean = false): void { if (isDFS) { //深搜 let test: Function = (row: number, col: number) => { if (!GameDataCenter.bubbles[row] || !GameDataCenter.bubbles[row][col]) return; if (row < 0) return; if (col < 0 || col >= 11) return; if (row % 2 == 1 && (col < 0 || col >= 10)) { return; } if (callback(row, col)) return; let leftTop = col; if (row % 2 === 0) { leftTop = col - 1; } // 每个泡泡周围有6个,依次检测 // 左上 test(row - 1, leftTop); //右上 test(row - 1, leftTop + 1); //左 test(row, col - 1); //右 test(row, col + 1); //左下 test(row + 1, leftTop); //右下 test(row + 1, leftTop + 1); } test(i, j); } else { //广搜 let indexs: cc.Vec2[] = []; indexs.push(cc.v2(i, j)); while (indexs.length != 0) { let index = indexs[0]; indexs.shift(); this.traversal(index.x, index.y, (row: number, col: number) => { if (!GameDataCenter.bubbles[row] || !GameDataCenter.bubbles[row][col]) return; if (row < 0) return; if (col < 0 || col >= 11) return; if (row % 2 == 1 && (col < 0 || col >= 10)) { return; } if (callback(row, col)) return; indexs.push(cc.v2(row, col)); }) } } } /**倒计时回调 */ private online(): void { this.onlineTime--; let mm = Math.floor(this.onlineTime / 60); let ss = this.onlineTime % 60; this.ui.getChildByName('online').getChildByName('time').getComponent(cc.Label).string = `${Utils.formatLen(mm, 2)};${Utils.formatLen(ss, 2)}`; let fun: Function = () => { this.scheduleOnce(() => { if (this.isPress) { fun(); } else { GameDataCenter.tipType = 4; UIManager.open('tip:TipPanel'); // this.onOnline(); } }, 1) } if (this.onlineTime <= 0) { this.ui.getChildByName('online').getChildByName('time').active = false; this.ui.getChildByName('online').getChildByName('name').getChildByName('label').getComponent(cc.Label).string = `领取`; this.ui.getChildByName('online').getChildByName('name').getChildByName('label').x += 14; this.ui.getChildByName('online').getChildByName('name').getChildByName('videoIcon').active = true; // this.ui.getChildByName('online').getComponent(cc.Button).interactable = true; this.unschedule(this.online); Utils.shake(this.ui.getChildByName('online').getChildByName('gift')); if (GameDataCenter.gameLevel >= 13) { fun(); } } } /**顶板透明 */ private topTween(op: number) { if (op) { this.ui.getChildByName('topPanel').opacity = 255; } else { this.ui.getChildByName('topPanel').opacity = 100; } } //创建数字 private creatLabel(s: string) { let node = new cc.Node(); node.parent = this.node; node.color = cc.color('#f5bf61' as any); let label = node.addComponent(cc.Label); label.string = s; label.fontSize = 34; label.lineHeight = 34; label.enableBold = true; this.scheduleOnce(() => { node.destroy() }, 1); } }