208 行
7.7 KiB
TypeScript
208 行
7.7 KiB
TypeScript
|
|
import { _decorator, Component, Node, Label, Sprite, Color, UITransform, Size, Layout } from 'cc';
|
|||
|
|
import { UITheme } from '../common/UITheme';
|
|||
|
|
import { UIBase } from '../common/UIBase';
|
|||
|
|
|
|||
|
|
const { ccclass, property } = _decorator;
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 角色面板 - 属性/装备/包裹
|
|||
|
|
* 基于江湖截图:角色属性 + 六边形装备槽 + 物品栏
|
|||
|
|
*/
|
|||
|
|
@ccclass('CharacterPanel')
|
|||
|
|
export class CharacterPanel extends UIBase {
|
|||
|
|
|
|||
|
|
@property(Node) characterInfo: Node = null!;
|
|||
|
|
@property(Node) statsArea: Node = null!;
|
|||
|
|
@property(Node) equipmentArea: Node = null!;
|
|||
|
|
@property(Node) inventoryArea: Node = null!;
|
|||
|
|
|
|||
|
|
start() {
|
|||
|
|
this.initCharacterInfo();
|
|||
|
|
this.initStatsArea();
|
|||
|
|
this.initEquipmentArea();
|
|||
|
|
this.initInventoryArea();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 角色基本信息区
|
|||
|
|
* 头像 + 角色名 + 称号 + 气血
|
|||
|
|
*/
|
|||
|
|
private initCharacterInfo() {
|
|||
|
|
if (!this.characterInfo) return;
|
|||
|
|
|
|||
|
|
const layout = this.characterInfo.addComponent(Layout);
|
|||
|
|
layout.type = Layout.Type.VERTICAL;
|
|||
|
|
|
|||
|
|
// 角色头像区域(圆形)
|
|||
|
|
const avatarNode = new Node('Avatar');
|
|||
|
|
const avatarTransform = avatarNode.addComponent(UITransform);
|
|||
|
|
avatarTransform.setContentSize(new Size(160, 160));
|
|||
|
|
avatarNode.setParent(this.characterInfo);
|
|||
|
|
|
|||
|
|
// 角色名
|
|||
|
|
const nameNode = new Node('Name');
|
|||
|
|
const nameLabel = nameNode.addComponent(Label);
|
|||
|
|
nameLabel.string = '角色名';
|
|||
|
|
nameLabel.fontSize = UITheme.FONT_SIZE.LG;
|
|||
|
|
nameLabel.color = this.hexToColor(UITheme.COLORS.TEXT_GOLD);
|
|||
|
|
nameNode.setParent(this.characterInfo);
|
|||
|
|
|
|||
|
|
// 称号
|
|||
|
|
const titleNode = new Node('Title');
|
|||
|
|
const titleLabel = titleNode.addComponent(Label);
|
|||
|
|
titleLabel.string = '锐不可挡';
|
|||
|
|
titleLabel.fontSize = UITheme.FONT_SIZE.SM;
|
|||
|
|
titleLabel.color = this.hexToColor(UITheme.COLORS.TEXT_ORANGE);
|
|||
|
|
titleNode.setParent(this.characterInfo);
|
|||
|
|
|
|||
|
|
// 气血
|
|||
|
|
const hpNode = new Node('HP');
|
|||
|
|
const hpLabel = hpNode.addComponent(Label);
|
|||
|
|
hpLabel.string = '气血 283098';
|
|||
|
|
hpLabel.fontSize = UITheme.FONT_SIZE.MD;
|
|||
|
|
hpLabel.color = this.hexToColor(UITheme.COLORS.HP_BAR);
|
|||
|
|
hpNode.setParent(this.characterInfo);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 属性面板
|
|||
|
|
* 攻击/筋骨/力道/身法/眼识
|
|||
|
|
*/
|
|||
|
|
private initStatsArea() {
|
|||
|
|
if (!this.statsArea) return;
|
|||
|
|
|
|||
|
|
const transform = this.statsArea.getComponent(UITransform) || this.statsArea.addComponent(UITransform);
|
|||
|
|
transform.setContentSize(new Size(400, 300));
|
|||
|
|
|
|||
|
|
const stats = [
|
|||
|
|
{ name: '攻击', value: '92442', color: UITheme.COLORS.TEXT_WHITE },
|
|||
|
|
{ name: '筋骨', value: '6031', color: UITheme.COLORS.TEXT_WHITE },
|
|||
|
|
{ name: '力道', value: '8963', color: UITheme.COLORS.TEXT_WHITE },
|
|||
|
|
{ name: '身法', value: '13249', color: UITheme.COLORS.TEXT_WHITE },
|
|||
|
|
{ name: '眼识', value: '3293', color: UITheme.COLORS.TEXT_WHITE },
|
|||
|
|
];
|
|||
|
|
|
|||
|
|
stats.forEach(stat => {
|
|||
|
|
const row = new Node(`Stat_${stat.name}`);
|
|||
|
|
const rowTransform = row.addComponent(UITransform);
|
|||
|
|
rowTransform.setContentSize(new Size(380, 40));
|
|||
|
|
row.setParent(this.statsArea);
|
|||
|
|
|
|||
|
|
const nameNode = new Node('Name');
|
|||
|
|
const nameLabel = nameNode.addComponent(Label);
|
|||
|
|
nameLabel.string = stat.name;
|
|||
|
|
nameLabel.fontSize = UITheme.FONT_SIZE.MD;
|
|||
|
|
nameLabel.color = this.hexToColor(UITheme.COLORS.TEXT_GOLD);
|
|||
|
|
nameNode.setParent(row);
|
|||
|
|
|
|||
|
|
const valueNode = new Node('Value');
|
|||
|
|
const valueLabel = valueNode.addComponent(Label);
|
|||
|
|
valueLabel.string = stat.value;
|
|||
|
|
valueLabel.fontSize = UITheme.FONT_SIZE.MD;
|
|||
|
|
valueLabel.color = this.hexToColor(stat.color);
|
|||
|
|
valueNode.setParent(row);
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 装备区域
|
|||
|
|
* 六边形装备槽(武器/头盔/衣服/腰带/鞋子/坐骑)
|
|||
|
|
*/
|
|||
|
|
private initEquipmentArea() {
|
|||
|
|
if (!this.equipmentArea) return;
|
|||
|
|
|
|||
|
|
const transform = this.equipmentArea.getComponent(UITransform) || this.equipmentArea.addComponent(UITransform);
|
|||
|
|
transform.setContentSize(new Size(720, 180));
|
|||
|
|
|
|||
|
|
const slots = ['武器', '头盔', '衣服', '腰带', '鞋子', '坐骑'];
|
|||
|
|
|
|||
|
|
slots.forEach((slotName, index) => {
|
|||
|
|
const slotNode = new Node(`Slot_${slotName}`);
|
|||
|
|
const slotTransform = slotNode.addComponent(UITransform);
|
|||
|
|
slotTransform.setContentSize(new Size(100, 100));
|
|||
|
|
slotNode.setParent(this.equipmentArea);
|
|||
|
|
|
|||
|
|
// 六边形边框
|
|||
|
|
const borderNode = new Node('Border');
|
|||
|
|
const borderSprite = borderNode.addComponent(Sprite);
|
|||
|
|
borderNode.getComponent(UITransform)?.setContentSize(new Size(100, 100));
|
|||
|
|
borderNode.setParent(slotNode);
|
|||
|
|
|
|||
|
|
// 装备图标
|
|||
|
|
const iconNode = new Node('Icon');
|
|||
|
|
const iconLabel = iconNode.addComponent(Label);
|
|||
|
|
iconLabel.string = '⚔️';
|
|||
|
|
iconLabel.fontSize = UITheme.FONT_SIZE.XL;
|
|||
|
|
iconNode.setParent(slotNode);
|
|||
|
|
|
|||
|
|
// 槽位名称
|
|||
|
|
const labelNode = new Node('Label');
|
|||
|
|
const label = labelNode.addComponent(Label);
|
|||
|
|
label.string = slotName;
|
|||
|
|
label.fontSize = UITheme.FONT_SIZE.XS;
|
|||
|
|
label.color = this.hexToColor(UITheme.COLORS.TEXT_DIM);
|
|||
|
|
labelNode.setParent(slotNode);
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 物品栏区域
|
|||
|
|
* 分类标签 + 物品格子
|
|||
|
|
*/
|
|||
|
|
private initInventoryArea() {
|
|||
|
|
if (!this.inventoryArea) return;
|
|||
|
|
|
|||
|
|
const transform = this.inventoryArea.getComponent(UITransform) || this.inventoryArea.addComponent(UITransform);
|
|||
|
|
transform.setContentSize(new Size(720, 400));
|
|||
|
|
|
|||
|
|
// 分类标签栏
|
|||
|
|
const tabBar = new Node('TabBar');
|
|||
|
|
const tabLayout = tabBar.addComponent(Layout);
|
|||
|
|
tabLayout.type = Layout.Type.HORIZONTAL;
|
|||
|
|
tabBar.setParent(this.inventoryArea);
|
|||
|
|
|
|||
|
|
const tabs = ['全部', '装备', '材料', '药材', '杂物'];
|
|||
|
|
tabs.forEach(tabName => {
|
|||
|
|
const tabNode = new Node(`Tab_${tabName}`);
|
|||
|
|
const tabTransform = tabNode.addComponent(UITransform);
|
|||
|
|
tabTransform.setContentSize(new Size(120, 40));
|
|||
|
|
tabNode.setParent(tabBar);
|
|||
|
|
|
|||
|
|
const label = tabNode.addComponent(Label);
|
|||
|
|
label.string = tabName;
|
|||
|
|
label.fontSize = UITheme.FONT_SIZE.SM;
|
|||
|
|
label.color = this.hexToColor(UITheme.COLORS.TEXT_NORMAL);
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// 物品格子网格(6列 x 5行)
|
|||
|
|
const gridNode = new Node('Grid');
|
|||
|
|
const gridLayout = gridNode.addComponent(Layout);
|
|||
|
|
gridLayout.type = Layout.Type.GRID;
|
|||
|
|
gridLayout.startAxis = Layout.AxisDirection.HORIZONTAL;
|
|||
|
|
gridLayout.cellSize = new Size(100, 100);
|
|||
|
|
gridLayout.spacingX = 8;
|
|||
|
|
gridLayout.spacingY = 8;
|
|||
|
|
gridNode.setParent(this.inventoryArea);
|
|||
|
|
|
|||
|
|
for (let i = 0; i < 30; i++) {
|
|||
|
|
const itemNode = new Node(`Item_${i}`);
|
|||
|
|
const itemTransform = itemNode.addComponent(UITransform);
|
|||
|
|
itemTransform.setContentSize(new Size(100, 100));
|
|||
|
|
itemNode.setParent(gridNode);
|
|||
|
|
|
|||
|
|
// 物品背景
|
|||
|
|
const bgNode = new Node('Bg');
|
|||
|
|
bgNode.addComponent(Sprite);
|
|||
|
|
bgNode.getComponent(UITransform)?.setContentSize(new Size(100, 100));
|
|||
|
|
bgNode.setParent(itemNode);
|
|||
|
|
|
|||
|
|
// 物品图标
|
|||
|
|
const iconNode = new Node('Icon');
|
|||
|
|
const iconLabel = iconNode.addComponent(Label);
|
|||
|
|
iconLabel.string = '📦';
|
|||
|
|
iconLabel.fontSize = UITheme.FONT_SIZE.XL;
|
|||
|
|
iconNode.setParent(itemNode);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|