123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494 |
- import { _decorator, Component, Node, Label, Sprite, Button, resources, SpriteFrame, tween, Vec3, UIOpacity, UITransform, Color } from 'cc';
- import { DataManager } from './DataManager';
- const { ccclass, property } = _decorator;
- /**
- * 通行证数据接口 (与DataManager中的PassInfo保持一致)
- */
- interface PassCardData {
- name: string; // 人物姓名
- room: string; // 房间号
- identityId: string; // 身份ID (注意:这里与之前的id字段不同)
- reason: string; // 原因
- avatarPath: string; // 头像路径
- hasStamp: boolean; // 是否有印章
- }
- @ccclass('PassCardManager')
- export class PassCardManager extends Component {
- @property({
- type: Node,
- tooltip: '通行证面板节点'
- })
- passCardPanel: Node = null;
- @property({
- type: Label,
- tooltip: '姓名标签'
- })
- nameLabel: Label = null;
- @property({
- type: Label,
- tooltip: '房间号标签'
- })
- roomLabel: Label = null;
- @property({
- type: Label,
- tooltip: '身份ID标签'
- })
- idLabel: Label = null;
- @property({
- type: Label,
- tooltip: '原因标签'
- })
- reasonLabel: Label = null;
- @property({
- type: Sprite,
- tooltip: '头像显示组件'
- })
- avatarSprite: Sprite = null;
- @property({
- type: Button,
- tooltip: '关闭按钮'
- })
- closeButton: Button = null;
- @property({
- tooltip: '通行证面板动画时长(秒)',
- range: [0.1, 2.0, 0.1]
- })
- animDuration: number = 0.5;
- @property({
- type: Node,
- tooltip: '卡片阴影节点(可选)'
- })
- cardShadow: Node = null;
- @property({
- type: DataManager,
- tooltip: '数据管理器引用'
- })
- dataManager: DataManager = null;
- // 当前通行证数据
- private currentPassData: PassCardData = null;
- // 用于动画控制的UIOpacity组件
- private passCardOpacity: UIOpacity = null;
- private shadowOpacity: UIOpacity = null;
- start() {
- // 初始隐藏通行证面板
- if (this.passCardPanel) {
- this.passCardPanel.active = false;
-
- // 确保面板有UIOpacity组件
- this.passCardOpacity = this.passCardPanel.getComponent(UIOpacity);
- if (!this.passCardOpacity) {
- this.passCardOpacity = this.passCardPanel.addComponent(UIOpacity);
- }
- // 如果有阴影节点,初始化它
- if (this.cardShadow) {
- this.shadowOpacity = this.cardShadow.getComponent(UIOpacity);
- if (!this.shadowOpacity) {
- this.shadowOpacity = this.cardShadow.addComponent(UIOpacity);
- }
- this.cardShadow.active = false;
- } else {
- // 自动创建阴影节点
- this.createShadowNode();
- }
- }
- // 注册关闭按钮点击事件
- if (this.closeButton) {
- // 先移除可能已存在的事件监听(防止重复注册)
- this.closeButton.node.off(Button.EventType.CLICK, this.onCloseButtonClick, this);
- // 重新注册点击事件
- this.closeButton.node.on(Button.EventType.CLICK, this.onCloseButtonClick, this);
- console.log('关闭按钮事件已注册');
- } else {
- console.error('关闭按钮未设置');
- }
- }
- /**
- * 创建卡片阴影节点
- */
- private createShadowNode(): void {
- if (!this.passCardPanel || this.cardShadow) return;
- // 创建阴影节点
- this.cardShadow = new Node('CardShadow');
- this.passCardPanel.parent.insertChild(this.cardShadow, this.passCardPanel.getSiblingIndex());
-
- // 设置阴影大小
- const cardTransform = this.passCardPanel.getComponent(UITransform);
- if (cardTransform) {
- const shadowTransform = this.cardShadow.addComponent(UITransform);
- shadowTransform.width = cardTransform.width * 0.9;
- shadowTransform.height = cardTransform.height * 0.9;
- }
-
- // 添加阴影图像
- const shadowSprite = this.cardShadow.addComponent(Sprite);
- shadowSprite.color = new Color(0, 0, 0, 180);
-
- // 添加透明度控制
- this.shadowOpacity = this.cardShadow.addComponent(UIOpacity);
- this.shadowOpacity.opacity = 0;
-
- this.cardShadow.active = false;
- }
- /**
- * 关闭按钮点击事件处理
- */
- private onCloseButtonClick(): void {
- console.log('关闭按钮被点击');
- this.hidePassCard();
- }
- /**
- * 显示通行证
- * @param passDataOrCharacterId 通行证数据或角色ID
- */
- public showPassCard(passDataOrCharacterId: PassCardData | number): void {
- console.log('PassCardManager.showPassCard 被调用:', passDataOrCharacterId);
-
- if (!this.passCardPanel) {
- console.error('通行证面板未设置');
- return;
- }
- // 根据参数类型处理数据
- if (typeof passDataOrCharacterId === 'number') {
- // 如果传入的是角色ID,则从DataManager获取通行证数据
- if (!this.dataManager) {
- console.error('数据管理器未设置,无法通过角色ID获取通行证数据');
- return;
- }
-
- const characterId = passDataOrCharacterId;
- const passInfo = this.dataManager.getNPCPassInfo(characterId);
-
- if (!passInfo) {
- console.error(`无法获取角色ID ${characterId} 的通行证数据`);
- return;
- }
-
- // 保存当前数据
- this.currentPassData = passInfo;
- } else {
- // 直接使用传入的通行证数据
- this.currentPassData = passDataOrCharacterId;
- }
- // 更新UI显示
- this.updatePassCardUI();
- // 显示面板并播放动画
- this.passCardPanel.active = true;
- this.playShowAnimation();
- console.log('通行证面板已显示');
- // 确保阴影也显示
- if (this.cardShadow) {
- this.cardShadow.active = true;
- }
- }
- /**
- * 播放显示动画
- */
- private playShowAnimation(): void {
- // 重置面板的初始状态
- this.passCardPanel.setScale(new Vec3(0.6, 0.6, 1));
- this.passCardPanel.setPosition(new Vec3(200, -100, 0)); // 从更远的地方传递过来
- this.passCardPanel.setRotationFromEuler(new Vec3(0, 0, -15)); // 初始旋转角度
-
- // 设置初始透明度
- if (this.passCardOpacity) {
- this.passCardOpacity.opacity = 0;
- }
- // 设置阴影初始状态
- if (this.cardShadow && this.shadowOpacity) {
- this.cardShadow.setPosition(new Vec3(210, -105, 0)); // 稍微偏移
- this.cardShadow.setScale(new Vec3(0.6, 0.6, 1));
- this.cardShadow.setRotationFromEuler(new Vec3(0, 0, -15));
- this.shadowOpacity.opacity = 0;
- }
- // 创建动画序列 - 模拟传递过来的感觉
- tween(this.passCardPanel)
- // 第一阶段:接近动作,带有轻微旋转
- .to(this.animDuration * 0.7, {
- scale: new Vec3(1.05, 1.05, 1),
- position: new Vec3(10, 5, 0),
- eulerAngles: new Vec3(0, 0, 5) // 轻微旋转到反方向
- }, {
- easing: 'quartOut'
- })
- // 第二阶段:最终位置,带有轻微的回弹效果
- .to(this.animDuration * 0.3, {
- scale: new Vec3(1, 1, 1),
- position: new Vec3(0, 0, 0),
- eulerAngles: new Vec3(0, 0, 0)
- }, {
- easing: 'backOut'
- })
- // 第三阶段:添加轻微的抖动效果,模拟卡片放在桌面上的感觉
- .call(() => {
- this.addShakeEffect();
- })
- .start();
-
- // 为阴影创建跟随动画
- if (this.cardShadow) {
- tween(this.cardShadow)
- // 第一阶段
- .to(this.animDuration * 0.7, {
- scale: new Vec3(1.05, 1.05, 1),
- position: new Vec3(15, 2, 0), // 稍微偏移以产生阴影效果
- eulerAngles: new Vec3(0, 0, 5)
- }, {
- easing: 'quartOut'
- })
- // 第二阶段
- .to(this.animDuration * 0.3, {
- scale: new Vec3(1, 1, 1),
- position: new Vec3(5, -3, 0), // 保持偏移
- eulerAngles: new Vec3(0, 0, 0)
- }, {
- easing: 'backOut'
- })
- .start();
-
- // 阴影透明度动画
- if (this.shadowOpacity) {
- tween(this.shadowOpacity)
- .delay(this.animDuration * 0.2)
- .to(this.animDuration * 0.5, { opacity: 100 }) // 半透明阴影
- .start();
- }
- }
-
- // 单独为透明度创建动画
- if (this.passCardOpacity) {
- tween(this.passCardOpacity)
- .to(this.animDuration * 0.5, { opacity: 255 })
- .start();
- }
- }
- /**
- * 添加轻微的抖动效果
- */
- private addShakeEffect(): void {
- // 创建一个轻微的抖动效果,模拟卡片被放置的震感
- const originalPos = new Vec3(0, 0, 0);
- const shakeAmount = 1.5; // 抖动幅度
-
- tween(this.passCardPanel)
- .to(0.05, { position: new Vec3(shakeAmount, 0, 0) })
- .to(0.05, { position: new Vec3(-shakeAmount, 0, 0) })
- .to(0.05, { position: new Vec3(shakeAmount * 0.5, 0, 0) })
- .to(0.05, { position: new Vec3(-shakeAmount * 0.5, 0, 0) })
- .to(0.05, { position: originalPos })
- .start();
- // 同时给阴影添加抖动效果
- if (this.cardShadow) {
- const shadowOriginalPos = new Vec3(5, -3, 0); // 阴影的原始位置
-
- tween(this.cardShadow)
- .to(0.05, { position: new Vec3(shadowOriginalPos.x + shakeAmount, shadowOriginalPos.y, 0) })
- .to(0.05, { position: new Vec3(shadowOriginalPos.x - shakeAmount, shadowOriginalPos.y, 0) })
- .to(0.05, { position: new Vec3(shadowOriginalPos.x + shakeAmount * 0.5, shadowOriginalPos.y, 0) })
- .to(0.05, { position: new Vec3(shadowOriginalPos.x - shakeAmount * 0.5, shadowOriginalPos.y, 0) })
- .to(0.05, { position: shadowOriginalPos })
- .start();
- }
- }
- /**
- * 隐藏通行证
- */
- public hidePassCard(): void {
- console.log('hidePassCard 被调用');
-
- if (this.passCardPanel) {
- // 播放隐藏动画
- this.playHideAnimation(() => {
- this.passCardPanel.active = false;
- console.log('通行证面板已隐藏');
- });
- } else {
- console.error('通行证面板未设置,无法隐藏');
- }
- }
- /**
- * 播放隐藏动画
- * @param callback 动画完成回调
- */
- private playHideAnimation(callback?: Function): void {
- // 创建移动和缩放动画 - 模拟被人收回的感觉
- tween(this.passCardPanel)
- // 首先上抬一点,像是被拿起
- .to(this.animDuration * 0.2, {
- position: new Vec3(0, 10, 0),
- eulerAngles: new Vec3(0, 0, -5)
- }, {
- easing: 'sineOut'
- })
- // 然后向远处移动,同时旋转
- .to(this.animDuration * 0.6, {
- scale: new Vec3(0.7, 0.7, 1),
- position: new Vec3(-180, 50, 0),
- eulerAngles: new Vec3(0, 0, -15)
- }, {
- easing: 'quartIn'
- })
- .call(() => {
- if (callback) callback();
- })
- .start();
-
- // 阴影的隐藏动画
- if (this.cardShadow) {
- tween(this.cardShadow)
- // 首先上抬一点,跟随卡片
- .to(this.animDuration * 0.2, {
- position: new Vec3(5, 7, 0), // 保持偏移
- eulerAngles: new Vec3(0, 0, -5)
- }, {
- easing: 'sineOut'
- })
- // 然后向远处移动
- .to(this.animDuration * 0.6, {
- scale: new Vec3(0.7, 0.7, 1),
- position: new Vec3(-175, 47, 0), // 保持偏移
- eulerAngles: new Vec3(0, 0, -15)
- }, {
- easing: 'quartIn'
- })
- .call(() => {
- if (this.cardShadow) {
- this.cardShadow.active = false;
- }
- })
- .start();
-
- // 阴影透明度动画
- if (this.shadowOpacity) {
- tween(this.shadowOpacity)
- .to(this.animDuration * 0.5, { opacity: 0 })
- .start();
- }
- }
-
- // 单独为透明度创建动画,稍微延迟开始
- if (this.passCardOpacity) {
- tween(this.passCardOpacity)
- .delay(this.animDuration * 0.1)
- .to(this.animDuration * 0.7, { opacity: 0 })
- .start();
- }
- }
- /**
- * 更新通行证UI
- */
- private updatePassCardUI(): void {
- console.log('更新通行证UI');
-
- if (!this.currentPassData) {
- console.error('没有通行证数据');
- return;
- }
- // 更新文本内容
- if (this.nameLabel) {
- this.nameLabel.string = this.currentPassData.name || '';
- console.log('设置姓名:', this.currentPassData.name);
- } else {
- console.error('姓名标签未设置');
- }
- if (this.roomLabel) {
- this.roomLabel.string = this.currentPassData.room || '';
- console.log('设置房间号:', this.currentPassData.room);
- } else {
- console.error('房间号标签未设置');
- }
- if (this.idLabel) {
- // 注意这里使用identityId而不是之前的id
- this.idLabel.string = this.currentPassData.identityId || '';
- console.log('设置ID:', this.currentPassData.identityId);
- } else {
- console.error('ID标签未设置');
- }
- if (this.reasonLabel) {
- this.reasonLabel.string = this.currentPassData.reason || '';
- console.log('设置原因:', this.currentPassData.reason);
- } else {
- console.error('原因标签未设置');
- }
- // 加载并显示头像(使用avatarPath)
- this.loadAvatar();
- }
- /**
- * 加载角色头像
- */
- private loadAvatar(): void {
- if (!this.avatarSprite) {
- console.error('头像Sprite组件未设置');
- return;
- }
-
- if (!this.currentPassData || !this.currentPassData.avatarPath) {
- console.error('无效的头像路径');
- return;
- }
- const avatarPath = this.currentPassData.avatarPath;
- console.log('尝试加载头像路径:', avatarPath);
-
- // 移除.png后缀
- const pathWithoutExtension = avatarPath.replace(/\.png$/, '');
-
- // 处理路径,确保以'/spriteFrame'结尾
- const finalPath = pathWithoutExtension.endsWith('/spriteFrame') ? pathWithoutExtension : `${pathWithoutExtension}/spriteFrame`;
-
- // 加载头像资源
- resources.load(finalPath, SpriteFrame, (err, spriteFrame) => {
- if (err) {
- console.error(`加载头像失败: ${finalPath}`, err);
- } else {
- // 设置头像
- this.avatarSprite.spriteFrame = spriteFrame;
- console.log('头像加载成功: ' + finalPath);
- }
- });
- }
- onDestroy() {
- // 清理事件监听
- if (this.closeButton) {
- this.closeButton.node.off(Button.EventType.CLICK, this.onCloseButtonClick, this);
- }
- }
- }
|