feat: 添加英雄界面并移除英雄卡等级概率机制

- 新增英雄界面 UI 配置、预制体和动画资源
- 在 MissionHomeComp 中添加打开英雄界面的方法
- 移除 CardSet 中英雄卡从1级升级到2级的概率逻辑,简化抽卡规则
- 在 HlistComp 中添加关闭英雄界面的方法
This commit is contained in:
walkpan
2026-04-09 09:16:55 +08:00
parent 43c5cace94
commit 36d65ac3cc
13 changed files with 20206 additions and 10239 deletions

View File

@@ -0,0 +1,405 @@
[
{
"__type__": "cc.AnimationClip",
"_name": "animation",
"_objFlags": 0,
"__editorExtras__": {
"embeddedPlayerGroups": []
},
"_native": "",
"sample": 6,
"speed": 1,
"wrapMode": 2,
"enableTrsBlending": false,
"_duration": 2,
"_hash": 500763545,
"_tracks": [
{
"__id__": 1
},
{
"__id__": 12
}
],
"_exoticAnimation": null,
"_events": [],
"_embeddedPlayers": [],
"_additiveSettings": {
"__id__": 23
},
"_auxiliaryCurveEntries": []
},
{
"__type__": "cc.animation.VectorTrack",
"_binding": {
"__type__": "cc.animation.TrackBinding",
"path": {
"__id__": 2
},
"proxy": null
},
"_channels": [
{
"__id__": 4
},
{
"__id__": 6
},
{
"__id__": 8
},
{
"__id__": 10
}
],
"_nComponents": 3
},
{
"__type__": "cc.animation.TrackPath",
"_paths": [
{
"__id__": 3
},
"eulerAngles"
]
},
{
"__type__": "cc.animation.HierarchyPath",
"path": "Effect_Lihgt_02"
},
{
"__type__": "cc.animation.Channel",
"_curve": {
"__id__": 5
}
},
{
"__type__": "cc.RealCurve",
"_times": [],
"_values": [],
"preExtrapolation": 1,
"postExtrapolation": 1
},
{
"__type__": "cc.animation.Channel",
"_curve": {
"__id__": 7
}
},
{
"__type__": "cc.RealCurve",
"_times": [],
"_values": [],
"preExtrapolation": 1,
"postExtrapolation": 1
},
{
"__type__": "cc.animation.Channel",
"_curve": {
"__id__": 9
}
},
{
"__type__": "cc.RealCurve",
"_times": [
0,
1.5,
2
],
"_values": [
{
"__type__": "cc.RealKeyframeValue",
"interpolationMode": 0,
"tangentWeightMode": 0,
"value": 0,
"rightTangent": 0,
"rightTangentWeight": 1,
"leftTangent": 0,
"leftTangentWeight": 1,
"easingMethod": 0,
"__editorExtras__": {
"tangentMode": 0
}
},
{
"__type__": "cc.RealKeyframeValue",
"interpolationMode": 0,
"tangentWeightMode": 0,
"value": -270,
"rightTangent": 0,
"rightTangentWeight": 1,
"leftTangent": 0,
"leftTangentWeight": 1,
"easingMethod": 0,
"__editorExtras__": {
"tangentMode": 0
}
},
{
"__type__": "cc.RealKeyframeValue",
"interpolationMode": 0,
"tangentWeightMode": 0,
"value": -360,
"rightTangent": 0,
"rightTangentWeight": 1,
"leftTangent": 0,
"leftTangentWeight": 1,
"easingMethod": 0,
"__editorExtras__": {
"tangentMode": 0
}
}
],
"preExtrapolation": 1,
"postExtrapolation": 1
},
{
"__type__": "cc.animation.Channel",
"_curve": {
"__id__": 11
}
},
{
"__type__": "cc.RealCurve",
"_times": [],
"_values": [],
"preExtrapolation": 1,
"postExtrapolation": 1
},
{
"__type__": "cc.animation.VectorTrack",
"_binding": {
"__type__": "cc.animation.TrackBinding",
"path": {
"__id__": 13
},
"proxy": null
},
"_channels": [
{
"__id__": 15
},
{
"__id__": 17
},
{
"__id__": 19
},
{
"__id__": 21
}
],
"_nComponents": 3
},
{
"__type__": "cc.animation.TrackPath",
"_paths": [
{
"__id__": 14
},
"scale"
]
},
{
"__type__": "cc.animation.HierarchyPath",
"path": "Image_Glow_Circle_03"
},
{
"__type__": "cc.animation.Channel",
"_curve": {
"__id__": 16
}
},
{
"__type__": "cc.RealCurve",
"_times": [
0,
1,
2
],
"_values": [
{
"__type__": "cc.RealKeyframeValue",
"interpolationMode": 0,
"tangentWeightMode": 0,
"value": 1.6,
"rightTangent": 0,
"rightTangentWeight": 1,
"leftTangent": 0,
"leftTangentWeight": 1,
"easingMethod": 0,
"__editorExtras__": {
"tangentMode": 0
}
},
{
"__type__": "cc.RealKeyframeValue",
"interpolationMode": 0,
"tangentWeightMode": 0,
"value": 1.8,
"rightTangent": 0,
"rightTangentWeight": 1,
"leftTangent": 0,
"leftTangentWeight": 1,
"easingMethod": 0,
"__editorExtras__": {
"tangentMode": 0
}
},
{
"__type__": "cc.RealKeyframeValue",
"interpolationMode": 0,
"tangentWeightMode": 0,
"value": 1.6,
"rightTangent": 0,
"rightTangentWeight": 1,
"leftTangent": 0,
"leftTangentWeight": 1,
"easingMethod": 0,
"__editorExtras__": {
"tangentMode": 0
}
}
],
"preExtrapolation": 1,
"postExtrapolation": 1
},
{
"__type__": "cc.animation.Channel",
"_curve": {
"__id__": 18
}
},
{
"__type__": "cc.RealCurve",
"_times": [
0,
1,
2
],
"_values": [
{
"__type__": "cc.RealKeyframeValue",
"interpolationMode": 0,
"tangentWeightMode": 0,
"value": 1.6,
"rightTangent": 0,
"rightTangentWeight": 1,
"leftTangent": 0,
"leftTangentWeight": 1,
"easingMethod": 0,
"__editorExtras__": {
"tangentMode": 0
}
},
{
"__type__": "cc.RealKeyframeValue",
"interpolationMode": 0,
"tangentWeightMode": 0,
"value": 1.8,
"rightTangent": 0,
"rightTangentWeight": 1,
"leftTangent": 0,
"leftTangentWeight": 1,
"easingMethod": 0,
"__editorExtras__": {
"tangentMode": 0
}
},
{
"__type__": "cc.RealKeyframeValue",
"interpolationMode": 0,
"tangentWeightMode": 0,
"value": 1.6,
"rightTangent": 0,
"rightTangentWeight": 1,
"leftTangent": 0,
"leftTangentWeight": 1,
"easingMethod": 0,
"__editorExtras__": {
"tangentMode": 0
}
}
],
"preExtrapolation": 1,
"postExtrapolation": 1
},
{
"__type__": "cc.animation.Channel",
"_curve": {
"__id__": 20
}
},
{
"__type__": "cc.RealCurve",
"_times": [
0,
1,
2
],
"_values": [
{
"__type__": "cc.RealKeyframeValue",
"interpolationMode": 0,
"tangentWeightMode": 0,
"value": 1,
"rightTangent": 0,
"rightTangentWeight": 1,
"leftTangent": 0,
"leftTangentWeight": 1,
"easingMethod": 0,
"__editorExtras__": {
"tangentMode": 0
}
},
{
"__type__": "cc.RealKeyframeValue",
"interpolationMode": 0,
"tangentWeightMode": 0,
"value": 1,
"rightTangent": 0,
"rightTangentWeight": 1,
"leftTangent": 0,
"leftTangentWeight": 1,
"easingMethod": 0,
"__editorExtras__": {
"tangentMode": 0
}
},
{
"__type__": "cc.RealKeyframeValue",
"interpolationMode": 0,
"tangentWeightMode": 0,
"value": 1,
"rightTangent": 0,
"rightTangentWeight": 1,
"leftTangent": 0,
"leftTangentWeight": 1,
"easingMethod": 0,
"__editorExtras__": {
"tangentMode": 0
}
}
],
"preExtrapolation": 1,
"postExtrapolation": 1
},
{
"__type__": "cc.animation.Channel",
"_curve": {
"__id__": 22
}
},
{
"__type__": "cc.RealCurve",
"_times": [],
"_values": [],
"preExtrapolation": 1,
"postExtrapolation": 1
},
{
"__type__": "cc.AnimationClipAdditiveSettings",
"enabled": false,
"refClip": null
}
]

