461 lines
14 KiB
TypeScript
461 lines
14 KiB
TypeScript
import { _decorator, animation, Animation, AnimationComponent, Button, Component, EventTouch, Input, input, instantiate, Label, math, Node, Prefab, randomRange, randomRangeInt, screen, Screen, sys, tween, Vec2, Vec3, view } from 'cc';
|
|
import { PanelBase } from '../framework/ui/PanelBase';
|
|
import { FPSCameraController } from '../FPSCameraController';
|
|
import { GameController } from '../GameController';
|
|
import { TargetIconItem } from './TargetIconItem';
|
|
import { EventCenter } from '../EventCenter';
|
|
import { UIManager } from '../framework/ui/UIManager';
|
|
import { QingBaoPanel } from './QingBaoPanel';
|
|
import { SettingPanel } from './SettingPanel';
|
|
import { SdkMgr } from '../framework/sdk/SdkMgr';
|
|
import { AudioMgr } from '../framework/audio/AudioMgr';
|
|
import { AssetController } from '../AssetController';
|
|
import { Ragdoll } from '../../Ragdoll/Ragdoll';
|
|
import { LocalSaveMgr } from '../framework/data/LocalSaveMgr';
|
|
const { ccclass, property } = _decorator;
|
|
|
|
@ccclass('PlayPanel')
|
|
export class PlayPanel extends PanelBase {
|
|
|
|
static instance: PlayPanel = null
|
|
|
|
@property(Node)
|
|
moveNode: Node = null; // 相机节点
|
|
|
|
@property(Node)
|
|
saoMiaoTip: Node = null; // 相机节点
|
|
|
|
@property(Node)
|
|
aimContent: Node = null;
|
|
|
|
@property(Node)
|
|
closeAim: Node = null;
|
|
|
|
@property(Node)
|
|
cancelLabel: Node = null;
|
|
|
|
@property(Prefab)
|
|
targetIconPrefab: Prefab = null;
|
|
|
|
@property(Node)
|
|
targetIconParent: Node = null;
|
|
|
|
@property(Button)
|
|
anim: Button = null;
|
|
|
|
@property(Button)
|
|
qingBao: Button = null;
|
|
|
|
|
|
@property(Label)
|
|
timerLabel: Label = null;
|
|
|
|
@property(Button)
|
|
saoMiao: Button = null;
|
|
|
|
@property(Button)
|
|
setting: Button = null;
|
|
|
|
@property(Label)
|
|
levelIndexLabel: Label = null;
|
|
|
|
|
|
@property(Button)
|
|
fire: Button = null;
|
|
|
|
@property(Node)
|
|
finger: Node = null;
|
|
|
|
@property(Node)
|
|
qingBaoResultNode: Node = null;
|
|
|
|
@property(Button)
|
|
qingBaoResultBtn: Button = null;
|
|
|
|
@property(AnimationComponent)
|
|
alienAnim: AnimationComponent = null;
|
|
|
|
@property(Label)
|
|
tutorialLabel: Label = null;
|
|
|
|
@property(Node)
|
|
tutorialLabelNode: Node = null;
|
|
|
|
@property(Node)
|
|
targetNode: Node = null;
|
|
|
|
|
|
@property(Node)
|
|
tipNode1: Node = null;
|
|
@property(Node)
|
|
tipNode2: Node = null;
|
|
@property(Node)
|
|
tipNode3: Node = null;
|
|
|
|
@property([Animation])
|
|
shootAnimations: Animation[] = [];
|
|
|
|
|
|
targetIcons: Array<TargetIconItem> = [];
|
|
|
|
onLoad() {
|
|
PlayPanel.instance = this
|
|
|
|
// Register the touch start event
|
|
this.moveNode.on(Node.EventType.TOUCH_START, this.onTouchStart, this);
|
|
this.moveNode.on(Node.EventType.TOUCH_MOVE, this.onTouchMove, this);
|
|
this.moveNode.on(Node.EventType.TOUCH_END, this.onTouchEnd, this);
|
|
|
|
this.anim.node.on(Button.EventType.CLICK, this.onClickAim, this);
|
|
this.fire.node.on(Button.EventType.CLICK, this.onClickFire, this);
|
|
this.qingBao.node.on(Button.EventType.CLICK, this.onClickQingBao, this);
|
|
this.qingBaoResultBtn.node.on(Button.EventType.CLICK, this.onClickQingBaoResult, this);
|
|
this.saoMiao.node.on(Button.EventType.CLICK, this.onClickSaoMiao, this);
|
|
this.setting.node.on(Button.EventType.CLICK, this.onClickSetting, this);
|
|
EventCenter.onEnemyDie.on(null, this.refreshTargetCount).bind(this)
|
|
|
|
|
|
}
|
|
onClickSetting() {
|
|
AudioMgr.inst.playOneShot(AssetController.instance.click)
|
|
UIManager.instance.openPanel(SettingPanel)
|
|
}
|
|
|
|
showTimer() {
|
|
let totalSeconds = GameController.getInstance().curLevel.timer
|
|
totalSeconds = Math.ceil(totalSeconds);
|
|
let minutes = Math.floor(totalSeconds / 60);
|
|
let seconds = totalSeconds % 60;
|
|
|
|
// 将分钟和秒格式化为两位数
|
|
let formattedMinutes = minutes < 10 ? `0${minutes}` : `${minutes}`;
|
|
let formattedSeconds = seconds < 10 ? `0${seconds}` : `${seconds}`;
|
|
|
|
// 组合成 00:00 的格式
|
|
let formattedTime = `${formattedMinutes}:${formattedSeconds}`;
|
|
this.timerLabel.string = formattedTime
|
|
}
|
|
|
|
onClickQingBao() {
|
|
if (sys.platform == sys.Platform.BYTEDANCE_MINI_GAME) {
|
|
tt.reportAnalytics('use_prop', {
|
|
level: GameController.getInstance().curLevel.levelIndex,
|
|
});
|
|
}
|
|
|
|
AudioMgr.inst.playOneShot(AssetController.instance.click)
|
|
SdkMgr.instance.playerRewardAds(() => {
|
|
|
|
UIManager.instance.openPanel(QingBaoPanel)
|
|
this.closeTip()
|
|
this.qingBaoResultNode.active = true
|
|
this.qingBao.node.active = false
|
|
})
|
|
}
|
|
|
|
|
|
onClickQingBaoResult() {
|
|
AudioMgr.inst.playOneShot(AssetController.instance.click)
|
|
UIManager.instance.openPanel(QingBaoPanel)
|
|
this.closeTip()
|
|
}
|
|
|
|
|
|
isOpenSaomiao: boolean = false
|
|
offset: Vec2
|
|
|
|
onClickSaoMiao() {
|
|
if (sys.platform == sys.Platform.BYTEDANCE_MINI_GAME) {
|
|
tt.reportAnalytics('use_prop', {
|
|
level: GameController.getInstance().curLevel.levelIndex,
|
|
});
|
|
}
|
|
|
|
AudioMgr.inst.playOneShot(AssetController.instance.click)
|
|
SdkMgr.instance.playerRewardAds(() => {
|
|
this.saoMiaoTip.active = true
|
|
GameController.getInstance().curLevel.SetSaoMiaoTarget()
|
|
this.offset = new Vec2(randomRange(-200, 200), randomRange(-200, 200))
|
|
this.updateSaomiao()
|
|
this.isOpenSaomiao = true
|
|
this.closeTip()
|
|
})
|
|
}
|
|
|
|
tipTimer = 0;
|
|
onTip: boolean = false
|
|
|
|
protected update(dt: number): void {
|
|
this.showTimer()
|
|
|
|
if (!this.onStep && !this.onTip)
|
|
this.tipTimer += dt
|
|
|
|
|
|
if (!this.onTip && this.tipTimer > 30) {
|
|
|
|
this.startTip()
|
|
}
|
|
}
|
|
|
|
startTip() {
|
|
|
|
this.onTip = true
|
|
AudioMgr.inst.playOneShot(AssetController.instance.xiao)
|
|
this.tipTimer = 0
|
|
this.tipNode1.active = true
|
|
this.tipNode2.active = true
|
|
this.tipNode3.active = true
|
|
|
|
this.alienAnim.play()
|
|
}
|
|
|
|
closeTip() {
|
|
this.onTip = false
|
|
this.tipTimer = 0
|
|
this.tipNode1.active = false
|
|
this.tipNode2.active = false
|
|
this.tipNode3.active = false
|
|
}
|
|
|
|
updateTargetPos() {
|
|
let target = this.tutorialTarget
|
|
if (!target) return;
|
|
if (target.isDie) {
|
|
this.saoMiaoTip.active = false
|
|
this.isOpenSaomiao = false
|
|
}
|
|
// 获取 3D 物体的世界坐标
|
|
let worldPos = target.centerNode.getWorldPosition();
|
|
// 获取主摄像机
|
|
let camera = FPSCameraController.getInstance().camera;
|
|
|
|
// 将世界坐标转换为屏幕坐标
|
|
let uiPos = camera.convertToUINode(worldPos, this.node);
|
|
// 设置 UI 节点的位置
|
|
this.targetNode.position = uiPos;
|
|
|
|
if (this.targetNode.position.y < 0 && Math.abs(this.targetNode.position.x) < 30) {
|
|
this.EnterStep3()
|
|
FPSCameraController.getInstance().setTutorialRotate()
|
|
}
|
|
|
|
}
|
|
|
|
protected lateUpdate(dt: number): void {
|
|
this.updateSaomiao()
|
|
this.updateTargetPos()
|
|
// this.updateQingBao()
|
|
|
|
}
|
|
|
|
|
|
// updateQingBao() {
|
|
// if (this.qingBaoResultNode.active) {
|
|
// if (!GameController.getInstance().curLevel.haveQingBaoTarget()) {
|
|
// this.switchAim(this.isOnAim)
|
|
// }
|
|
// }
|
|
// }
|
|
|
|
updateSaomiao() {
|
|
let target = GameController.getInstance().curLevel.saoMiaoTarget
|
|
if (!target) return;
|
|
if (target.isDie) {
|
|
this.saoMiaoTip.active = false
|
|
this.isOpenSaomiao = false
|
|
}
|
|
if (!this.isOpenSaomiao) return
|
|
// 获取 3D 物体的世界坐标
|
|
let worldPos = target.centerNode.getWorldPosition();
|
|
|
|
// 获取主摄像机
|
|
let camera = FPSCameraController.getInstance().camera;
|
|
|
|
// 将世界坐标转换为屏幕坐标
|
|
let uiPos = camera.convertToUINode(worldPos, this.node);
|
|
// 设置 UI 节点的位置
|
|
// console.log(uiPos)
|
|
uiPos = new Vec3(uiPos.x + this.offset.x, uiPos.y + this.offset.y, 0)
|
|
this.saoMiaoTip.position = uiPos;
|
|
}
|
|
tutorialTarget: Ragdoll
|
|
|
|
protected onOpen(): void {
|
|
PlayPanel.instance.switchAim(false)
|
|
PlayPanel.instance.initEnemies()
|
|
|
|
this.levelIndexLabel.string = `关卡 ${GameController.getInstance().curLevel.levelIndex}`
|
|
if (GameController.getInstance().curLevel.levelIndex == 1 && !LocalSaveMgr.instance.playerData.haveTutorial) {
|
|
this.onStep = true
|
|
}
|
|
|
|
if (this.onStep) {
|
|
this.EnterStep1()
|
|
this.tutorialTarget = GameController.getInstance().curLevel.getTutorialAliveEnemey()
|
|
console.log("Player panel", this.tutorialTarget)
|
|
} else {
|
|
this.targetNode.active = false
|
|
this.finger.active = false
|
|
this.tutorialLabelNode.active = false
|
|
}
|
|
this.qingBaoResultNode.active = false
|
|
}
|
|
|
|
isOnAim: boolean = false
|
|
switchAim(onAim: boolean) {
|
|
this.anim.node.active = !onAim
|
|
this.fire.node.active = onAim
|
|
this.isOnAim = onAim
|
|
this.cancelLabel.active = onAim
|
|
this.qingBao.node.active = !onAim && !GameController.getInstance().curLevel.haveQingBaoTarget()
|
|
this.qingBaoResultNode.active = !onAim && GameController.getInstance().curLevel.haveQingBaoTarget()
|
|
this.saoMiao.node.active = !onAim
|
|
this.aimContent.active = onAim
|
|
this.closeAim.active = !onAim
|
|
GameController.getInstance().curLevel.gunNode.active = !onAim
|
|
}
|
|
|
|
|
|
refreshTargetCount() {
|
|
let self = PlayPanel.instance
|
|
let aliveCount = GameController.getInstance().curLevel.aliveCount
|
|
for (let index = 0; index < self.targetIcons.length; index++) {
|
|
if (index < aliveCount) {
|
|
self.targetIcons[index].switchActive(true)
|
|
} else {
|
|
self.targetIcons[index].switchActive(false)
|
|
}
|
|
}
|
|
}
|
|
|
|
initEnemies() {
|
|
let count = GameController.getInstance().curLevel.enemies.length
|
|
console.log("目标外星人个数", count)
|
|
|
|
for (let index = 0; index < count; index++) {
|
|
var item = instantiate(this.targetIconPrefab)
|
|
item.parent = this.targetIconParent
|
|
let iconItem = item.getComponent(TargetIconItem)
|
|
this.targetIcons.push(iconItem)
|
|
iconItem.switchActive(true)
|
|
}
|
|
}
|
|
|
|
onClickAim() {
|
|
AudioMgr.inst.playOneShot(AssetController.instance.click)
|
|
FPSCameraController.getInstance().onAimButtonClick(true)
|
|
this.switchAim(true)
|
|
|
|
if (this.onStep) {
|
|
this.EnterStep2()
|
|
}
|
|
}
|
|
|
|
limitFire: boolean = false
|
|
|
|
onClickFire() {
|
|
if (this.limitFire) return
|
|
|
|
if (this.onStep) {
|
|
this.finishTutorial()
|
|
}
|
|
|
|
this.closeTip()
|
|
|
|
AudioMgr.inst.playOneShot(AssetController.instance.fire)
|
|
let result = FPSCameraController.getInstance().shoot()
|
|
if (result) {
|
|
let effect = this.shootAnimations[randomRangeInt(0, this.shootAnimations.length)]
|
|
effect.node.active = true
|
|
effect.play()
|
|
this.scheduleOnce(() => {
|
|
effect.node.active = false
|
|
}, 0.8)
|
|
}
|
|
let self = this
|
|
self.limitFire = true
|
|
tween(this.aimContent)
|
|
.to(0.05, { scale: new Vec3(1, 1, 1), position: new Vec3(0, 120, 0) })
|
|
.to(0.05, { scale: new Vec3(0.8, 0.8, 1), position: new Vec3(0, 0, 0) })
|
|
.call(() => {
|
|
self.limitFire = false
|
|
})
|
|
.start()
|
|
}
|
|
|
|
downTime: Date
|
|
startTouchPos: Vec2 = null
|
|
onTouchStart(event: EventTouch) {
|
|
FPSCameraController.getInstance().onTouchStart(event)
|
|
this.downTime = new Date();
|
|
this.startTouchPos = event.getLocation()
|
|
}
|
|
|
|
onTouchMove(event: EventTouch) {
|
|
FPSCameraController.getInstance().onTouchMove(event)
|
|
}
|
|
|
|
onTouchEnd(event: EventTouch) {
|
|
if (this.isOnAim) {
|
|
let now = new Date();
|
|
var offset = now.getTime() - this.downTime.getTime()
|
|
let moveDetal = Math.abs(this.startTouchPos.x - event.getLocation().x) + Math.abs(this.startTouchPos.y - event.getLocation().y)
|
|
// console.log("offset", offset, moveDetal)
|
|
|
|
if (!this.onStep)
|
|
if (offset < 200 && moveDetal < 20) {
|
|
FPSCameraController.getInstance().onAimButtonClick(false)
|
|
this.switchAim(false)
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
EnterStep1() {
|
|
this.targetNode.active = true
|
|
this.finger.active = true
|
|
this.tutorialLabel.string = "点击瞄准按钮"
|
|
this.moveNode.active = false
|
|
this.tutorialLabelNode.active = true
|
|
}
|
|
onStep: boolean = false
|
|
EnterStep2() {
|
|
this.finger.active = false
|
|
this.tutorialLabel.string = "滑动屏幕,瞄准目标"
|
|
this.moveNode.active = true
|
|
this.fire.node.active = false
|
|
this.cancelLabel.active = false
|
|
}
|
|
|
|
EnterStep3() {
|
|
this.fire.node.active = true
|
|
this.finger.active = true
|
|
this.tutorialLabel.string = "点击开火按钮"
|
|
this.moveNode.active = false
|
|
this.cancelLabel.active = false
|
|
}
|
|
|
|
|
|
finishTutorial() {
|
|
this.targetNode.active = false
|
|
this.finger.active = false
|
|
this.tutorialLabelNode.active = false
|
|
this.tutorialLabel.string = "点击开火按钮"
|
|
this.moveNode.active = true
|
|
this.onStep = false
|
|
this.tutorialTarget = null
|
|
LocalSaveMgr.instance.completeTutorial()
|
|
this.cancelLabel.active = true
|
|
}
|
|
|
|
|
|
protected onDestroy(): void {
|
|
PlayPanel.instance = null
|
|
EventCenter.onEnemyDie.off(null, this.refreshTargetCount)
|
|
|
|
}
|
|
}
|
|
|
|
|