Skip to content

03 - L1 Cocos 兼容层详细设计

返回目录 | 上一章


3.1 设计原则

  1. 接口一致性:C# 方法签名与 JS 保持语义一致,仅命名风格从 camelCase 转为 PascalCase
  2. 无业务逻辑:L1 只做 API 翻译,不包含任何 Slot 业务语义
  3. 静态无状态:所有方法为 static 方法,不持有实例状态
  4. Unity 原生:内部实现使用 Unity 原生 API(DOTween、Transform、Animator 等)
  5. 容错一致:保持与 JS 版本相同的空值保护行为(JS 版本大量使用 cc.sys.isObjectValid 检查)

3.2 文件规划

所有 L1 文件位于:Assets/Project/AddressableRes/Scripts/framework/slot/compat2022/Core/ 下各子目录

文件目录命名空间映射源实现优先级
CCCompat.csCore/Bridge/WTC.Slot.Compat2022.Core.Bridgecc.p/cc.color/cc.size/cc.sys/cc.is*P0 — 零依赖基础
CCAction.csCore/Bridge/WTC.Slot.Compat2022.Core.Bridgecc.sequence/moveTo/callFunc... → DOTweenP0 — 高频核心
NodeHelper.csCore/Utils/WTC.Slot.Compat2022.Core.Utilsgame.nodeHelper.*P1 — 最高调用量
GameUtil.csCore/Utils/WTC.Slot.Compat2022.Core.Utilsgame.util.*P1 — 核心工具
SlotUtil.csCore/Utils/WTC.Slot.Compat2022.Core.Utilsgame.slotUtil.*P1 — Slot 专用
ActivityUtil.csCore/Utils/WTC.Slot.Compat2022.Core.Utilsgame.aUtil.*P2
NameBinder.csCore/Contrller/WTC.Slot.Compat2022.Core.Controller.controller._ 自动绑定P1 — 高频绑定
UIHelper.csCore/Utils/WTC.Slot.Compat2022.Core.Utilsgame.uIHelper.*P2
EventDispatcher.csCore/(根)WTC.Slot.Compat2022.Coregame.eventDispatcher.*P2
AudioBridge.csCore/Bridge/WTC.Slot.Compat2022.Core.Bridgegame.audioPlayer.*P2
DialogBridge.csCore/Bridge/WTC.Slot.Compat2022.Core.Bridgegame.dialogManager.*P3
SlotPopupUtil.csCore/Utils/WTC.Slot.Compat2022.Core.Utilsgame.slotPopupUtil.*P3
WinEffectHelper.csCore/Utils/WTC.Slot.Compat2022.Core.Utilsgame.winEffectHelper.*P3
HighRollerSlotUtil.csCore/Utils/WTC.Slot.Compat2022.Core.Utilsgame.highRollerSlotUtil.*P3

3.3 完整 API 映射表

映射表格式说明

每个 API 的映射条目包含:

说明
JS APIJavaScript 中的完整方法调用
C# 方法对应的 C# 静态方法签名
Unity 实现策略内部使用的 Unity API 或实现思路
调用次数源代码库中的总调用次数
状态待实现 / 已实现 / 不需要(C# 天然解决)

执行规范:每实现一个方法,必须将状态从 待实现 更新为 已实现,并补充实际的 C# 方法签名。 参见 07-execution-standards.md 第 7.1 节。


3.3.1 CCCompat.cs — 类型、几何与系统兼容

JS 源:Cocos2d 引擎内置 cc.*
C# 文件CCCompat.cs
调用总量:~25,000+

几何构造

JS APIC# 方法Unity 实现策略次数状态
cc.p(x, y)CC.P(float x, float y)Vector2new Vector2(x, y)4,815待实现
cc.size(w, h)CC.Size(float w, float h)Vector2new Vector2(w, h)970待实现
cc.color(r, g, b, a)CC.Color(int r, int g, int b, int a)Colornew Color(r/255f, g/255f, b/255f, a/255f)643待实现
cc.rect(x, y, w, h)CC.Rect(float x, float y, float w, float h)Rectnew Rect(x, y, w, h)73待实现

点运算

JS APIC# 方法Unity 实现策略次数状态
cc.pAdd(p1, p2)CC.PAdd(Vector2, Vector2)Vector2p1 + p2136待实现
cc.pSub(p1, p2)CC.PSub(Vector2, Vector2)Vector2p1 - p235待实现
cc.pMult(p, f)CC.PMult(Vector2, float)Vector2p * f22待实现
cc.pNormalize(p)CC.PNormalize(Vector2)Vector2p.normalized27待实现
cc.pDistance(p1, p2)CC.PDistance(Vector2, Vector2)floatVector2.Distance(p1, p2)16待实现
cc.pLength(p)CC.PLength(Vector2)floatp.magnitude14待实现
cc.pToAngle(p)CC.PToAngle(Vector2)floatMathf.Atan2(p.y, p.x)3待实现
cc.pMidpoint(p1, p2)CC.PMidpoint(Vector2, Vector2)Vector2(p1 + p2) * 0.5f7待实现
cc.pointEqualToPoint(p1, p2)CC.PointEqual(Vector2, Vector2)boolVector2.Distance < epsilon7待实现
cc.pLerp(p1, p2, t)CC.PLerp(Vector2, Vector2, float)Vector2Vector2.Lerp(p1, p2, t)2待实现
cc.pDot(p1, p2)CC.PDot(Vector2, Vector2)floatVector2.Dot(p1, p2)1待实现

矩形运算

JS APIC# 方法Unity 实现策略次数状态
cc.rectContainsPoint(rect, p)CC.RectContainsPoint(Rect, Vector2)boolrect.Contains(p)75待实现
cc.rectIntersectsRect(r1, r2)CC.RectIntersects(Rect, Rect)boolr1.Overlaps(r2)11待实现
cc.rectOverlapsRect(r1, r2)CC.RectOverlaps(Rect, Rect)boolr1.Overlaps(r2)2待实现

类型检查

JS APIC# 方法Unity 实现策略次数状态
cc.sys.isObjectValid(obj)CC.IsValid(object)boolobj != null;如果是 UnityEngine.Object 则用隐式 bool4,108待实现
cc.isFunction(obj)CC.IsFunction(object)boolobj is Delegateobj is Action1,103待实现
cc.isUndefined(obj)CC.IsUndefined(object)boolobj == null998待实现
cc.isNumber(obj)CC.IsNumber(object)boolobj is int or float or double or long522待实现
cc.isArray(obj)CC.IsArray(object)boolobj is IList447待实现
cc.isObject(obj)CC.IsObject(object)boolobj != null && !(obj is ValueType)94待实现
cc.isString(obj)CC.IsString(object)boolobj is string87待实现

系统信息

JS APIC# 方法Unity 实现策略次数状态
cc.sys.isNativeCC.IsNativebool!Application.isEditor(或平台判断)715待实现
cc.sys.osCC.SysOSstringApplication.platform 映射131待实现
cc.sys.OS_IOSCC.OS_IOSstring"iOS" 常量74待实现
cc.sys.OS_ANDROIDCC.OS_ANDROIDstring"Android" 常量53待实现
cc.sys.openURL(url)CC.OpenURL(string)Application.OpenURL(url)36待实现
cc.sys.localStorageCC.LocalStoragePlayerPrefs 封装4待实现
cc.sys.garbageCollect()CC.GarbageCollect()System.GC.Collect()4待实现
cc.sys.isMobileCC.IsMobileboolApplication.isMobilePlatform2待实现

数学工具

JS APIC# 方法Unity 实现策略次数状态
cc.clampf(v, min, max)CC.Clampf(float, float, float)floatMathf.Clamp(v, min, max)8待实现
cc.random0To1()CC.Random01()floatUnityEngine.Random.value7待实现
cc.lerp(a, b, t)CC.Lerp(float, float, float)floatMathf.Lerp(a, b, t)4待实现
cc.radiansToDegrees(r)CC.RadToDeg(float)floatr * Mathf.Rad2Deg1待实现

不需要映射(C# 天然解决)

JS API次数C# 替代
cc.each(arr, func)845foreach 循环
cc.log(...)2,910Debug.Log(...)
cc.error(...)617Debug.LogError(...)
cc.warn(...)608Debug.LogWarning(...)
cc.assert(...)14Debug.Assert(...)
cc.extend(target, src)26对象初始化器或手动赋值
cc.arrayRemoveObject(arr, obj)2list.Remove(obj)
cc.copyArray(arr)1new List<T>(arr)

3.3.2 CCAction.cs — 动作链 → DOTween Sequence

JS 源:Cocos2d 引擎内置 cc.* 动作系统
C# 文件CCAction.cs
依赖:DOTween Pro
调用总量:~9,256 (动作) + ~324 (easing) + ~3,124 (runAction)

核心设计

csharp
// JS 模式:
node.runAction(cc.sequence(
    cc.delayTime(0.5),
    cc.moveTo(0.3, cc.p(100, 200)),
    cc.callFunc(function() { ... })
));

// C# 映射:
CCAction.RunAction(transform, CCAction.Sequence(
    CCAction.DelayTime(0.5f),
    CCAction.MoveTo(0.3f, new Vector2(100, 200)),
    CCAction.CallFunc(() => { ... })
));

// 内部实现:构建并播放一个 DOTween Sequence

容器动作

JS APIC# 方法DOTween 映射次数状态
cc.sequence(a1, a2, ...)CCAction.Sequence(params ITweenAction[])DOTween.Sequence().Append(...) 依次串接2,183待实现
cc.spawn(a1, a2, ...)CCAction.Spawn(params ITweenAction[])DOTween.Sequence().Join(...) 并行94待实现
cc.repeat(action, times)CCAction.Repeat(ITweenAction, int)SetLoops(times)2待实现
cc.repeatForever(action)CCAction.RepeatForever(ITweenAction)SetLoops(-1)62待实现
cc.speed(action, speed)CCAction.Speed(ITweenAction, float)SetTimeScale(speed)1待实现
node.runAction(action)CCAction.RunAction(Transform, ITweenAction)构建 Sequence 并 Play3,124待实现
node.stopAllActions()CCAction.StopAll(Transform)DOTween.Kill(transform)待统计待实现
node.stopAction(action)CCAction.Stop(Tween)tween.Kill()待统计待实现

即时动作

JS APIC# 方法DOTween 映射次数状态
cc.callFunc(func, target, data)CCAction.CallFunc(Action)AppendCallback(func)2,781待实现
cc.show()CCAction.Show()AppendCallback(() => go.SetActive(true))42待实现
cc.hide()CCAction.Hide()AppendCallback(() => go.SetActive(false))68待实现
cc.removeSelf()CCAction.RemoveSelf()AppendCallback(() => Destroy(go))33待实现
cc.place(x, y)CCAction.Place(Vector2)AppendCallback(() => transform.localPosition = pos)5待实现

间隔动作

JS APIC# 方法DOTween 映射次数状态
cc.delayTime(d)CCAction.DelayTime(float)AppendInterval(d)2,373待实现
cc.moveTo(d, pos)CCAction.MoveTo(float, Vector2)DOLocalMove(pos, d)643待实现
cc.moveBy(d, delta)CCAction.MoveBy(float, Vector2)DOLocalMove(current+delta, d)164待实现
cc.scaleTo(d, sx, sy)CCAction.ScaleTo(float, float, float?)DOScale(new Vector3(sx,sy,1), d)353待实现
cc.scaleBy(d, sx, sy)CCAction.ScaleBy(float, float, float?)DOScale(current*s, d)8待实现
cc.fadeTo(d, opacity)CCAction.FadeTo(float, float)DOFade(opacity/255f, d) on CanvasGroup/SpriteRenderer79待实现
cc.fadeIn(d)CCAction.FadeIn(float)DOFade(1f, d)108待实现
cc.fadeOut(d)CCAction.FadeOut(float)DOFade(0f, d)71待实现
cc.rotateTo(d, angle)CCAction.RotateTo(float, float)DOLocalRotate(new Vector3(0,0,-angle), d)32待实现
cc.rotateBy(d, angle)CCAction.RotateBy(float, float)DOLocalRotate(delta, d, RotateMode.LocalAxisAdd)28待实现
cc.bezierTo(d, points)CCAction.BezierTo(float, Vector2[])DOLocalPath(path, d, PathType.CubicBezier)233待实现
cc.bezierBy(d, points)CCAction.BezierBy(float, Vector2[])类似,基于相对偏移1待实现
cc.jumpTo(d, pos, h, jumps)CCAction.JumpTo(float, Vector2, float, int)DOLocalJump(pos, h, jumps, d)20待实现
cc.tintTo(d, r, g, b)CCAction.TintTo(float, Color)DOColor(color, d) on SpriteRenderer27待实现
cc.progressTo(d, percent)CCAction.ProgressTo(float, float)DOValue(percent, d) on Slider/Image.fillAmount223待实现
cc.progressFromTo(d, from, to)CCAction.ProgressFromTo(float, float, float)DOValue with from/to3待实现
cc.animate(anim)CCAction.Animate(AnimationClip)Animator 播放9待实现
cc.orbitCamera(d, ...)CCAction.OrbitCamera(...)自定义旋转 Tween4待实现

Easing 函数

JS APIC# 映射DOTween Ease次数状态
action.easing(cc.easeIn(rate)).SetEase(Ease.InQuad)rate≈2: InQuad, rate≈3: InCubic119待实现
cc.easeOut(rate).SetEase(Ease.OutQuad)同上映射21待实现
cc.easeInOut(rate).SetEase(Ease.InOutQuad)同上映射30待实现
cc.easeBackOut().SetEase(Ease.OutBack)50待实现
cc.easeBackIn().SetEase(Ease.InBack)4待实现
cc.easeBackInOut().SetEase(Ease.InOutBack)3待实现
cc.easeSineIn().SetEase(Ease.InSine)11待实现
cc.easeSineOut().SetEase(Ease.OutSine)13待实现
cc.easeSineInOut().SetEase(Ease.InOutSine)21待实现
cc.easeBounceOut().SetEase(Ease.OutBounce)20待实现
cc.easeElasticOut().SetEase(Ease.OutElastic)4待实现
cc.easeExponentialOut().SetEase(Ease.OutExpo)6待实现
cc.easeExponentialIn().SetEase(Ease.InExpo)2待实现
cc.easeExponentialInOut().SetEase(Ease.InOutExpo)5待实现
cc.easeCircleActionOut().SetEase(Ease.OutCirc)5待实现
cc.easeBezierAction(a,b,c,d).SetEase(AnimationCurve)自定义贝塞尔曲线8待实现
cc.easeQuadraticActionInOut().SetEase(Ease.InOutQuad)2待实现

ITweenAction 接口设计

csharp
// 所有 CCAction 方法返回 ITweenAction,用于组合
public interface ITweenAction
{
    void ApplyTo(Sequence seq, Transform target);
}

// 使用示例
CCAction.RunAction(transform, CCAction.Sequence(
    CCAction.DelayTime(0.5f),
    CCAction.MoveTo(0.3f, new Vector2(100, 200)).Easing(Ease.OutBack),
    CCAction.CallFunc(() => Debug.Log("done"))
));

3.3.3 NodeHelper.cs — 节点操作

JS 源src/common/util/NodeHelper.js (491 行)
C# 文件NodeHelper.cs
调用总量:~17,283

JS APIC# 方法Unity 实现策略次数状态
setNodeVisible(node, visible)NodeHelper.SetVisible(GameObject, bool)go.SetActive(visible)10,105待实现
setNodeText(node, text, isScaleY)NodeHelper.SetText(Component, string, bool)TMP_Text.text = text;如有 __oriLabelScale 则自动缩放2,692待实现
setNodeEnabled(node, enabled)NodeHelper.SetEnabled(Component, bool)Selectable.interactable 或自定义 ISetEnabled1,929待实现
setSpriteFrameName(sprite, name)NodeHelper.SetSpriteFrame(Image, string)image.sprite = Resources.Load<Sprite>(name) 或 Addressable726待实现
setNodePosition(node, pos)NodeHelper.SetPosition(Transform, Vector2)transform.localPosition = pos315待实现
removeCCBFromParent(node, cleanup)NodeHelper.RemoveFromParent(GameObject, bool)Destroy(go) 或回收到池301待实现
setNodeLocalZOrder(node, z)NodeHelper.SetZOrder(Transform, int)transform.SetSiblingIndex(z)283待实现
removeNodeFromParent(node, cleanup)NodeHelper.RemoveNode(GameObject, bool)Destroy(go)187待实现
setNodeColor(node, color)NodeHelper.SetColor(Component, Color)Graphic.color = colorSpriteRenderer.color136待实现
setCascadeColorEnabledRecursive(node, b)NodeHelper.SetCascadeColor(Transform, bool)Unity UI 天然级联颜色,可能不需要操作110待实现
setNodeOpacity(node, opacity)NodeHelper.SetOpacity(Component, float)CanvasGroup.alphacolor.a103待实现
setNodeRotationSafe(node, rot)NodeHelper.SetRotation(Transform, float)transform.localEulerAngles = new Vector3(0,0,-rot)88待实现
makeTouchable(node, swallow, priority)NodeHelper.MakeTouchable(GameObject, bool, int)添加 Graphic.raycastTarget = true 或 EventTrigger79待实现
autoAlignNodes(nodes, groupI, innerI, cx)NodeHelper.AutoAlign(Transform[], float, float, float)计算总宽度后居中排列65待实现
setCascadeOpacityEnabledRecursive(node, b)NodeHelper.SetCascadeOpacity(Transform, bool)CanvasGroup 控制级联透明57待实现
setNodeScale(node, sx, sy)NodeHelper.SetScale(Transform, float, float?)transform.localScale = new Vector3(sx, sy ?? sx, 1)55待实现
isNodeVisible(node)NodeHelper.IsVisible(GameObject)bool遍历父链检查 activeSelf22待实现
setNodeOpacityRecursive(node, opacity)NodeHelper.SetOpacityRecursive(Transform, float)递归设置所有子节点透明度16待实现
setNodeTextAutoChangeLine(node, text, maxW, align)NodeHelper.SetTextAutoWrap(TMP_Text, string, float, TextAlignmentOptions)TMP 自动换行 + rectTransform.sizeDelta8待实现
disableMultiTouch(rootNode)NodeHelper.DisableMultiTouch(GameObject)Input.multiTouchEnabled = false 或自定义2待实现
autoAlignTextNodes(nodes, outerI, innerI, cx)NodeHelper.AutoAlignText(Transform[], float, float, float)类似 autoAlignNodes,处理嵌套文本+图标组合2待实现
verticalAlignNodes(nodes, interval, cy)NodeHelper.VerticalAlign(Transform[], float, float)垂直居中排列1待实现
stopNodeAction(node)NodeHelper.StopAction(Transform)DOTween.Kill(transform)1待实现

3.3.4 GameUtil.cs — 核心工具方法

JS 源src/common/util/Util.js (1805 行)
C# 文件GameUtil.cs
调用总量:~31,237(扣除不需要映射的 inherits/registerController 后约 ~22,000)

动画与 CCB

JS APIC# 方法Unity 实现策略次数状态
playAnim(node, name, target, cb, arg)GameUtil.PlayAnim(GameObject, string, Action)Animator.Play(name) + 回调等待动画结束7,369待实现
playCCBAnimation(node, name, target, cb, arg)GameUtil.PlayCCBAnim(GameObject, string, Action)同 PlayAnim(DEPRECATED 版本,内部转发)2,647待实现
playDefaultAnim(node, target, cb, arg)GameUtil.PlayDefaultAnim(GameObject, Action)Animator.Play("default")50待实现
isCCBHasAnimation(node, name)GameUtil.HasAnimation(GameObject, string)bool检查 Animator 是否含指定 State124待实现
loadNodeFromCCB(ccb, parent, ctrl, ctrlNode)GameUtil.LoadPrefab(string, Transform, ...)GameObjectAddressables.InstantiateAsyncInstantiate(prefab) + NameBinder2,186待实现
loadNodeFromSpine(spine, skin)GameUtil.LoadSpine(string, string)GameObjectSpine-Unity runtime 加载26待实现
animManRunSeqName(node, seqName)GameUtil.RunAnimSeq(GameObject, string)Animator.Play(seqName)459待实现
animManRunSeqId(node, seqId, duration)GameUtil.RunAnimSeqById(GameObject, int, float)根据 ID 播放(需建立映射)41待实现
seekNodeByTag(root, tag)GameUtil.SeekByTag(Transform, int)Transform递归 Transform.Find 或预建 tag 索引1,841待实现
recordLabelScale(label)GameUtil.RecordLabelScale(TMP_Text)存储原始 scale/width 到自定义组件242待实现
recordCCLabelScale(label)GameUtil.RecordCCLabelScale(TMP_Text)同上32待实现

字符串格式化

JS APIC# 方法Unity 实现策略次数状态
sprintf(fmt, ...)GameUtil.Sprintf(string, params object[])string.Format() 适配 %d/%s/%f 格式1,281待实现
getCommaNum(num)GameUtil.GetCommaNum(long)stringnum.ToString("N0")818待实现
formatAbbrNumAutoComma(num, round)GameUtil.FormatAbbrAuto(double, ...)stringK/M/B/T 缩写 + 自动小数675待实现
formatAbbrNumOneComma(num, round)GameUtil.FormatAbbrOne(double, ...)string最多 1 位小数136待实现
formatAbbrNumWithoutComma(num, round)GameUtil.FormatAbbrInt(double, ...)string无小数44待实现
formatAbbrNumThreeComma(num, round)GameUtil.FormatAbbrThree(double, ...)string最多 3 位小数3待实现
formatAbbrNumWithPrecision(num, r, p)GameUtil.FormatAbbrPrecision(double, ...)string可配精度5待实现
formatNumForSlotMachine(num, round)GameUtil.FormatSlotNum(double, ...)string3+ 位整数无小数49待实现
getFormatTime(ms, showH, showD)GameUtil.FormatTime(long, bool, bool)stringTimeSpan 格式化422待实现
getFormatTimeDays(ms, ...)GameUtil.FormatTimeDays(long, ...)string"X DAYS HH:MM:SS"75待实现
getFormatTimeDaysPlus(ms, ...)GameUtil.FormatTimeDaysPlus(long, ...)string"Xd Yh"63待实现
getFormatDate(fmt, date)GameUtil.FormatDate(string, DateTime)stringDateTime.ToString(fmt)6待实现
getTwoDigit(num)GameUtil.TwoDigit(int)stringnum.ToString("D2")34待实现
getRankSuffix(rank, upper)GameUtil.RankSuffix(int, bool)string1st/2nd/3rd/4th...14待实现
omitText(text, maxLen)GameUtil.OmitText(string, int)string截断 + "..."16待实现

数学与随机

JS APIC# 方法Unity 实现策略次数状态
floorPrecision(num)GameUtil.FloorPrecision(double)longMath.Floor(num + 1e-11)871待实现
ceilPrecision(num)GameUtil.CeilPrecision(double)longMath.Ceiling(num - 1e-11)131待实现
randomNextInt(upper)GameUtil.RandomInt(int)intUnityEngine.Random.Range(0, upper)227待实现
randomNextIntInRange(lower, upper)GameUtil.RandomRange(int, int)intRandom.Range(lower, upper)85待实现
shuffle2(array)GameUtil.Shuffle<T>(List<T>)Fisher-Yates 原地洗牌180待实现
deepCopyObject(target, source)GameUtil.DeepCopy<T>(T)TJSON 序列化/反序列化 或手动深拷贝447待实现
deepClone(obj)GameUtil.DeepClone<T>(T)T同上112待实现
clone(obj)GameUtil.Clone<T>(T)TMemberwiseClone72待实现
arrContain(arr, elem)GameUtil.Contains<T>(IList<T>, T)boollist.Contains(elem)16待实现

标签缩放

JS APIC# 方法Unity 实现策略次数状态
scaleCCLabelBMFont(label, maxW, defScale)GameUtil.ScaleLabel(TMP_Text, float, float)根据文本宽度计算缩放3待实现
scaleCCLabelBMFontWithOriScale(l, w, s, sy)GameUtil.ScaleLabelOri(TMP_Text, float, float, float)保持原始比例缩放7待实现

延迟调用

JS APIC# 方法Unity 实现策略次数状态
delayCall(sec, cb, node, tag, arg)GameUtil.DelayCall(float, Action, ...)DOVirtual.DelayedCall(sec, cb) 或 Coroutine418待实现
delayCallWithTarget(sec, target, cb, ...)GameUtil.DelayCallTarget(float, object, Action, ...)同上,带目标生命周期绑定125待实现
cancelDelayCall(tag, node)GameUtil.CancelDelay(int, ...)Kill 对应 Tween20待实现

文件与资源

JS APIC# 方法Unity 实现策略次数状态
isFileExist(fileName)GameUtil.FileExists(string)boolAddressables.GetDownloadSizeAsync 或 Resources 检查261待实现
loadJson(url)GameUtil.LoadJson<T>(string)TJsonUtility.FromJsonNewtonsoft.Json27待实现

平台与设备

JS APIC# 方法Unity 实现策略次数状态
isAndroidOneSixAdapter()GameUtil.IsAndroid16Ratio()boolScreen.width / Screen.height 计算71待实现
getScreenSize()GameUtil.GetScreenSize()Vector2new Vector2(Screen.width, Screen.height)待统计待实现

不需要映射(C# 天然解决)

JS API次数C# 替代
inherits(Sub, Super)4,170class Sub : Super
registerController(name, cls)2,561NameBinder 替代
unRegisterController(name)2,547NameBinder 替代
getCurrentTime()待统计DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()

3.3.5 SlotUtil.cs — Slot 专用工具

JS 源src/newdesign_slot/tools/SlotUtil.js (1211 行)
C# 文件SlotUtil.cs
调用总量:~10,199

动画与音效

JS APIC# 方法Unity 实现策略次数状态
playAnim(node, name, ...cbs)SlotUtil.PlayAnim(GameObject, string, params Action[])Animator 播放 + 多回调链接3,927待实现
playAnimEasy(node, name, ...cbs)SlotUtil.PlayAnimEasy(GameObject, string, params Action[])同上,静默忽略无效节点731待实现
playEffect(name, loop)SlotUtil.PlayEffect(string, bool)AudioBridge 播放音效1,566待实现
stopEffect(name)SlotUtil.StopEffect(string)AudioBridge 停止音效146待实现
stopMusic()SlotUtil.StopMusic()AudioBridge 停止背景音乐44待实现
playChipsUpEffect(duration)SlotUtil.PlayChipsUpEffect(float)播放筹码上升音效5待实现

延迟与流控制

JS APIC# 方法Unity 实现策略次数状态
delayCall(sec, func, name)SlotUtil.DelayCall(float, Action, string)DOVirtual.DelayedCall 绑定到当前 SlotMachine 生命周期1,312待实现
cancelDelayCallByName(name)SlotUtil.CancelDelay(string)Kill 指定名称的 Tween91待实现
clearDelayCall()SlotUtil.ClearAllDelay()Kill 所有关联 Tween3待实现
createFlow(handler, name)SlotUtil.CreateFlow(Action<Action>, string)SlotFlow异步流控制(串行回调队列)626待实现

飞行动画

JS APIC# 方法Unity 实现策略次数状态
flyItemByWorldPos(node, root, from, to, d, cb, pre, mid, ease)SlotUtil.FlyByWorldPos(...)贝塞尔曲线 DOTween 动画59待实现
flyItem(node, from, to, d, cb, pre)SlotUtil.FlyItem(...)同上简化版19待实现
flyCCBItem(ccb, root, from, to, d, cb, pre, mid, ease)SlotUtil.FlyCCB(...)加载 Prefab + 飞行 + 销毁27待实现
flyCCBItemWithRecycle(...)SlotUtil.FlyCCBRecycle(...)飞行 + 对象池回收64待实现
flyCCBItemWithCleanup(...)SlotUtil.FlyCCBCleanup(...)飞行 + 完全清理2待实现

坐标转换

JS APIC# 方法Unity 实现策略次数状态
getWorldPosition(node)SlotUtil.GetWorldPos(Transform)Vector3transform.position125待实现
getNodePosition(node, worldPos)SlotUtil.WorldToLocal(Transform, Vector3)Vector3transform.InverseTransformPoint(worldPos)39待实现
getAngle(from, to, offset)SlotUtil.GetAngle(Transform, Transform, float)floatMathf.Atan2 计算角度8待实现
getDistance(from, to)SlotUtil.GetDistance(Transform, Transform)floatVector3.Distance1待实现

文本格式

JS APIC# 方法Unity 实现策略次数状态
setNodeText(node, text)SlotUtil.SetText(Component, string)转发到 NodeHelper.SetText346待实现
setNodeTextWithForAbbrChipsAppropriate(node, chips)SlotUtil.SetChipsTextAuto(Component, double)智能缩写:100K / 10.1K / 1.01K226待实现
setNodeTextWithForAbbrChips(node, chips, type)SlotUtil.SetChipsText(Component, double, int)按类型缩写63待实现
setNodeTextForCommaChips(node, chips, modPos)SlotUtil.SetCommaChips(Component, double, bool)千分位格式91待实现
getAnimationKeyByPos(col, row, prefix)SlotUtil.AnimKeyByPos(int, int, string)string$"{prefix}_{col}_{row}"344待实现
formatAbbrNumAutoCommaFloor(chips)SlotUtil.FormatAbbrFloor(double)string缩写 + floor15待实现
padString(str, len, pad)SlotUtil.PadLeft(string, int, char)stringstr.PadLeft(len, pad)4待实现

赢分等级

JS APIC# 方法Unity 实现策略次数状态
setWinLevel(totalWin, panel)SlotUtil.SetWinLevel(double, SpinPanel)根据 bet 倍率设置 BIG/MEGA/SMALL34待实现
getWinLevel(totalWin)SlotUtil.GetWinLevel(double)int纯计算,无副作用59待实现
hasBigWin(totalWin)SlotUtil.HasBigWin(double)boolwinLevel >= BIG_WIN15待实现

遍历工具

JS APIC# 方法Unity 实现策略次数状态
traverseCell(cols, rows, func)SlotUtil.TraverseCell(int, int, Action<int,int>)双层循环7待实现
traverseCellNature(cols, rows, func)SlotUtil.TraverseCellNature(int, int, Action<int,int>)双层循环(底→顶)1待实现

杂项

JS APIC# 方法Unity 实现策略次数状态
getCurrentSlotMachine()SlotUtil.GetCurrentMachine()SlotMachineBase静态引用21待实现
getCurrentMachineConfig()SlotUtil.GetCurrentConfig()MachineConfig通过 CurrentMachine 获取21待实现
shakeScreen(d, inT, outT, scale, pos, shakeD)SlotUtil.ShakeScreen(...)DOTween.Shake14待实现
stopShakeScreen()SlotUtil.StopShake()Kill Shake Tween2待实现
randomDataFromList(list, prob)SlotUtil.WeightedRandom<T>(T[], float[])T按权重随机25待实现
getRandomFromArray(arr, count)SlotUtil.RandomPick<T>(T[], int)T[]洗牌取前 N3待实现
resetParticlePositionType(node)SlotUtil.ResetParticlePos(Transform)重置粒子系统 SimulationSpace11待实现
copyNodePerspective(anim, sprite)SlotUtil.CopyPerspective(Transform, Transform)复制 scale/rotation2待实现
sendSlotParam(cb, param)SlotUtil.SendSlotParam(Action, object)网络层转发(需协议适配)5待实现
getJackpotLevelRatioMap(subjectId)SlotUtil.GetJackpotRatios(int)Dictionary配置查表2待实现
getJackpotMaxValue(subjectId)SlotUtil.GetJackpotMax(int)double配置查表1待实现
getNewVirtualLineNum()SlotUtil.GetVirtualLineNum()int特殊关卡虚拟线数调整9待实现
recordSpinPanel(context)SlotUtil.RecordPanel(SlotMachineBase)深拷贝当前面板符号1待实现
restoreSpinPanel(context)SlotUtil.RestorePanel(SlotMachineBase)恢复面板1待实现

3.3.6 ActivityUtil.cs — 活动工具

JS 源src/task/tools/ActivityUtil.js (1784 行)
C# 文件ActivityUtil.cs
调用总量:~5,275

注:ActivityUtil 中有相当比例的方法是活动系统(Activity)专用的,不在 Slot 关卡中直接使用。 此处仅列出在 Slot 关卡代码中实际被调用的方法。完整列表见 09-appendix-api-reference.md

Slot 关卡高频使用

JS APIC# 方法Unity 实现策略次数状态
setNodeTextAutoScale(node, text, isScaleY)AUtil.SetTextAutoScale(Component, string, bool)TMP_Text + 自动宽度缩放1,248待实现
delayCallWithNode(sec, cb, root, tag, arg)AUtil.DelayCallNode(float, Action, GameObject, int)绑定 GameObject 生命周期的延迟调用650待实现
getCurrentSequenceName(node)AUtil.GetAnimSequenceName(GameObject)string获取当前播放的 Animator State 名372待实现
createFlowNode(rootNode)AUtil.CreateFlowNode(GameObject)FlowNode创建异步流节点366待实现
convertToNodeSpace(node, root, offset)AUtil.ConvertToNodeSpace(Transform, Transform, Vector2)Vector2InverseTransformPoint337待实现
showOneChildByTag(root, tag)AUtil.ShowOneChild(Transform, int)隐藏所有子节点,只显示指定 tag 的328待实现
safelyButtonClicked(sender, cb)AUtil.SafeButtonClick(Button, Action)防重复点击229待实现
arraySearch(arr, pred, def)AUtil.ArraySearch<T>(T[], Func<T,bool>, T)Tarr.FirstOrDefault(pred) ?? def138待实现
cancelDelayCall(tag, root)AUtil.CancelDelay(int, GameObject)Kill 指定 Tween84待实现
playAnimOnce(node, name, target, cb, arg)AUtil.PlayAnimOnce(GameObject, string, Action)仅当非当前动画时播放88待实现
hidePanel(panel, noAnim)AUtil.HidePanel(GameObject, bool)播放 "disappear" 动画或直接隐藏81待实现
safelyButtonClickedV2(sender, cb, delay)AUtil.SafeButtonClickV2(Button, Action, float)带冷却时间的防重复74待实现
centralizeCoinLabel(coin, label, text, noScale)AUtil.CenterCoinLabel(Transform, TMP_Text, string, bool)图标+文本水平居中71待实现
arraySum(arr, iterator)AUtil.ArraySum<T>(T[], Func<T,double>)doublearr.Sum(iterator)56待实现
arrayFilter(arr, filter)AUtil.ArrayFilter<T>(T[], Func<T,bool>)T[]arr.Where(filter).ToArray()39待实现
hideAllChildren(root)AUtil.HideAllChildren(Transform)遍历隐藏28待实现
showPanel(panel, isToggle)AUtil.ShowPanel(GameObject, bool)播放 "appear" 动画或直接显示135待实现
getSequenceDuration(node, name)AUtil.GetAnimDuration(GameObject, string)floatAnimatorStateInfo.length10待实现
replaceLabelString(label, value, search, ...)AUtil.ReplaceLabel(TMP_Text, string, string, ...)文本占位符替换24待实现
flyExistItemToPoint(from, end, time, spawn, cb)AUtil.FlyToPoint(Transform, Transform, float, ...)DOTween 移动19待实现
seekAllNodesByTag(root, tag, result)AUtil.SeekAllByTag(Transform, int)List<Transform>递归查找25待实现
getStorageCacheItem(ctrl, key, def, prefix)AUtil.GetCache(string, string, string)stringPlayerPrefs 带内存缓存30待实现
setStorageCacheItem(ctrl, key, val, prefix)AUtil.SetCache(string, string, string)PlayerPrefs + 内存缓存32待实现

数组工具

JS APIC# 方法Unity 实现策略次数状态
arrayContain(arr, elem)AUtil.Contains<T>(T[], T)boolArray.IndexOf >= 012待实现
arrayRemoveFirst(arr, pred, def)AUtil.RemoveFirst<T>(List<T>, Func<T,bool>)T找到并移除16待实现
arrayRemove(arr, pred, max)AUtil.Remove<T>(List<T>, Func<T,bool>, int)批量移除7待实现
arrayMax(arr, iterator)AUtil.ArrayMax<T>(T[], Func<T,double>)doublearr.Max(iterator)8待实现
arrayMin(arr, iterator)AUtil.ArrayMin<T>(T[], Func<T,double>)doublearr.Min(iterator)5待实现
arrayTrain(arr, iterator, cb)AUtil.ArrayTrain<T>(T[], Action<T,Action>, Action)异步串行执行5待实现

3.3.7 NameBinder.cs — CCB 属性自动绑定

模式来源.controller._propertyName 访问(~24,000 次)
C# 文件NameBinder.cs

问题描述

Cocos CCB 文件通过 CocosBuilder 的 "Owner Variable" 机制将节点绑定到 controller 的属性上。代码中通过 node.controller._btnSpin 这样的模式访问这些绑定节点。

这 ~24,000 次访问分布在 2,514 个文件中,是最普遍的 Cocos 特有模式。

设计方案

csharp
/// <summary>
/// 自动绑定系统:通过 Transform.Find 按名称查找子节点,
/// 绑定到 MonoBehaviour 的字段上。
/// 替代 Cocos CCB 的 controller._propertyName 模式。
/// </summary>
public class NameBinder : MonoBehaviour
{
    /// <summary>
    /// 扫描目标组件上标记了 [AutoBind] 的字段,
    /// 通过 Transform.Find(fieldName) 自动绑定。
    /// </summary>
    public static void Bind(MonoBehaviour target, Transform root = null);
    
    /// <summary>
    /// 手动按名称查找并返回子节点。
    /// 兼容嵌套路径如 "panel/btnSpin"。
    /// </summary>
    public static Transform Find(Transform root, string name);
    
    /// <summary>
    /// 批量查找,返回字典。
    /// </summary>
    public static Dictionary<string, Transform> FindAll(Transform root, params string[] names);
}

/// <summary>
/// 标记字段为自动绑定目标。
/// 字段名(去掉下划线前缀)作为查找名称。
/// </summary>
[AttributeUsage(AttributeTargets.Field)]
public class AutoBindAttribute : Attribute
{
    public string OverrideName { get; set; }
}

// 使用示例:
public class WildsStarburstMachine : SlotMachineBase
{
    [AutoBind] private Transform _btnSpin;        // 查找名为 "btnSpin" 的子节点
    [AutoBind] private Transform _nodeWinEffect;  // 查找名为 "nodeWinEffect"
    [AutoBind("customName")] private Transform _special; // 指定查找名
    
    protected override void OnInit()
    {
        NameBinder.Bind(this);  // 一次调用完成所有绑定
    }
}

映射规则

JS 模式C# 模式
this.node.controller._btnSpinthis._btnSpin(通过 [AutoBind] 自动绑定)
this.node.controller.initWith(data)this.InitWith(data)(直接方法调用)
someNode.controller._labelNameBinder.Find(someNode, "label")
game.util.loadNodeFromCCB("xxx", parent)GameUtil.LoadPrefab("xxx", parent) → 自动执行 NameBinder.Bind

3.3.8 其他辅助类

以下类优先级较低,方法数和调用量也相对较少,可在主要类完成后再实现。

UIHelper.cs

JS APIC# 方法次数状态
showFlyCoins(...)UIHelper.ShowFlyCoins(...)待实现
showFlyCoinsFromNode(...)UIHelper.FlyCoinsFrom(...)待实现
getCoinIconWorldPosition()UIHelper.GetCoinIconPos()Vector3待实现
getBezierControlPosition(from, to)UIHelper.GetBezierCtrl(Vector3, Vector3)Vector3待实现
addMaskLayer(root, opacity, cb)UIHelper.AddMask(Transform, float, Action)待实现
removeMaskLayer(root)UIHelper.RemoveMask(Transform)待实现
createTouchPanel(root, cb)UIHelper.CreateTouchPanel(Transform, Action)待实现
其余 ~27 个方法09-appendix-api-reference.md待实现

EventDispatcher.cs

JS APIC# 方法Unity 实现策略次数状态
addEventListener(event, cb, target, priority)EventDispatcher.On(string, Action<object>, int)C# event 或自定义发布-订阅待实现
removeEventListener(event, cb, target)EventDispatcher.Off(string, Action<object>)待实现
dispatchEvent(event, data)EventDispatcher.Emit(string, object)待实现

AudioBridge.cs

JS APIC# 方法Unity 实现策略次数状态
playEffectByKey(name, loop)AudioBridge.PlayEffect(string, bool)AudioSource.PlayOneShot 或音频管理器待实现
stopEffect(name)AudioBridge.StopEffect(string)待实现
playMusic(key, loop)AudioBridge.PlayMusic(string, bool)待实现
stopMusic()AudioBridge.StopMusic()待实现
setAudioOn(on)AudioBridge.SetEnabled(bool)待实现

DialogBridge.cs

JS APIC# 方法Unity 实现策略次数状态
show(dlg, params)DialogBridge.Show(string, object)Prefab 实例化 + 入场动画待实现
close(dlg, cleanup)DialogBridge.Close(GameObject, bool)退场动画 + 销毁待实现
pushToWaitingStack(dlg, params)DialogBridge.PushToQueue(string, object)弹窗队列待实现

3.4 特殊处理项

3.4.1 game.util.inherits() — 消除

JS 中用 game.util.inherits(SubClass, SuperClass) 实现原型链继承(4,170 次调用)。

C# 处理:完全不需要。直接使用 class SubClass : SuperClass 语法。

转换规则

javascript
// JS
game.util.inherits(WildsStarburstMachineScene287, SlotMachineScene2022);
// → C# 不生成任何代码,继承关系体现在类声明中:
// public class WildsStarburstMachine : SlotMachineBase

3.4.2 cc.Class.extend() — 消除

JS 中用 cc.Class.extend({ ... }) 定义新类(242 次)。

C# 处理:同上,直接用 class 语法。

3.4.3 registerController / unRegisterController — NameBinder 替代

JS 中 game.util.registerController("MyController", MyClass) 用于将 CCB controller 类注册到全局表(~5,108 次合计)。

C# 处理:由 NameBinder 系统完全替代。Unity Prefab 直接挂载 MonoBehaviour,无需注册/反注册。

3.4.4 loadNodeFromCCB → Prefab + NameBinder

JS 中 game.util.loadNodeFromCCB("path.ccbi", parent, "ControllerName") 加载 CCB 文件并绑定 controller(2,186 次)。

C# 处理

csharp
// GameUtil.LoadPrefab 内部流程:
// 1. Addressables.InstantiateAsync(prefabPath) 或 Instantiate(Resources.Load<GameObject>(path))
// 2. 设置 parent
// 3. 获取目标 MonoBehaviour 组件
// 4. 调用 NameBinder.Bind(component) 自动绑定子节点
// 5. 返回 GameObject

3.4.5 cc.Node 构造 → Unity GameObject

JS 中 new cc.Node() 创建空节点(989 次),new cc.Sprite() 创建精灵节点(445 次)。

C# 处理

csharp
// cc.Node() → new GameObject()
// cc.Sprite(frame) → 创建 GameObject + 添加 Image/SpriteRenderer 组件
// cc.ProgressTimer() → 创建 GameObject + Image(type=Filled)
// cc.Scale9Sprite() → 创建 GameObject + Image(type=Sliced)
// cc.ClippingNode() → 创建 GameObject + Mask 组件
// cc.LayerColor() → 创建 GameObject + Image(color fill)

3.5 实现优先级

P0(零依赖基础,最先实现)
├── CCCompat.cs 所有其他文件的基础类型
└── CCAction.cs 3,124 runAction 调用依赖

P1(高频核心,P0 完成后实现)
├── NodeHelper.cs 17,283 次调用,最高单文件
├── GameUtil.cs 31,237 次调用(扣除不需要的仍有 ~22,000)
├── SlotUtil.cs 10,199 次调用
└── NameBinder.cs 24,000 .controller._ 依赖

P2(中频辅助,P1 完成后实现)
├── ActivityUtil.cs 5,275 次调用
├── UIHelper.cs 中频
├── EventDispatcher.cs 事件系统
└── AudioBridge.cs 音效系统

P3(低频/可延后)
├── DialogBridge.cs
├── SlotPopupUtil.cs
├── WinEffectHelper.cs
└── HighRollerSlotUtil.cs

下一章:04 - L2 Slot 框架层详细设计

Released under the MIT License.