View File

@@ -0,0 +1,13 @@
{
"ver": "2.0.3",
"importer": "animation-clip",
"imported": true,
"uuid": "1a0edaaf-b1c5-4a43-a874-afb780a978b3",
"files": [
".cconb"
],
"subMetas": {},
"userData": {
"name": "animation"
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,13 @@
{
"ver": "1.1.50",
"importer": "prefab",
"imported": true,
"uuid": "6e63f83d-28f6-415e-ac98-dabef66282d6",
"files": [
".json"
],
"subMetas": {},
"userData": {
"syncNodeName": "heros"
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 282 KiB

After

Width:  |  Height:  |  Size: 291 KiB

View File

@@ -63,8 +63,6 @@ export const CARD_POOL_MAX_LEVEL = CardLV.LV5
/** 英雄最高等级限制 */ /** 英雄最高等级限制 */
export const CARD_HERO_MAX_LEVEL = 3 export const CARD_HERO_MAX_LEVEL = 3
/** 基础卡池(英雄、技能、功能) */ /** 基础卡池(英雄、技能、功能) */
export const HERO_LV2_INIT_PROB = 0
export const HERO_LV2_PROB_INC_PER_LV = 0.02
export const CardPoolList: CardConfig[] = [ export const CardPoolList: CardConfig[] = [
{ uuid: 5001, type: CardType.Hero, cost: 3, weight: 25, pool_lv: 1, kind: CKind.Hero, hero_lv: 1 }, { uuid: 5001, type: CardType.Hero, cost: 3, weight: 25, pool_lv: 1, kind: CKind.Hero, hero_lv: 1 },
@@ -186,20 +184,6 @@ const pickCards = (cards: CardConfig[], count: number): CardConfig[] => {
return selected return selected
} }
/** 根据概率尝试将抽到的英雄卡的 hero_lv 提升到 2 */
const applyHeroLv2Probability = (cards: CardConfig[], currentPoolLv: number): CardConfig[] => {
return cards.map(card => {
if (card.type === CardType.Hero && card.hero_lv === 1) {
const prob = HERO_LV2_INIT_PROB + HERO_LV2_PROB_INC_PER_LV * (currentPoolLv - card.pool_lv)
if (Math.random() < prob) {
// 升级到2级时花费呈指数增长 (1级cost * MERGE_NEED^(2-1))
return { ...card, hero_lv: 2, cost: card.cost * Math.pow(FightSet.MERGE_NEED, 1) }
}
}
return card
})
}
/** 获取指定等级可出现的基础卡池 */ /** 获取指定等级可出现的基础卡池 */
export const getCardPoolByLv = (lv: number, onlyCurrentLv: boolean = false): CardConfig[] => { export const getCardPoolByLv = (lv: number, onlyCurrentLv: boolean = false): CardConfig[] => {
const cardLv = clampCardLv(lv) const cardLv = clampCardLv(lv)
@@ -224,13 +208,13 @@ export const getCardsByLv = (
if (type !== undefined) { if (type !== undefined) {
const typeSet = normalizeTypeFilter(type) const typeSet = normalizeTypeFilter(type)
const filteredPool = pool.filter(card => typeSet.has(card.type)) const filteredPool = pool.filter(card => typeSet.has(card.type))
return applyHeroLv2Probability(pickCards(filteredPool, 4), lv) return pickCards(filteredPool, 4)
} }
const heroPool = pool.filter(card => card.type === CardType.Hero) const heroPool = pool.filter(card => card.type === CardType.Hero)
const otherPool = pool.filter(card => card.type !== CardType.Hero) const otherPool = pool.filter(card => card.type !== CardType.Hero)
const heroes = pickCards(heroPool, 2) const heroes = pickCards(heroPool, 2)
const others = pickCards(otherPool, 2) const others = pickCards(otherPool, 2)
return applyHeroLv2Probability([...heroes, ...others], lv) return [...heroes, ...others]
} }
export const drawCardsByRule = ( export const drawCardsByRule = (
@@ -270,9 +254,5 @@ export const drawCardsByRule = (
}) })
} }
const picked = pickCards(pool, count) const picked = pickCards(pool, count)
// 如果明确指定了需要的 heroLv则不触发升级概率 return picked
if (options.heroLv !== undefined) {
return picked
}
return applyHeroLv2Probability(picked, lv)
} }

View File

@@ -18,6 +18,7 @@ export enum UIID {
IBox, IBox,
Notity, Notity,
Ranks, Ranks,
Heros,
} }
/** 打开界面方式的配置数据 */ /** 打开界面方式的配置数据 */
@@ -29,4 +30,5 @@ export var UIConfigData: { [key: number]: UIConfig } = {
[UIID.IBox]: { layer: LayerType.UI, prefab: "gui/element/ibox" }, [UIID.IBox]: { layer: LayerType.UI, prefab: "gui/element/ibox" },
[UIID.Notity]: { layer: LayerType.UI, prefab: "gui/element/notity" }, [UIID.Notity]: { layer: LayerType.UI, prefab: "gui/element/notity" },
[UIID.Ranks]: { layer: LayerType.UI, prefab: "gui/element/ranks" }, [UIID.Ranks]: { layer: LayerType.UI, prefab: "gui/element/ranks" },
[UIID.Heros]: { layer: LayerType.UI, prefab: "gui/element/heros" },
} }

