Files
Alien_Sniper/assets/scripts/ui/PlayPanel.ts
T

502 lines
16 KiB
TypeScript

import { _decorator, animation, Animation, AnimationComponent, Button, Color, Component, EventTouch, HorizontalTextAlignment, Input, input, instantiate, Label, math, Node, Prefab, randomRange, randomRangeInt, screen, Screen, tween, UITransform, Vec2, Vec3, VerticalTextAlignment, 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';
import { LevelState } from '../EnumFile';
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);
this.createDeveloperButtons()
EventCenter.onEnemyDie.on(null, this.refreshTargetCount).bind(this)
}
/** 为测试关卡提供快捷操作,仅显示文字,避免与正式功能图标混淆。 */
private createDeveloperButtons() {
this.createDeveloperButton('DEV_KillEnemies', '开发:杀死敌人', new Vec3(350, 830, 0), this.onClickDevKillEnemies)
this.createDeveloperButton('DEV_CompleteLevel', '开发:完成过关', new Vec3(350, 760, 0), this.onClickDevCompleteLevel)
}
private createDeveloperButton(name: string, text: string, position: Vec3, callback: () => void) {
const buttonNode = new Node(name)
buttonNode.name = name
buttonNode.layer = this.setting.node.layer
buttonNode.setParent(this.setting.node.parent)
buttonNode.setPosition(position)
buttonNode.addComponent(UITransform).setContentSize(220, 60)
const button = buttonNode.addComponent(Button)
const labelNode = new Node('Label')
labelNode.layer = buttonNode.layer
labelNode.setParent(buttonNode)
labelNode.addComponent(UITransform).setContentSize(220, 60)
const label = labelNode.addComponent(Label)
label.string = text
label.fontSize = 24
label.lineHeight = 32
label.color = new Color(255, 220, 90, 255)
label.horizontalAlign = HorizontalTextAlignment.CENTER
label.verticalAlign = VerticalTextAlignment.CENTER
button.node.on(Button.EventType.CLICK, callback, this)
}
private onClickDevKillEnemies() {
const level = GameController.getInstance().curLevel
if (level.levelState !== LevelState.Running) return
AudioMgr.inst.playOneShot(AssetController.instance.click)
for (const enemy of level.enemies) {
if (!enemy.isDie) {
enemy.setEnabled(true)
}
}
}
private onClickDevCompleteLevel() {
const level = GameController.getInstance().curLevel
if (level.levelState !== LevelState.Running) return
AudioMgr.inst.playOneShot(AssetController.instance.click)
level.win()
}
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() {
AudioMgr.inst.playOneShot(AssetController.instance.click)
SdkMgr.instance.requestReward(() => {
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() {
AudioMgr.inst.playOneShot(AssetController.instance.click)
SdkMgr.instance.requestReward(() => {
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)
}
}