View File

@@ -25,6 +25,7 @@ import { HeroInfo, HeroList } from "../common/config/heroSet";
import { IType, SkillSet } from "../common/config/SkillSet"; import { IType, SkillSet } from "../common/config/SkillSet";
import { oops } from "db://oops-framework/core/Oops"; import { oops } from "db://oops-framework/core/Oops";
import { mLogger } from "../common/Logger"; import { mLogger } from "../common/Logger";
import { UIID } from "../common/config/GameUIConfig";
const {property, ccclass } = _decorator; const {property, ccclass } = _decorator;
@@ -96,7 +97,14 @@ export class HListComp extends CCComp {
this.pre_btn?.on(NodeEventType.TOUCH_END, this.onPreClick, this); this.pre_btn?.on(NodeEventType.TOUCH_END, this.onPreClick, this);
this.next_btn?.on(NodeEventType.TOUCH_END, this.onNextClick, this); this.next_btn?.on(NodeEventType.TOUCH_END, this.onNextClick, this);
} }
/** 预留:弹窗打开时接收参数 */
onAdded(args: any) {
}
/** 关闭排行榜弹窗 */
closeHeros(){
oops.gui.remove(UIID.Ranks)
}
start() { start() {
// 初始化轮播节点数组和固定位置 // 初始化轮播节点数组和固定位置
if (this.phero1_icon && this.phero_icon && this.hero_icon && this.nhero_icon && this.nhero1_icon) { if (this.phero1_icon && this.phero_icon && this.hero_icon && this.nhero_icon && this.nhero1_icon) {

View File

@@ -83,7 +83,9 @@ export class MissionHomeComp extends CCComp {
openRanks(){ openRanks(){
oops.gui.open(UIID.Ranks) oops.gui.open(UIID.Ranks)
} }
openHero(){
oops.gui.open(UIID.Heros)
}
/** 任务结束回调:重新显示主页 */ /** 任务结束回调:重新显示主页 */
mission_end(){ mission_end(){
mLogger.log(this.debugMode, 'MissionHomeComp', "[MissionHomeComp]=>mission_end") mLogger.log(this.debugMode, 'MissionHomeComp', "[MissionHomeComp]=>mission_end")