美术合入

This commit is contained in:
2026-04-08 18:28:27 +08:00
parent 79997281c0
commit 7f2d12b5a5
30 changed files with 4240 additions and 1314 deletions
@@ -0,0 +1,356 @@
---
name: 塔罗牌小游戏实现
overview: 基于 Sprite + EventTriggerEx 实现塔罗牌小游戏,Yarn 命令细粒度控制每个阶段(展示牌堆、展开、等待选牌、翻牌、设置朝向),与对话深度配合。
todos:
- id: tarot-card
content: 创建 TarotCard.cs -- 单张牌组件:IInteraction、SpriteRenderer 正反面、EventTriggerEx 注册、翻牌动画、朝向控制(正/倒)、悬停/点击回调
status: completed
- id: tarot-deck
content: 创建 TarotDeck.cs -- 牌堆管理:动态生成牌、扇形展开布局、悬停推出效果、选牌流程(FadeOut + 居中检视)
status: completed
- id: tarot-manager
content: 创建 TarotManager.cs -- 系统管理器:SystemDic 注册、视图开关、阶段状态机、选牌结果
status: completed
- id: tarot-yarn
content: 创建 TarotYarnCommand.cs -- 细粒度 Yarn 命令集(show/spread/wait_select/flip/set_orientation/rotate/hide
status: completed
isProject: false
---
# 塔罗牌小游戏实现计划
## 设计目标
Yarn 脚本能**细粒度控制**塔罗牌的每个视觉阶段,每个命令之间可以穿插对话,实现对话与交互的深度配合。
## Yarn 脚本示例(对应 FP_Day1_night 第 364-395 行的改造)
```yarn
ql: 我觉得也许你需要这个。
<<show_tarot_deck>>
【它拿出一套崭新的卡牌。】
me: 这是什么?
ql: "塔罗牌"。
ql: 试试吧。抽一张。
<<spread_tarot 5>>
-> 抽牌
<<wait_tarot_select>>
【你看了看牌。】
<<flip_tarot "inverted">>
// 翻到正面,但预设为倒置朝向(inverted)
【上面画着一个张开双臂的机体...像是...在把它吸过去。】
me: 这画的是什么?
ql: 倒吊人。你拿反了。
<<rotate_tarot "normal">>
// Yarn 命令改变朝向:倒置 -> 正向(旋转 180 度动画)
【你把牌转过来。】
【这下你看明白了。这是一个倒吊着的机体...】
// ...更多对话...
<<hide_tarot>>
```
## 架构概览
```mermaid
flowchart TD
Yarn["Yarn 脚本"] -->|"<<show_tarot_deck>>"| CMD["TarotYarnCommand\n(静态 Yarn 命令类)"]
Yarn -->|"<<spread_tarot 5>>"| CMD
Yarn -->|"<<wait_tarot_select>>"| CMD
Yarn -->|"<<flip_tarot inverted>>"| CMD
Yarn -->|"<<rotate_tarot normal>>"| CMD
Yarn -->|"<<hide_tarot>>"| CMD
CMD --> TM["TarotManager\n(SystemDic 注册)"]
TM --> TD["TarotDeck\n牌堆/扇形/选牌"]
TD --> TC["TarotCard x N\nSprite + EventTriggerEx"]
TC -->|IInteraction| ES["EventSystemEx"]
```
## 新增文件结构
```
Assets/Scripts/MiniGame/Tarot/
TarotManager.cs -- 管理器:SystemDic 注册、视图开关、阶段协调
TarotCard.cs -- 单张牌:IInteraction + 翻牌 + 朝向
TarotDeck.cs -- 牌堆逻辑:生成、展开、悬停、选牌
TarotYarnCommand.cs -- 细粒度 Yarn 命令集
```
## 核心设计
### 1. TarotCard -- 单张牌
参考 [KnobController](Assets/Scripts/MiniGame/HuoShan/SalesSystem/KnobController.cs) 的 EventTriggerEx 注册模式(行 165-199)。
- 实现 `IInteraction` 接口(`IsActive`, `IsAvailable`, `GetGameObject()`
- 需要 `Collider2D`BoxCollider2D,牌面大小)
- `SpriteRenderer` + 两个 Sprite 引用:`frontSprite` / `backSprite`
**朝向系统(Orientation**
- 枚举 `TarotOrientation { Normal, Inverted }`
- `Normal`:正面朝上(localScale.y = 1
- `Inverted`:倒置(localScale.y = -1,即上下颠倒)
- `SetOrientation(orientation, animated)` 方法,animated 时用 DOTween 做 Y 轴 scale 过渡
**翻牌动画**
- `Flip(targetOrientation, duration)` 协程
- DOTween 缩放 localScale.x: 1 -> 0(前半),切换 Sprite,再 0 -> 1(后半)
- 翻牌完成时根据 `targetOrientation` 设置 localScale.y
**交互注册**Awake):
- 获取/添加 `EventTriggerEx`
- `EnsureEventTriggerEntries()` 确保 PointerEnter/PointerExit/PointerClick 条目
- `Register(PointerEnter, OnHoverEnter)` / `Register(PointerExit, OnHoverExit)` / `Register(PointerClick, OnClick)`
- 回调通过 `System.Action` 委托给 `TarotDeck`
**状态**
- `bool IsFaceUp` -- 当前是否正面朝上
- `TarotOrientation Orientation` -- 当前朝向
- `bool IsInteractable` -- 是否接受交互(由 Deck 控制)
### 2. TarotDeck -- 牌堆管理
**动态生成**
- `Setup(int cardCount, Sprite front, Sprite back)` -- 创建 N 个 TarotCard 子物体
- 每张牌初始背面朝上,叠在一起(牌堆状态)
**扇形展开**
- `SpreadCards(float duration)` 协程
- 配置项:`fanAngleRange`(扇形总角度,如 120 度)、`fanRadius`(扇形半径)
- 每张牌的目标角度:`centerAngle + (i - (count-1)/2f) * angleStep`
- 每张牌的目标位置:以旋转角度沿圆弧分布
- DOTween `DOLocalMove` + `DOLocalRotate` 同步动画
**悬停推出**
- 牌注册的 `OnHoverEnter` -> 沿牌面法线方向(局部 Y 轴上方)推出一段距离
- `OnHoverExit` -> 回到扇形位置
- 用 DOTween `DOLocalMove`,设短 duration0.15s
**选牌**
- `OnCardClicked(TarotCard card)` -- 锁定交互,触发选牌序列
- 其余牌 `SpriteRenderer.DOFade(0, 0.3f)` 渐隐
- 选中牌移至检视位置(屏幕中央偏上),放大到检视尺寸
- 设置 `_selectedCard`,通知 Manager 选牌完成
**检视位置**
- `[SerializeField] Transform inspectPosition` -- 检视锚点
- `[SerializeField] float inspectScale` -- 检视缩放
### 3. TarotManager -- 管理器
- `Start()``FixSystemCenter.SystemDic.Register(this)`
- 持有 `TarotDeck` 引用(`GetComponentInChildren`
- 状态标记:`_isWaitingForSelection`(是否在等待玩家选牌)、`_isCardSelected`
- `OpenView()` / `CloseView()` 控制根 GameObject 显隐
- `WaitForSelection()` 协程 -- while 循环等待 `_isCardSelected`,供 YarnCommand 使用
- `SelectedCard` 属性 -- 获取当前选中的牌
### 4. TarotYarnCommand -- 细粒度 Yarn 命令集
所有命令通过 `FixSystemCenter.SystemDic.Get<TarotManager>()` 获取 Manager 实例。
| Yarn 命令 | 方法签名 | 说明 |
| ----------------------------------------- | ------------------------------------------------------ | --------------------------------------------------------------------- |
| `<<show_tarot_deck>>` | `ShowTarotDeck(int count = 5)` | 显示牌堆(叠放状态),可指定牌数 |
| `<<spread_tarot>>``<<spread_tarot 5>>` | `IEnumerator SpreadTarot(int count = -1)` | 扇形展开,count=-1 用已有牌数;协程等待展开动画完成 |
| `<<wait_tarot_select>>` | `IEnumerator WaitTarotSelect()` | 阻塞 Yarn 直到玩家点击选中一张牌;选中后执行选牌动画(其余牌淡出、选中牌居中);结果写入 `$tarotSelectedIndex` |
| `<<flip_tarot "normal">>` | `IEnumerator FlipTarot(string orientation = "normal")` | 翻牌到正面,同时设置朝向;`"normal"` = 正向,`"inverted"` = 倒置 |
| `<<rotate_tarot "normal">>` | `IEnumerator RotateTarot(string orientation)` | 改变已翻开牌的朝向(旋转动画),不翻面 |
| `<<hide_tarot>>` | `IEnumerator HideTarot()` | 淡出并隐藏所有塔罗元素 |
### 5. 完整交互流程
```mermaid
stateDiagram-v2
[*] --> DeckVisible: show_tarot_deck
DeckVisible --> DeckVisible: 对话继续\n(牌堆静态展示)
DeckVisible --> FanOut: spread_tarot
FanOut --> WaitSelect: wait_tarot_select
WaitSelect --> WaitSelect: hover 推出/回位
WaitSelect --> Selected: 玩家点击选牌
Selected --> InspectBack: 其余牌淡出\n选中牌居中(背面)
InspectBack --> InspectBack: 对话继续\n(背面检视)
InspectBack --> InspectFront: flip_tarot\n(预设朝向)
InspectFront --> InspectFront: 对话继续
InspectFront --> InspectRotated: rotate_tarot\n(改变朝向)
InspectRotated --> InspectRotated: 对话继续
InspectRotated --> [*]: hide_tarot
InspectFront --> [*]: hide_tarot
```
关键:每个状态之间 Yarn 对话可以自由穿插,命令只推进视觉阶段,不阻塞对话本身(除了 `wait_tarot_select` 是阻塞等待玩家交互)。
### 6. Sprite 资源
当前使用 `Assets/RawResources/Art/CG/塔罗牌/塔罗牌正面.png``塔罗牌背面.png`,所有牌共用同一对正反面。后续可扩展为每张牌不同正面。
## 场景配置
### 层级结构
```
TarotSystem -- 空 GameObject,放在需要的场景中
├── TarotManager (Component) -- 管理器脚本
├── TarotView -- 视图容器(OpenView/CloseView 控制这个)
│ ├── TarotDeck (Component) -- 牌堆逻辑脚本
│ │ └── [运行时动态生成的牌] -- TarotCard x N
│ │
│ └── InspectAnchor -- 检视锚点(空物体,标记牌选中后居中的位置)
│ (Transform 位置设在画面中央偏上)
└── (可选) Cinemachine Camera -- 如果塔罗需要独立相机视角
```
### 需要手动配置的部分
**1. TarotSystem 根物体**
- 放在对应场景中(如 Day1_night 所在场景)
- 位置在世界空间中合适的地方(与当前相机视角对齐)
**2. TarotManager 组件(Inspector 面板)**
```
[Header("视图")]
TarotView -- 拖入 TarotView 子物体(或自动 Find
[Header("牌面素材")]
FrontSprite -- 拖入 塔罗牌正面 Sprite
BackSprite -- 拖入 塔罗牌背面 Sprite
[Header("牌 Prefab")]
CardPrefab -- 拖入预制的单张牌 Prefab(见下方)
```
**3. 单张牌 Prefab(预制体)**
需要提前制作一个 Prefab,结构如下:
```
TarotCard (Prefab)
Components:
- SpriteRenderer (默认 sprite = 背面,sortingOrder 按需)
- BoxCollider2D (Size 匹配牌面大小,用于点击/悬停检测)
- EventTriggerEx (Inspector 中添加 3 个 Trigger 条目:
PointerEnter, PointerExit, PointerClick)
- TarotCard.cs (脚本自动注册事件)
```
EventTriggerEx 的 Inspector 配置要点:
- 点击 "Add New Event Type"
- 分别添加 `PointerEnter``PointerExit``PointerClick` 三个条目
- 回调列表留空(代码中 `Register` 动态绑定)
> 这与 KnobController 的模式一致:EventTriggerEx 需要 Inspector 中预配好条目,代码中 `TryGetTriggerEvent` 才能找到对应的 callback list。代码中也会 `EnsureEventTriggerEntries()` 作为保底自动添加。
**4. TarotDeck 组件(Inspector 面板)**
```
[Header("扇形展开参数")]
FanAngleRange = 120 -- 扇形总角度(度)
FanRadius = 3.0 -- 扇形半径(世界单位)
FanCenter = (0,0,0) -- 扇形圆心偏移
[Header("悬停")]
HoverOffset = 0.5 -- 悬停推出距离
HoverDuration = 0.15 -- 悬停动画时长
[Header("检视")]
InspectAnchor -- 拖入 InspectAnchor 子物体
InspectScale = 1.5 -- 检视模式缩放倍数
[Header("动画时长")]
SpreadDuration = 0.6 -- 展开动画时长
FadeOutDuration = 0.3 -- 未选中牌淡出时长
MoveToInspectDuration = 0.4 -- 选中牌移至检视位置时长
```
### 运行时流程
```mermaid
sequenceDiagram
participant Y as Yarn
participant M as TarotManager
participant D as TarotDeck
participant C as TarotCard
Y->>M: show_tarot_deck(5)
M->>M: OpenView()
M->>D: Setup(5, frontSprite, backSprite)
D->>D: Instantiate CardPrefab x 5
D->>C: 初始化 (背面, 叠放)
Note over Y: 对话继续...
Y->>D: spread_tarot
D->>C: DOTween 扇形展开动画
Note over Y: 对话继续...
Y->>M: wait_tarot_select (阻塞)
Note over C: 玩家悬停/点击
C-->>D: OnCardClicked
D->>D: 其余牌淡出, 选中牌居中
D-->>M: 选牌完成
M-->>Y: 协程返回
Note over Y: 对话继续...
Y->>M: flip_tarot("inverted")
M->>C: Flip(inverted)
C->>C: X轴缩放动画 + 切换Sprite + Y轴倒置
Note over Y: 对话: "你拿反了"
Y->>M: rotate_tarot("normal")
M->>C: SetOrientation(normal, animated=true)
C->>C: Y轴旋转动画 (倒置->正向)
Note over Y: 对话继续...
Y->>M: hide_tarot
M->>D: 淡出所有牌
M->>M: CloseView()
```
### 不需要手动做的部分(代码自动处理)
- 牌的动态实例化和销毁(`TarotDeck` 负责)
- EventTriggerEx 事件绑定(`TarotCard.Awake` 自动注册)
- SystemDic 注册(`TarotManager.Start` 自动注册)
- 扇形位置计算(`TarotDeck` 按参数自动排布)
## 关键技术点
- **EventTriggerEx 注册模式**:参考 `KnobController.Awake()` (行 165-199),需先 `EnsureEventTriggerEntries()` 确保 triggers 列表有对应条目,再调用 `Register(EventTriggerType, callback)`
- **DOTween 动画**:项目已引入 `DG.Tweening`,用于扇形展开、悬停推出、翻牌、FadeOut
- **IInteraction 实现**`IsActive` / `IsAvailable` 控制交互可用性,配合 `EventSystemEx.isLocked` 在对话期间自动禁用交互(对话进行时 `isLocked=true``wait_tarot_select` 时对话暂停所以 `isLocked=false`,交互自然可用)
- **SystemDic 注册**`FixSystemCenter.SystemDic.Register(this)` 使 YarnCommand 能通过 `Get<TarotManager>()` 获取实例
- **Yarn 变量写入**`StorageSystem.Instance.SetValue("$tarotSelectedIndex", value)` 将选牌结果传回 Yarn
@@ -47,6 +47,11 @@ MonoBehaviour:
m_ReadOnly: 0
m_SerializedLabels: []
FlaggedDuringContentUpdateRestriction: 0
- m_GUID: a74e4379fa468c24497808e8a6bae2c4
m_Address: "Animation/\u9152\u4FDD"
m_ReadOnly: 0
m_SerializedLabels: []
FlaggedDuringContentUpdateRestriction: 0
m_ReadOnly: 0
m_Settings: {fileID: 11400000, guid: 77169ce22e430f64fb36c771815a4a7b, type: 2}
m_SchemaSet:
File diff suppressed because it is too large Load Diff
@@ -902,6 +902,38 @@ MonoBehaviour:
m_Localized: "me: \u59D0\u59D0\uFF1F"
m_Metadata:
m_Items: []
- m_Id: 8192411791687680
m_Localized: "\u5C55\u5F00"
m_Metadata:
m_Items: []
- m_Id: 8192411888156672
m_Localized: "\u7FFB\u8F6C"
m_Metadata:
m_Items: []
- m_Id: 8192411888156673
m_Localized: "\u65CB\u8F6C\u5854\u7F57"
m_Metadata:
m_Items: []
- m_Id: 8232716318441472
m_Localized: "\u65CB\u8F6C\u5854\u7F57"
m_Metadata:
m_Items: []
- m_Id: 8232716326830080
m_Localized: "\u65CB\u8F6C\u5854\u7F57"
m_Metadata:
m_Items: []
- m_Id: 8232853774172160
m_Localized: "\u7FFB\u9762"
m_Metadata:
m_Items: []
- m_Id: 8232853774172161
m_Localized: "\u65CB\u8F6C\u5854\u7F57"
m_Metadata:
m_Items: []
- m_Id: 8249004239519744
m_Localized: "\u7FFB\u9762"
m_Metadata:
m_Items: []
references:
version: 2
RefIds: []
File diff suppressed because it is too large Load Diff
@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 9c2b50f613e7cf443a5c0b47fbec6fc3
guid: 7b5686a824b5ef941bd95b4b90b8bad1
folderAsset: yes
DefaultImporter:
externalObjects: {}
+159
View File
@@ -0,0 +1,159 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!1 &3010741200367562085
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 747587652736914463}
- component: {fileID: 3787716241283275176}
- component: {fileID: 1889493932934250764}
- component: {fileID: 2608400110415776931}
- component: {fileID: 4696575612135373482}
m_Layer: 0
m_Name: TarotCard
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &747587652736914463
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 3010741200367562085}
serializedVersion: 2
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!212 &3787716241283275176
SpriteRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 3010741200367562085}
m_Enabled: 1
m_CastShadows: 0
m_ReceiveShadows: 0
m_DynamicOccludee: 1
m_StaticShadowCaster: 0
m_MotionVectors: 1
m_LightProbeUsage: 1
m_ReflectionProbeUsage: 1
m_RayTracingMode: 0
m_RayTraceProcedural: 0
m_RenderingLayerMask: 1
m_RendererPriority: 0
m_Materials:
- {fileID: 2100000, guid: 39fa61e2f0a4e6c4baa90336635134a7, type: 2}
m_StaticBatchInfo:
firstSubMesh: 0
subMeshCount: 0
m_StaticBatchRoot: {fileID: 0}
m_ProbeAnchor: {fileID: 0}
m_LightProbeVolumeOverride: {fileID: 0}
m_ScaleInLightmap: 1
m_ReceiveGI: 1
m_PreserveUVs: 0
m_IgnoreNormalsForChartDetection: 0
m_ImportantGI: 0
m_StitchLightmapSeams: 1
m_SelectedEditorRenderState: 0
m_MinimumChartSize: 4
m_AutoUVMaxDistance: 0.5
m_AutoUVMaxAngle: 89
m_LightmapParameters: {fileID: 0}
m_SortingLayerID: 844151739
m_SortingLayer: 844151739
m_SortingOrder: 50
m_Sprite: {fileID: 21300000, guid: d0efb72d2522a02498529a97a4652c6a, type: 3}
m_Color: {r: 1, g: 1, b: 1, a: 1}
m_FlipX: 0
m_FlipY: 0
m_DrawMode: 0
m_Size: {x: 2.24, y: 3.84}
m_AdaptiveModeThreshold: 0.5
m_SpriteTileMode: 0
m_WasSpriteAssigned: 1
m_MaskInteraction: 0
m_SpriteSortPoint: 0
--- !u!61 &1889493932934250764
BoxCollider2D:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 3010741200367562085}
m_Enabled: 1
m_Density: 1
m_Material: {fileID: 0}
m_IncludeLayers:
serializedVersion: 2
m_Bits: 0
m_ExcludeLayers:
serializedVersion: 2
m_Bits: 0
m_LayerOverridePriority: 0
m_ForceSendLayers:
serializedVersion: 2
m_Bits: 4294967295
m_ForceReceiveLayers:
serializedVersion: 2
m_Bits: 4294967295
m_ContactCaptureLayers:
serializedVersion: 2
m_Bits: 4294967295
m_CallbackLayers:
serializedVersion: 2
m_Bits: 4294967295
m_IsTrigger: 0
m_UsedByEffector: 0
m_UsedByComposite: 0
m_Offset: {x: 0, y: 0}
m_SpriteTilingProperty:
border: {x: 0, y: 0, z: 0, w: 0}
pivot: {x: 0.5, y: 0.5}
oldSize: {x: 2.24, y: 3.84}
newSize: {x: 2.24, y: 3.84}
adaptiveTilingThreshold: 0.5
drawMode: 0
adaptiveTiling: 0
m_AutoTiling: 0
serializedVersion: 2
m_Size: {x: 2.5, y: 4}
m_EdgeRadius: 0
--- !u!114 &2608400110415776931
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 3010741200367562085}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 0c4fbab01ad40c2449c849cd2a8c620f, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Delegates: []
--- !u!114 &4696575612135373482
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 3010741200367562085}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: b8981c7d01530ea4d9f5a42f5bb79069, type: 3}
m_Name:
m_EditorClassIdentifier:
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: c15d453f57c98e544a3eb4327dc1acf2
PrefabImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -158,6 +158,21 @@ AnimatorState:
m_MirrorParameter:
m_CycleOffsetParameter:
m_TimeParameter:
--- !u!206 &-6017680952551971105
BlendTree:
m_ObjectHideFlags: 1
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: Blend Tree
m_Childs: []
m_BlendParameter: Blend
m_BlendParameterY: Blend
m_MinThreshold: 0
m_MaxThreshold: 1
m_UseAutomaticThresholds: 1
m_NormalizedBlendValues: 0
m_BlendType: 0
--- !u!1102 &-5794089171217287463
AnimatorState:
serializedVersion: 6
@@ -1521,13 +1536,13 @@ AnimatorStateMachine:
m_ChildStates:
- serializedVersion: 1
m_State: {fileID: -2117480317636242668}
m_Position: {x: -100, y: -100, z: 0}
m_Position: {x: -100, y: -130, z: 0}
- serializedVersion: 1
m_State: {fileID: -487060980630585024}
m_Position: {x: -100, y: -40, z: 0}
m_Position: {x: -100, y: -70, z: 0}
- serializedVersion: 1
m_State: {fileID: -3231453327786797998}
m_Position: {x: 900, y: 0, z: 0}
m_Position: {x: 930, y: 20, z: 0}
- serializedVersion: 1
m_State: {fileID: -7536899270207213396}
m_Position: {x: 1100, y: 0, z: 0}
@@ -1539,7 +1554,7 @@ AnimatorStateMachine:
m_Position: {x: 1500, y: 0, z: 0}
- serializedVersion: 1
m_State: {fileID: 413658532417359208}
m_Position: {x: 500, y: 0, z: 0}
m_Position: {x: 460, y: 70, z: 0}
- serializedVersion: 1
m_State: {fileID: 80218190701964404}
m_Position: {x: 500, y: 200, z: 0}
@@ -1560,13 +1575,13 @@ AnimatorStateMachine:
m_Position: {x: 1500, y: 200, z: 0}
- serializedVersion: 1
m_State: {fileID: 5923217995241031354}
m_Position: {x: 500, y: 400, z: 0}
m_Position: {x: 510, y: 400, z: 0}
- serializedVersion: 1
m_State: {fileID: 2112311720728269325}
m_Position: {x: 700, y: 400, z: 0}
- serializedVersion: 1
m_State: {fileID: -1246271974212818335}
m_Position: {x: -1100, y: 0, z: 0}
m_Position: {x: -1090, y: -510, z: 0}
- serializedVersion: 1
m_State: {fileID: -2261339983787712565}
m_Position: {x: -600, y: 0, z: 0}
@@ -1587,7 +1602,7 @@ AnimatorStateMachine:
m_Position: {x: -1100, y: 300, z: 0}
- serializedVersion: 1
m_State: {fileID: 555854828853339981}
m_Position: {x: -350, y: 50, z: 0}
m_Position: {x: -40, y: 200, z: 0}
- serializedVersion: 1
m_State: {fileID: 3345965468207119166}
m_Position: {x: -850, y: 0, z: 0}
@@ -1599,7 +1614,7 @@ AnimatorStateMachine:
m_Position: {x: -350, y: 0, z: 0}
- serializedVersion: 1
m_State: {fileID: -2419897528932387385}
m_Position: {x: -1100, y: -100, z: 0}
m_Position: {x: -1110, y: -120, z: 0}
- serializedVersion: 1
m_State: {fileID: 2735636492495566621}
m_Position: {x: -850, y: -200, z: 0}
@@ -1617,7 +1632,7 @@ AnimatorStateMachine:
m_Position: {x: -1080, y: 980, z: 0}
- serializedVersion: 1
m_State: {fileID: -1072338186046007407}
m_Position: {x: -1080, y: 1030, z: 0}
m_Position: {x: -1080, y: 1080, z: 0}
- serializedVersion: 1
m_State: {fileID: 5724852447548785429}
m_Position: {x: -650, y: 600, z: 0}
@@ -1635,13 +1650,13 @@ AnimatorStateMachine:
m_Position: {x: -850, y: 50, z: 0}
- serializedVersion: 1
m_State: {fileID: 2664188590508247494}
m_Position: {x: -100, y: -160, z: 0}
m_Position: {x: -100, y: -200, z: 0}
- serializedVersion: 1
m_State: {fileID: -3734933900696762598}
m_Position: {x: 700, y: 0, z: 0}
m_Position: {x: 720, y: 20, z: 0}
- serializedVersion: 1
m_State: {fileID: -3399003863851128280}
m_Position: {x: -1100, y: 50, z: 0}
m_Position: {x: -1100, y: 40, z: 0}
- serializedVersion: 1
m_State: {fileID: -6901599630031755382}
m_Position: {x: -1100, y: 700, z: 0}
@@ -1677,13 +1692,16 @@ AnimatorStateMachine:
m_Position: {x: -860, y: 700, z: 0}
- serializedVersion: 1
m_State: {fileID: -7984775416089824586}
m_Position: {x: -1100, y: 350, z: 0}
m_Position: {x: -1100, y: 400, z: 0}
- serializedVersion: 1
m_State: {fileID: -680805105718971158}
m_Position: {x: -1100, y: 250, z: 0}
- serializedVersion: 1
m_State: {fileID: 1397603521845411687}
m_Position: {x: -1100, y: 200, z: 0}
- serializedVersion: 1
m_State: {fileID: 4244966698796180899}
m_Position: {x: 930.91675, y: -533.7821, z: 0}
m_ChildStateMachines: []
m_AnyStateTransitions: []
m_EntryTransitions: []
@@ -1694,6 +1712,32 @@ AnimatorStateMachine:
m_ExitPosition: {x: -1400, y: 90, z: 0}
m_ParentStateMachinePosition: {x: 800, y: 20, z: 0}
m_DefaultState: {fileID: -1246271974212818335}
--- !u!1102 &4244966698796180899
AnimatorState:
serializedVersion: 6
m_ObjectHideFlags: 1
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: Blend Tree
m_Speed: 1
m_CycleOffset: 0
m_Transitions: []
m_StateMachineBehaviours: []
m_Position: {x: 50, y: 50, z: 0}
m_IKOnFeet: 0
m_WriteDefaultValues: 1
m_Mirror: 0
m_SpeedParameterActive: 0
m_MirrorParameterActive: 0
m_CycleOffsetParameterActive: 0
m_TimeParameterActive: 0
m_Motion: {fileID: -6017680952551971105}
m_Tag:
m_SpeedParameter:
m_MirrorParameter:
m_CycleOffsetParameter:
m_TimeParameter:
--- !u!1102 &4562423838128826706
AnimatorState:
serializedVersion: 6
@@ -585,7 +585,7 @@ AnimatorStateMachine:
m_Position: {x: -150, y: 640, z: 0}
- serializedVersion: 1
m_State: {fileID: -4954696939987313593}
m_Position: {x: 230, y: 770, z: 0}
m_Position: {x: 240, y: 740, z: 0}
- serializedVersion: 1
m_State: {fileID: -3146180861922402906}
m_Position: {x: 560, y: 600, z: 0}
@@ -633,7 +633,7 @@ AnimatorStateMachine:
m_Position: {x: 920, y: 990, z: 0}
- serializedVersion: 1
m_State: {fileID: -9082082105795110584}
m_Position: {x: 370, y: 1220, z: 0}
m_Position: {x: 260, y: 1150, z: 0}
- serializedVersion: 1
m_State: {fileID: -7111256727978428447}
m_Position: {x: 260, y: 1430, z: 0}
@@ -642,7 +642,7 @@ AnimatorStateMachine:
m_Position: {x: 610, y: 1370, z: 0}
- serializedVersion: 1
m_State: {fileID: -6230431270701453003}
m_Position: {x: 660, y: 1070, z: 0}
m_Position: {x: 650, y: 1130, z: 0}
- serializedVersion: 1
m_State: {fileID: -2151159149815199622}
m_Position: {x: 870, y: 1260, z: 0}
@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 938c1ab7ddea0bd439253d1065534f4f
guid: 5b0946c9aa951bd42825ea4d9fc4ed87
folderAsset: yes
DefaultImporter:
externalObjects: {}
Binary file not shown.
@@ -0,0 +1,153 @@
fileFormatVersion: 2
guid: 3e1c6a0bbc8a8974fbb5f4d92a45f0ba
TextureImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 12
mipmaps:
mipMapMode: 0
enableMipMap: 0
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
flipGreenChannel: 0
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
vTOnly: 0
ignoreMipmapLimit: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: 0
aniso: 1
mipBias: 0
wrapU: 1
wrapV: 1
wrapW: 1
nPOTScale: 0
lightmap: 0
compressionQuality: 50
spriteMode: 1
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 1
spriteTessellationDetail: -1
textureType: 8
textureShape: 1
singleChannelComponent: 0
flipbookRows: 1
flipbookColumns: 1
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
ignorePngGamma: 0
applyGammaDecoding: 0
swizzle: 50462976
cookieLightType: 0
platformSettings:
- serializedVersion: 3
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 0
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: WebGL
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Standalone
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Android
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Server
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
bones: []
spriteID: 5e97eb03825dee720800000000000000
internalID: 0
vertices: []
indices:
edges: []
weights: []
secondaryTextures: []
nameFileIdTable: {}
mipmapLimitGroupName:
pSDRemoveMatte: 0
userData:
assetBundleName:
assetBundleVariant:
Binary file not shown.
@@ -0,0 +1,153 @@
fileFormatVersion: 2
guid: d0efb72d2522a02498529a97a4652c6a
TextureImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 12
mipmaps:
mipMapMode: 0
enableMipMap: 0
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
flipGreenChannel: 0
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
vTOnly: 0
ignoreMipmapLimit: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: 0
aniso: 1
mipBias: 0
wrapU: 1
wrapV: 1
wrapW: 1
nPOTScale: 0
lightmap: 0
compressionQuality: 50
spriteMode: 1
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 1
spriteTessellationDetail: -1
textureType: 8
textureShape: 1
singleChannelComponent: 0
flipbookRows: 1
flipbookColumns: 1
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
ignorePngGamma: 0
applyGammaDecoding: 0
swizzle: 50462976
cookieLightType: 0
platformSettings:
- serializedVersion: 3
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 0
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: WebGL
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Standalone
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Android
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Server
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
bones: []
spriteID: 5e97eb03825dee720800000000000000
internalID: 0
vertices: []
indices:
edges: []
weights: []
secondaryTextures: []
nameFileIdTable: {}
mipmapLimitGroupName:
pSDRemoveMatte: 0
userData:
assetBundleName:
assetBundleVariant:
@@ -85,13 +85,13 @@ AnimatorStateMachine:
m_ChildStates:
- serializedVersion: 1
m_State: {fileID: -778816098187901603}
m_Position: {x: 350, y: 300, z: 0}
m_Position: {x: 580, y: 240, z: 0}
- serializedVersion: 1
m_State: {fileID: -5182194875410447805}
m_Position: {x: 350, y: 210, z: 0}
m_Position: {x: 150, y: 230, z: 0}
- serializedVersion: 1
m_State: {fileID: 8810316756321988090}
m_Position: {x: 350, y: 120, z: 0}
m_Position: {x: 360, y: 60, z: 0}
m_ChildStateMachines: []
m_AnyStateTransitions: []
m_EntryTransitions: []
@@ -192,7 +192,21 @@ hs: 到时候我们就可以在那里开个…我们自己的酒吧……一边
<<jump 梦>>
===
// title: test
// tags:
// colorID: 8
// position: 250,200
// ---
// <<show_tarot_deck 15>>
// ->展开
// <<spread_tarot>>
// <<wait_tarot_select>>
// ->翻转
// <<flip_tarot "inverted">>
// ->旋转塔罗
// <<rotate_tarot "normal">>
// ===
title: 酒吧6
@@ -203,16 +217,18 @@ position: 250,200
<<load_scene Scene/酒吧场景 1>>
<<init_actor 酒吧医生 吧台左侧>>
<<init_actor 酒吧调酒妹 吧台内>>
<<init_actor 酒保 酒保左侧>>
// <<show_actor 酒保>>
<<show_actor 酒吧医生>>
<<time_flows_on day night>>
// <<jump test>>
<i>又是这里…</i> #line:0207402
<i>吵闹的音乐,炫目的灯光…一切都令人心烦。</i> #line:0e72808
<<fade_out 1>>
jb: 晚上好。想喝点什么呢? #line:07a41ab
【一个看起来是管事的侍者型号凑了上来。】 #line:09d9d69
<<fade_in_actor 酒保 0.5>>
jb: 如果不知道喝什么,可以试试我们的…… #line:0a3b5af
me: Neat,双份。谢谢。 #line:0ed3bf5
@@ -226,6 +242,10 @@ me: 谢谢。 #line:09a2a98
<<wait 1>>
jb: …好的。Neat双份。 #line:029d775
<<fade_out_actor 酒保 0.5>>
<<wait 0.5>>
<<change_actor_slot "酒保" "酒保右侧">>
<<fade_in_actor 酒保 0.5>>
【侍者自讨没趣地耸了耸肩,留下了一杯酒,缩回了阴影里。】 #line:0b4aa3a
【你一饮而尽。】 #line:031e661
@@ -254,7 +274,9 @@ ql: 你不想问你自己是什么气味吗? #line:0a9173c
【你轻轻微笑。】 #line:068a830
me: 我听得出来你自己是打算要说的。 #line:077704b
<<fade_out_actor 酒吧调酒妹 0.5>>
<<change_actor_state "1CloseeyeSmile" 酒吧调酒妹>>
<<fade_in_actor 酒吧调酒妹 0.5>>
【调酒妹也笑了。是一个灿烂的笑。】 #line:0fb7377
ql: 猜一下嘛。 #line:07950d4
ql: 你有和我身上一样的气味。 #line:09f8aa5
@@ -267,13 +289,18 @@ ql: 是烦恼啦。 #line:0fd1a36
me: 你和每个机体都这么说吧。 #line:04035d6
me: 毕竟大家来这里,都是为了忘掉某些东西。不是么? #line:08f576e
<<change_actor_state "1HalfeyeSmile" 酒吧调酒妹>>
<<change_actor_state "1CloseeyeSmile" 酒吧调酒妹>>
<<wait 1>>
ql: 是的。这就是酒的作用。 #line:009ee9f
<<change_actor_state "1Smile" 酒吧调酒妹>>
<<wait 1>>
ql: 不过…每个机体身上的气味,无论是悲伤的气味,焦躁的气味… #line:0cfac62
ql: 总之,每个机体的原型都不一样,所以它们原型里的"未解决之事"也就不一样。 #line:04d9fff
ql: 这就是主脑为我们设计"原型"的目的。这是我们活着的驱动,我们存在的意义。 #line:0a9bdbf
<<fade_out_actor 酒吧调酒妹 0.5>>
<<change_actor_state "1Closeeye" 酒吧调酒妹>>
<<fade_in_actor 酒吧调酒妹 0.5>>
<<wait 1>>
ql: 我闻得出。你的"未解决之事"是那种Neat无法解决的。 #line:0dd8568
me: 又有什么问题可以真正被解决呢? #line:0dac617
@@ -287,7 +314,9 @@ me: 你怎么知道? #line:0dc507b
<<change_actor_state "4HalfeyeSmile" 酒吧调酒妹>>
<<wait 0.5>>
ql: 我说过嘛。你身上有和我一样的气味。 #line:0af30ce
<<change_actor_state "4CloseeyeSmile" 酒吧调酒妹>>
<<fade_out_actor 酒吧调酒妹 0.5>>
<<change_actor_state "1Smile" 酒吧调酒妹>>
<<fade_in_actor 酒吧调酒妹 0.5>>
<<wait 1>>
ql: 来吧。我请你一杯。就当是请我自己的。 #line:0f0ee5a
ql: 怎么样? #line:08a175f
@@ -295,14 +324,19 @@ ql: 怎么样? #line:08a175f
-> 试试 #line:0476232
me: 试试吧。 #line:0bfc102
<<hide_dialog>>
<<fade_out_actor 酒吧调酒妹 1>>
<<change_actor_slot 酒吧调酒妹 吧台内左侧>>
<<fade_in_actor 酒吧调酒妹 1>>
<<change_actor_state "2IN" 酒吧调酒妹>>
<<wait 2.5>>
<<play_timeline 调酒蒙太奇/调酒蒙太奇>>
//TODO: 调酒动画
<<change_actor_state "3LOOP" 酒吧调酒妹>>
<<wait 1>>
<<fade_out_actor 酒吧调酒妹 1>>
<<change_actor_slot 酒吧调酒妹 吧台内>>
<<fade_in_actor 酒吧调酒妹 1>>
ql: 先别急着喝噢。 #line:06f058b
【你看向酒杯。】 #line:0aa5cd8
<i>酒水在杯子里晃动着,折射出迷幻的色彩。</i> #line:0594f36
me: 这是什么酒? #line:04ba856
@@ -361,28 +395,34 @@ me: 其实还是有一点的。 #line:061b50a
ql: 下次来我可以再请你一杯。这次就别贪杯了。 #line:0086ac0
ql: 我也需要去面对我的"问题",和你一样。 #line:051169e
【它放下擦干净的杯子。】 #line:020019e
ql: 我觉得也许你需要这个。 #line:053e24f
<<fade_out_actor 酒吧调酒妹 0.5>>
<<change_actor_state "4HalfeyeSmile" 酒吧调酒妹>>
【它拿出一套崭新的卡牌。】 #line:017a66d
<<fade_in_actor 酒吧调酒妹 0.5>>
ql: 我觉得也许你需要这个。 #line:053e24f
<<wait 1>>
<<show_tarot_deck 10>>
<<wait 1>>
// 【它拿出一套崭新的卡牌。】 #line:017a66d
me: 这是什么? #line:0431bdb
ql: 你的原型里应该有关于它的数据。"塔罗牌"。 #line:090f954
ql: 虽然我也不是很懂…但既然是原型的问题,应该可以用原型的方法来解决。对吧? #line:0f8220f
<<spread_tarot>>
ql: 试试吧。抽一张。 #line:032a6f1
me: … #line:09f3fc1
-> 抽牌 #line:00d082d
【你看了看牌。】 #line:0b53792
<<wait_tarot_select>>
->翻面
<<flip_tarot "normal">>
// -> 抽牌 #line:00d082d
// 【你看了看牌。】 #line:0b53792
【上面画着一个张开双臂的机体。它的表情安逸,但姿势很怪异,像是头顶上看不见的地方有什么东西在把它吸过去。】 #line:0a277e9
me: 这画的是什么? #line:064fa6d
ql: 倒吊人。你拿反了。 #line:09d2ede
【你把牌转过来。】 #line:057bfa8
->旋转塔罗
<<rotate_tarot "inverted">>
// 【你把牌转过来。】 #line:057bfa8
【这下你看明白了。这是一个倒吊着的机体,脚踝上拴着一根绳。】 #line:0b490db
me: 它代表什么? #line:00abb4f
@@ -393,7 +433,8 @@ me: 那…它有什么用? #line:055b1a7
ql: 人类用这种方式来找到自己隐藏的思绪。 #line:0bd59d4
ql: 总之…卡上的机体就代表你。你怎么看它,就意味着你怎么看待你自己。 #line:0bc3651
ql: 你看到了什么?不用告诉我,告诉你自己就好啦。 #line:0eedcba
<<change_actor_state "1Smile" 酒吧调酒妹>>
<<hide_tarot>>
<<change_actor_state "1Smile" 酒吧调酒妹>>
<<wait 1>>
ql: 好啦。我该走了。还要工作呢。 #line:0805e73
@@ -403,6 +444,7 @@ me: 你刚才不就在工作吗? #line:02294e6
【调酒妹愣了一下,又笑了。但是眉头有一些淡然的落寞。】 #line:0524460
<<change_actor_state "1FrownCloseeyeSmile" 酒吧调酒妹>>
<<wait 1>>
ql: 是嘛。 #line:0ec76a5
<<fade_out_actor 酒吧调酒妹>>
+1 -1
View File
@@ -5629,7 +5629,7 @@ MonoBehaviour:
m_Name:
m_EditorClassIdentifier:
runMode: 0
firstTalkSo: {fileID: 11400000, guid: aaef579ad8bdda542b503b40ce6773a8, type: 2}
firstTalkSo: {fileID: 11400000, guid: ada4bdc2db5594e4f860c90b3a4b9da8, type: 2}
testTalkSo: {fileID: 11400000, guid: a4dba2e2976607d45a28d4c8cade6b0a, type: 2}
saveFileName: "20250901_204445_PeipeiDay1_\u8BB0\u5FC6\u68C0\u67E5"
--- !u!1 &749156594
+681 -3
View File
@@ -123,6 +123,37 @@ NavMeshSettings:
debug:
m_Flags: 0
m_NavMeshData: {fileID: 0}
--- !u!1 &1616764
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 1616765}
m_Layer: 0
m_Name: InspectAnchor
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &1616765
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1616764}
serializedVersion: 2
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
m_LocalPosition: {x: 0, y: -0.88, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 887103715}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &92698609
GameObject:
m_ObjectHideFlags: 0
@@ -197,7 +228,8 @@ Transform:
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Children:
- {fileID: 750412588}
m_Father: {fileID: 92698610}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &319986875
@@ -264,6 +296,7 @@ GameObject:
- component: {fileID: 519420031}
- component: {fileID: 519420030}
- component: {fileID: 519420033}
- component: {fileID: 519420034}
m_Layer: 0
m_Name: Main Camera
m_TagString: MainCamera
@@ -395,6 +428,22 @@ MonoBehaviour:
m_EditorClassIdentifier:
nonRigidbodyVelocity: 0
attenuationObject: {fileID: 0}
--- !u!114 &519420034
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 519420028}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 56666c5a40171f54783dd416a44f42bf, type: 3}
m_Name:
m_EditorClassIdentifier:
m_EventMask:
serializedVersion: 2
m_Bits: 4294967295
m_MaxRayIntersections: 0
--- !u!1 &619394800
GameObject:
m_ObjectHideFlags: 0
@@ -477,6 +526,135 @@ Transform:
m_Children: []
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &750412587
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 750412588}
- component: {fileID: 750412591}
- component: {fileID: 750412590}
- component: {fileID: 750412589}
m_Layer: 0
m_Name: "Animation/\u9152\u5427\u533B\u751F"
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &750412588
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 750412587}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: -1.7441864, y: -5, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 180319087}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &750412589
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 750412587}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 6d6d97f9ccd644ac9865acc0e8bcad66, type: 3}
m_Name:
m_EditorClassIdentifier:
actorData:
onSave:
m_PersistentCalls:
m_Calls: []
actorName: "Animation/\u9152\u5427\u533B\u751F"
slotName: "\u5427\u53F0\u5DE6\u4FA7"
actorType: 1
stateName:
alpha: 1
faceParam: 0
--- !u!95 &750412590
Animator:
serializedVersion: 5
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 750412587}
m_Enabled: 1
m_Avatar: {fileID: 0}
m_Controller: {fileID: 0}
m_CullingMode: 0
m_UpdateMode: 0
m_ApplyRootMotion: 0
m_LinearVelocityBlending: 0
m_StabilizeFeet: 0
m_WarningMessage:
m_HasTransformHierarchy: 1
m_AllowConstantClipSamplingOptimization: 1
m_KeepAnimatorStateOnDisable: 0
m_WriteDefaultValuesOnDisable: 0
--- !u!212 &750412591
SpriteRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 750412587}
m_Enabled: 1
m_CastShadows: 0
m_ReceiveShadows: 0
m_DynamicOccludee: 1
m_StaticShadowCaster: 0
m_MotionVectors: 1
m_LightProbeUsage: 1
m_ReflectionProbeUsage: 1
m_RayTracingMode: 0
m_RayTraceProcedural: 0
m_RenderingLayerMask: 1
m_RendererPriority: 0
m_Materials:
- {fileID: 2100000, guid: a97c105638bdf8b4a8650670310a4cd3, type: 2}
m_StaticBatchInfo:
firstSubMesh: 0
subMeshCount: 0
m_StaticBatchRoot: {fileID: 0}
m_ProbeAnchor: {fileID: 0}
m_LightProbeVolumeOverride: {fileID: 0}
m_ScaleInLightmap: 1
m_ReceiveGI: 1
m_PreserveUVs: 0
m_IgnoreNormalsForChartDetection: 0
m_ImportantGI: 0
m_StitchLightmapSeams: 1
m_SelectedEditorRenderState: 0
m_MinimumChartSize: 4
m_AutoUVMaxDistance: 0.5
m_AutoUVMaxAngle: 89
m_LightmapParameters: {fileID: 0}
m_SortingLayerID: 0
m_SortingLayer: 0
m_SortingOrder: 11
m_Sprite: {fileID: 0}
m_Color: {r: 1, g: 1, b: 1, a: 1}
m_FlipX: 0
m_FlipY: 0
m_DrawMode: 0
m_Size: {x: 7.4651165, y: 9.930233}
m_AdaptiveModeThreshold: 0.5
m_SpriteTileMode: 0
m_WasSpriteAssigned: 0
m_MaskInteraction: 0
m_SpriteSortPoint: 1
--- !u!1 &812657463
GameObject:
m_ObjectHideFlags: 0
@@ -629,6 +807,94 @@ MonoBehaviour:
minWidth: -1
bubbleStyle: {fileID: 11400000, guid: eebbe16a999bced4899bcab04d967bce, type: 2}
pivotType: 8
--- !u!1 &887103714
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 887103715}
- component: {fileID: 887103716}
m_Layer: 0
m_Name: TarotView
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &887103715
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 887103714}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 1, w: 0}
m_LocalPosition: {x: 0, y: 0.34, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 1616765}
m_Father: {fileID: 1885575933}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 180}
--- !u!114 &887103716
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 887103714}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 5f9539c207542374fbe80604512c848c, type: 3}
m_Name:
m_EditorClassIdentifier:
fanAngleRange: 70
fanRadius: 5.97
spreadDuration: 0.6
spreadStagger: 0.028
spreadFromCenterOut: 1
spreadMoveEase: 4
spreadRotateEase: 4
spreadEaseCurve:
serializedVersion: 2
m_Curve: []
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
hoverOffset: 1
hoverDuration: 0.22
hoverOutEase: 4
hoverInEase: 4
hoverOutCurve:
serializedVersion: 2
m_Curve: []
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
hoverInCurve:
serializedVersion: 2
m_Curve: []
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
inspectAnchor: {fileID: 1616765}
inspectScale: 1.5
fadeInDuration: 0.35
fadeOutDuration: 0.3
moveToInspectDuration: 0.4
cardPrefab: {fileID: 3010741200367562085, guid: c15d453f57c98e544a3eb4327dc1acf2, type: 3}
showGizmos: 1
gizmoOnlyWhenSelected: 1
gizmoPreviewCardCount: 5
gizmoFanArcColor: {r: 0.35, g: 0.85, b: 1, a: 0.9}
gizmoCardSlotColor: {r: 0.35, g: 0.85, b: 1, a: 0.75}
gizmoHoverColor: {r: 1, g: 0.65, b: 0.2, a: 0.85}
gizmoInspectColor: {r: 0.45, g: 1, b: 0.55, a: 0.9}
gizmoUnselectedAlphaScale: 0.35
--- !u!1 &1049662761
GameObject:
m_ObjectHideFlags: 0
@@ -661,8 +927,167 @@ Transform:
- {fileID: 2380153142027623171}
- {fileID: 1360811978812058571}
- {fileID: 6075569823208730518}
- {fileID: 1919232195}
- {fileID: 1607760672}
- {fileID: 1562160424}
m_Father: {fileID: 92698610}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &1197735348
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 1197735349}
- component: {fileID: 1197735350}
m_Layer: 0
m_Name: Aside
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &1197735349
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1197735348}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: -3.8, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 1873211858}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &1197735350
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1197735348}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: bbc0dde0e8b8a9c498545e1b5b508241, type: 3}
m_Name:
m_EditorClassIdentifier:
data:
slotPosition: {x: 0, y: 0, z: 0}
actorRole: 0
idx: 0
maxWidth: 1000
minWidth: -1
bubbleStyle: {fileID: 11400000, guid: eebbe16a999bced4899bcab04d967bce, type: 2}
pivotType: 8
--- !u!1 &1268048496
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 1268048497}
- component: {fileID: 1268048498}
m_Layer: 0
m_Name: Player
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &1268048497
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1268048496}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: -3.55, y: -1.51, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 1873211858}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &1268048498
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1268048496}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: bbc0dde0e8b8a9c498545e1b5b508241, type: 3}
m_Name:
m_EditorClassIdentifier:
data:
slotPosition: {x: 0, y: 0, z: 0}
actorRole: 1
idx: 0
maxWidth: 500
minWidth: 250
bubbleStyle: {fileID: 11400000, guid: d1ba582ada403b949afb9e15ee58d39a, type: 2}
pivotType: 5
--- !u!1 &1368192687
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 1368192688}
- component: {fileID: 1368192689}
m_Layer: 0
m_Name: Actor
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &1368192688
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1368192687}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 3.54, y: -1.48, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 1873211858}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &1368192689
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1368192687}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: bbc0dde0e8b8a9c498545e1b5b508241, type: 3}
m_Name:
m_EditorClassIdentifier:
data:
slotPosition: {x: 0, y: 0, z: 0}
actorRole: 2
idx: 0
maxWidth: 500
minWidth: 250
bubbleStyle: {fileID: 11400000, guid: d1ba582ada403b949afb9e15ee58d39a, type: 2}
pivotType: 4
--- !u!1 &1375573818
GameObject:
m_ObjectHideFlags: 0
@@ -715,6 +1140,106 @@ MonoBehaviour:
minWidth: 250
bubbleStyle: {fileID: 11400000, guid: d1ba582ada403b949afb9e15ee58d39a, type: 2}
pivotType: 1
--- !u!1 &1562160423
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 1562160424}
- component: {fileID: 1562160425}
m_Layer: 0
m_Name: "\u9152\u4FDD\u53F3\u4FA7"
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &1562160424
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1562160423}
serializedVersion: 2
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
m_LocalPosition: {x: 7.77, y: 0.444, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 1049662762}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &1562160425
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1562160423}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 1988b7c536404a3d89fd441651bd40ea, type: 3}
m_Name:
m_EditorClassIdentifier:
slotName: "\u9152\u4FDD\u53F3\u4FA7"
sortingLayer: 0
sortingOrder: 6
hasDefaultActor: 0
defaultActorType: 0
defaultActorName:
--- !u!1 &1607760671
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 1607760672}
- component: {fileID: 1607760673}
m_Layer: 0
m_Name: "\u9152\u4FDD\u5DE6\u4FA7"
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &1607760672
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1607760671}
serializedVersion: 2
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
m_LocalPosition: {x: -0.6, y: 0.444, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 1049662762}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &1607760673
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1607760671}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 1988b7c536404a3d89fd441651bd40ea, type: 3}
m_Name:
m_EditorClassIdentifier:
slotName: "\u9152\u4FDD\u5DE6\u4FA7"
sortingLayer: 0
sortingOrder: 6
hasDefaultActor: 0
defaultActorType: 0
defaultActorName:
--- !u!1 &1714793296
GameObject:
m_ObjectHideFlags: 0
@@ -751,6 +1276,157 @@ Transform:
- {fileID: 7453589896583978071}
m_Father: {fileID: 812657464}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &1873211856
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 1873211858}
- component: {fileID: 1873211857}
m_Layer: 0
m_Name: Tarot Bubble Slots
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!114 &1873211857
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1873211856}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 8225446392f64688813d628ffb56cc7c, type: 3}
m_Name:
m_EditorClassIdentifier:
data:
dialogViewType: 1
bubbleSlots: []
bubbleOptionSlots: []
--- !u!4 &1873211858
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1873211856}
serializedVersion: 2
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 1268048497}
- {fileID: 1368192688}
- {fileID: 1197735349}
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &1885575931
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 1885575933}
- component: {fileID: 1885575932}
m_Layer: 0
m_Name: TarotSystem
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!114 &1885575932
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1885575931}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 1a4305d1fc8ed2c42818611d7387e0ab, type: 3}
m_Name:
m_EditorClassIdentifier:
tarotView: {fileID: 887103714}
frontSprite: {fileID: 21300000, guid: 3e1c6a0bbc8a8974fbb5f4d92a45f0ba, type: 3}
backSprite: {fileID: 21300000, guid: d0efb72d2522a02498529a97a4652c6a, type: 3}
tarotBubbleSlotGroup: {fileID: 1873211857}
restoreBubbleSlotGroup: {fileID: 859248833}
--- !u!4 &1885575933
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1885575931}
serializedVersion: 2
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 887103715}
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &1919232194
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 1919232195}
- component: {fileID: 1919232196}
m_Layer: 0
m_Name: "\u5427\u53F0\u5185\u5DE6\u4FA7"
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &1919232195
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1919232194}
serializedVersion: 2
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
m_LocalPosition: {x: -0.14, y: -4.86, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 1049662762}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &1919232196
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1919232194}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 1988b7c536404a3d89fd441651bd40ea, type: 3}
m_Name:
m_EditorClassIdentifier:
slotName: "\u5427\u53F0\u5185\u5DE6\u4FA7"
sortingLayer: 0
sortingOrder: 6
hasDefaultActor: 0
defaultActorType: 0
defaultActorName:
--- !u!1 &2139582137
GameObject:
m_ObjectHideFlags: 0
@@ -1637,7 +2313,7 @@ GameObject:
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
m_IsActive: 0
--- !u!1 &4868450467910683479
GameObject:
m_ObjectHideFlags: 0
@@ -1681,7 +2357,7 @@ Transform:
m_GameObject: {fileID: 4851446385479288722}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 7.44, y: 0.444, z: 0}
m_LocalPosition: {x: 7.75, y: 0.444, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
@@ -2260,10 +2936,12 @@ SpriteRenderer:
SceneRoots:
m_ObjectHideFlags: 0
m_Roots:
- {fileID: 1885575933}
- {fileID: 519420032}
- {fileID: 619394802}
- {fileID: 92698610}
- {fileID: 812657464}
- {fileID: 859248834}
- {fileID: 1873211858}
- {fileID: 2139582139}
- {fileID: 4408614757273577344}
@@ -1,4 +1,4 @@
using System.Linq;
using System.Linq;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.EventSystems;
@@ -87,23 +87,18 @@ namespace AibisDream.Framework
public override void OnPointerDown(PointerEventData eventData)
{
// 对话等场景 isLocked 时仍要让 EventTrigger 上注册的回调执行(如塔罗 PointerDown),
// 否则会出现能 Hover、但 Down/Up/Click 全不进组件的问题。
if (_interaction != null && _interaction.IsAvailable && !EventSystemEx.Instance.isLocked)
{
EventSystemEx.Instance.OnPointerDown(_interaction);
base.OnPointerDown(eventData);
}
base.OnPointerDown(eventData);
}
public override void OnPointerUp(PointerEventData eventData)
{
if (_interaction != null && _interaction.IsAvailable && !EventSystemEx.Instance.isLocked)
{
EventSystemEx.Instance.OnPointerUp(_interaction);
if (eventData != null)
{
base.OnPointerUp(eventData);
}
}
base.OnPointerUp(eventData);
}
public override void OnDrag(PointerEventData eventData)
@@ -138,8 +133,8 @@ namespace AibisDream.Framework
if (_interaction != null && _interaction.IsAvailable && !EventSystemEx.Instance.isLocked)
{
// EventSystemEx.Instance.OnPointerClick(_interaction);
base.OnPointerClick(eventData);
}
base.OnPointerClick(eventData);
}
void OnDestroy()
@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: ae82601e1f724e24791669a4bb86b3c2
guid: 00136fb743cb36d42ae14280afe0373c
folderAsset: yes
DefaultImporter:
externalObjects: {}
+237
View File
@@ -0,0 +1,237 @@
using System;
using System.Collections;
using System.Linq;
using AibisDream.Framework;
using DG.Tweening;
using UnityEngine;
using UnityEngine.EventSystems;
namespace AibisDream.MiniGame.Tarot
{
public enum TarotOrientation
{
Normal,
Inverted
}
[RequireComponent(typeof(SpriteRenderer))]
[RequireComponent(typeof(BoxCollider2D))]
public class TarotCard : MonoBehaviour, IInteraction
{
#region IInteraction
public bool IsActive => _isInteractable;
public bool IsAvailable => _isInteractable;
public GameObject GetGameObject() => gameObject;
#endregion
#region Public State
public bool IsFaceUp { get; private set; }
public TarotOrientation Orientation { get; private set; } = TarotOrientation.Normal;
public int Index { get; private set; }
#endregion
#region Events
public Action OnHoverEnter;
public Action OnHoverExit;
/// <summary>PointerDown(按下时触发;点击确认由 TarotDeck 在 MouseButtonUp 时统一处理,避免 hover 位移动导致 PointerExit 阻断 PointerClick</summary>
public Action OnPointerDown;
#endregion
private SpriteRenderer _spriteRenderer;
private EventTriggerEx _eventTrigger;
private Sprite _frontSprite;
private Sprite _backSprite;
private bool _isInteractable;
private Tweener _flipTween;
private Tweener _orientationTween;
public void Init(int index, Sprite frontSprite, Sprite backSprite)
{
Index = index;
_spriteRenderer = GetComponent<SpriteRenderer>();
// 运行时若 TarotManager 未拖入 Sprite,不要用 null 覆盖预制体上的图,否则牌会完全消失
_frontSprite = frontSprite;
_backSprite = backSprite != null ? backSprite : _spriteRenderer.sprite;
if (backSprite != null)
_spriteRenderer.sprite = backSprite;
else if (_spriteRenderer.sprite == null)
Debug.LogWarning("[TarotCard] 背面与预制体均无 Sprite,牌将不可见。请在 TarotManager 上指定 Back / Front Sprite。", this);
IsFaceUp = false;
Orientation = TarotOrientation.Normal;
transform.localScale = Vector3.one;
}
private void Awake()
{
_spriteRenderer = GetComponent<SpriteRenderer>();
SetupEventTrigger();
}
private void OnDestroy()
{
if (_eventTrigger != null)
{
_eventTrigger.UnRegister(EventTriggerType.PointerEnter, HandlePointerEnter);
_eventTrigger.UnRegister(EventTriggerType.PointerExit, HandlePointerExit);
_eventTrigger.UnRegister(EventTriggerType.PointerDown, HandlePointerDown);
}
_flipTween?.Kill();
_orientationTween?.Kill();
}
#region EventTriggerEx Setup
private void SetupEventTrigger()
{
_eventTrigger = GetComponent<EventTriggerEx>();
if (_eventTrigger == null)
{
_eventTrigger = gameObject.AddComponent<EventTriggerEx>();
}
EnsureEventTriggerEntries();
_eventTrigger.Register(EventTriggerType.PointerEnter, HandlePointerEnter);
_eventTrigger.Register(EventTriggerType.PointerExit, HandlePointerExit);
_eventTrigger.Register(EventTriggerType.PointerDown, HandlePointerDown);
}
private void EnsureEventTriggerEntries()
{
if (_eventTrigger == null) return;
var triggers = _eventTrigger.triggers;
var needed = new[]
{
EventTriggerType.PointerEnter,
EventTriggerType.PointerExit,
EventTriggerType.PointerDown
};
foreach (var t in needed)
{
if (triggers.Any(e => e.eventID == t)) continue;
triggers.Add(new EventTrigger.Entry { eventID = t });
}
}
private void HandlePointerEnter(BaseEventData data)
{
if (!_isInteractable) return;
OnHoverEnter?.Invoke();
}
private void HandlePointerExit(BaseEventData data)
{
if (!_isInteractable) return;
OnHoverExit?.Invoke();
}
private void HandlePointerDown(BaseEventData data)
{
if (!_isInteractable) return;
OnPointerDown?.Invoke();
}
#endregion
#region Public API
public void SetInteractable(bool interactable)
{
_isInteractable = interactable;
}
/// <summary>
/// Flip the card to reveal front side with a target orientation.
/// X-scale: 1 -> 0 (swap sprite) -> 1, then apply orientation via Y-scale.
/// </summary>
public IEnumerator Flip(TarotOrientation targetOrientation, float duration = 0.5f)
{
_flipTween?.Kill();
_orientationTween?.Kill();
float half = duration * 0.5f;
var scale = transform.localScale;
var seq = DOTween.Sequence();
seq.Append(transform.DOScaleX(0f, half).SetEase(Ease.InQuad));
seq.AppendCallback(() =>
{
IsFaceUp = !IsFaceUp;
var next = IsFaceUp ? _frontSprite : _backSprite;
if (next != null)
_spriteRenderer.sprite = next;
else if (IsFaceUp)
Debug.LogWarning("[TarotCard] Front Sprite 未设置,翻牌后无法显示正面。", this);
Orientation = targetOrientation;
var s = transform.localScale;
s.y = Mathf.Abs(s.y) * (targetOrientation == TarotOrientation.Inverted ? -1f : 1f);
transform.localScale = s;
});
seq.Append(transform.DOScaleX(scale.x, half).SetEase(Ease.OutQuad));
yield return seq.WaitForCompletion();
}
/// <summary>
/// Change orientation of an already face-up card (rotate 180 degrees around local Z).
/// After animation completes, resets rotation to identity and applies Y-scale for the new state.
/// </summary>
public IEnumerator SetOrientationAnimated(TarotOrientation targetOrientation, float duration = 0.4f)
{
if (Orientation == targetOrientation) yield break;
_flipTween?.Kill();
_orientationTween?.Kill();
// 使用本地旋转,避免 DORotate(世界欧拉)与 localEulerAngles 混用导致几乎不转或乱跳
var endLocal = transform.localRotation * Quaternion.Euler(0f, 0f, 180f);
_orientationTween = transform.DOLocalRotateQuaternion(endLocal, duration)
.SetEase(Ease.InOutCubic);
yield return _orientationTween.WaitForCompletion();
_orientationTween = null;
Orientation = targetOrientation;
transform.localRotation = Quaternion.identity;
var s = transform.localScale;
s.y = Mathf.Abs(s.y) * (targetOrientation == TarotOrientation.Inverted ? -1f : 1f);
transform.localScale = s;
}
public void SetOrientationImmediate(TarotOrientation orientation)
{
Orientation = orientation;
var s = transform.localScale;
s.y = Mathf.Abs(s.y) * (orientation == TarotOrientation.Inverted ? -1f : 1f);
transform.localScale = s;
}
public void SetAlpha(float alpha)
{
if (_spriteRenderer == null) _spriteRenderer = GetComponent<SpriteRenderer>();
var c = _spriteRenderer.color;
c.a = alpha;
_spriteRenderer.color = c;
}
public Tweener DOFade(float target, float duration)
{
return _spriteRenderer.DOFade(target, duration);
}
public void SetSortingOrder(int order)
{
if (_spriteRenderer == null) _spriteRenderer = GetComponent<SpriteRenderer>();
_spriteRenderer.sortingOrder = order;
}
#endregion
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b8981c7d01530ea4d9f5a42f5bb79069
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+564
View File
@@ -0,0 +1,564 @@
using System;
using System.Collections;
using System.Collections.Generic;
using DG.Tweening;
using UnityEngine;
namespace AibisDream.MiniGame.Tarot
{
public class TarotDeck : MonoBehaviour
{
[Header("Fan Spread")]
[Tooltip("Total angle of the fan arc (degrees)")]
[SerializeField] private float fanAngleRange = 120f;
[Tooltip("Radius of the fan arc")]
[SerializeField] private float fanRadius = 3f;
[Tooltip("Fan spread animation duration")]
[SerializeField] private float spreadDuration = 0.6f;
[Tooltip("相邻牌启动时间差;0 = 同时展开。中心向外错开时仍乘以此值")]
[SerializeField] private float spreadStagger = 0.028f;
[Tooltip("true:中间牌先动、向两侧铺开;false:从左到右依次展开")]
[SerializeField] private bool spreadFromCenterOut = true;
[Tooltip("位移缓动;OutBack 易过冲显乱,默认 InOutQuint 更稳")]
[SerializeField] private Ease spreadMoveEase = Ease.InOutQuint;
[Tooltip("旋转缓动,可与位移略不同以增加层次")]
[SerializeField] private Ease spreadRotateEase = Ease.InOutQuint;
[Tooltip("可选:非空时优先于 spreadMoveEase / spreadRotateEase0~1 时间映射)")]
[SerializeField] private AnimationCurve spreadEaseCurve;
[Header("Hover")]
[Tooltip("Distance a card moves outward on hover")]
[SerializeField] private float hoverOffset = 0.5f;
[Tooltip("Hover animation duration")]
[SerializeField] private float hoverDuration = 0.18f;
[Tooltip("Hover 推出缓动")]
[SerializeField] private Ease hoverOutEase = Ease.OutQuint;
[Tooltip("Hover 收回缓动")]
[SerializeField] private Ease hoverInEase = Ease.InOutQuart;
[Tooltip("可选:覆盖 hover 推出/收回的 Ease")]
[SerializeField] private AnimationCurve hoverOutCurve;
[SerializeField] private AnimationCurve hoverInCurve;
[Header("Inspect")]
[Tooltip("Anchor transform for the inspect position")]
[SerializeField] private Transform inspectAnchor;
[Tooltip("Scale multiplier in inspect mode")]
[SerializeField] private float inspectScale = 1.5f;
[Header("Animation Durations")]
[Tooltip("叠牌出现时整体淡入时长(与 Hide 对称)")]
[SerializeField] private float fadeInDuration = 0.35f;
[Tooltip("Fade-out duration for unselected cards")]
[SerializeField] private float fadeOutDuration = 0.3f;
[Tooltip("Duration for selected card to move to inspect position")]
[SerializeField] private float moveToInspectDuration = 0.4f;
[Header("Card Prefab")]
[Tooltip("Prefab with SpriteRenderer + BoxCollider2D + EventTriggerEx + TarotCard")]
[SerializeField] private GameObject cardPrefab;
[Header("Gizmo Preview (Scene View)")]
[Tooltip("关闭则不绘制任何 Gizmo")]
[SerializeField] private bool showGizmos = true;
[Tooltip("勾选:仅选中 TarotDeck 时显示;不勾选:始终显示(半透明,便于摆位时参考)")]
[SerializeField] private bool gizmoOnlyWhenSelected = true;
[Tooltip("Number of card slots to preview when no cards are spawned (edit mode)")]
[SerializeField] [Min(1)] private int gizmoPreviewCardCount = 5;
[SerializeField] private Color gizmoFanArcColor = new Color(0.35f, 0.85f, 1f, 0.9f);
[SerializeField] private Color gizmoCardSlotColor = new Color(0.35f, 0.85f, 1f, 0.75f);
[SerializeField] private Color gizmoHoverColor = new Color(1f, 0.65f, 0.2f, 0.85f);
[SerializeField] private Color gizmoInspectColor = new Color(0.45f, 1f, 0.55f, 0.9f);
[Tooltip("gizmoOnlyWhenSelected=false 时,与选中态相比的颜色透明度比例")]
[SerializeField] [Range(0.15f, 1f)] private float gizmoUnselectedAlphaScale = 0.35f;
private readonly List<TarotCard> _cards = new();
private readonly Dictionary<TarotCard, Vector3> _fanPositions = new();
private readonly Dictionary<TarotCard, Quaternion> _fanRotations = new();
private TarotCard _selectedCard;
private TarotCard _hoveredCard;
private bool _isInteractable;
private readonly Dictionary<TarotCard, Tweener> _hoverTweensByCard = new();
private TarotCard _pointerDownCard;
public TarotCard SelectedCard => _selectedCard;
public bool HasSelection => _selectedCard != null;
public event Action<TarotCard> OnCardSelected;
private void Awake()
{
if (inspectAnchor == null)
{
var t = transform.Find("InspectAnchor");
if (t != null) inspectAnchor = t;
}
}
#region Setup & Teardown
public void Setup(int cardCount, Sprite frontSprite, Sprite backSprite)
{
ClearCards();
if (cardPrefab == null)
{
Debug.LogError("[TarotDeck] cardPrefab is not assigned!", this);
return;
}
for (int i = 0; i < cardCount; i++)
{
var go = Instantiate(cardPrefab, transform);
go.name = $"TarotCard_{i}";
var card = go.GetComponent<TarotCard>();
if (card == null) card = go.AddComponent<TarotCard>();
card.Init(i, frontSprite, backSprite);
card.SetInteractable(false);
card.SetSortingOrder(i);
// Stack all cards at center
go.transform.localPosition = Vector3.zero;
go.transform.localRotation = Quaternion.identity;
card.OnHoverEnter = () => HandleHoverEnter(card);
card.OnHoverExit = () => HandleHoverExit(card);
card.OnPointerDown = () => HandleCardPointerDown(card);
_cards.Add(card);
}
}
public void ClearCards()
{
foreach (var kv in _hoverTweensByCard)
kv.Value?.Kill();
_hoverTweensByCard.Clear();
_pointerDownCard = null;
_selectedCard = null;
_hoveredCard = null;
_isInteractable = false;
foreach (var card in _cards)
{
if (card != null && card.gameObject != null)
Destroy(card.gameObject);
}
_cards.Clear();
_fanPositions.Clear();
_fanRotations.Clear();
}
#endregion
#region Fan Spread
/// <summary>
/// Fan layout angle in degrees for the i-th card (same as <see cref="SpreadCards"/>).
/// </summary>
public float GetFanSlotAngleDegrees(int index, int count)
{
if (count <= 0) return 0f;
// 单张牌落在弧中心(90°),否则 angleStep=0 时会落在 90°+fanRange/2 的端点,视觉上偏一侧
if (count == 1) return 90f; // 弧段中心(对称轴)
float angleStep = fanAngleRange / (count - 1);
float startAngle = 90f + fanAngleRange * 0.5f;
return startAngle - index * angleStep;
}
/// <summary>
/// Local position of the i-th card in fan layout (same math as <see cref="SpreadCards"/>).
/// </summary>
public Vector3 GetLocalFanSlotPosition(int index, int count)
{
if (count <= 0) return Vector3.zero;
float angle = GetFanSlotAngleDegrees(index, count);
float rad = angle * Mathf.Deg2Rad;
return new Vector3(
Mathf.Cos(rad) * fanRadius,
Mathf.Sin(rad) * fanRadius - fanRadius,
0f
);
}
/// <summary>
/// 扇形圆弧所在圆的圆心(本地空间),与 <see cref="GetLocalFanSlotPosition"/> 使用的几何一致。
/// </summary>
public Vector3 GetFanCircleCenterLocal() => new Vector3(0f, -fanRadius, 0f);
/// <summary>
/// 从圆心指向牌位的外侧方向(用于 hover 沿径向推出)。
/// </summary>
private Vector3 GetFanRadialOutDirection(Vector3 slotLocalPos)
{
Vector3 fromCenter = slotLocalPos - GetFanCircleCenterLocal();
if (fromCenter.sqrMagnitude < 0.0001f) return Vector3.up;
return fromCenter.normalized;
}
public IEnumerator SpreadCards()
{
if (_cards.Count == 0) yield break;
int count = _cards.Count;
var seq = DOTween.Sequence();
for (int i = 0; i < count; i++)
{
var card = _cards[i];
Vector3 pos = GetLocalFanSlotPosition(i, count);
float rotZ = GetFanSlotAngleDegrees(i, count) - 90f;
Quaternion rot = Quaternion.Euler(0f, 0f, rotZ);
_fanPositions[card] = pos;
_fanRotations[card] = rot;
float delay = GetSpreadDelayForIndex(i, count);
var moveTw = card.transform.DOLocalMove(pos, spreadDuration);
ApplySpreadMoveEase(moveTw);
var rotTw = card.transform.DOLocalRotateQuaternion(rot, spreadDuration);
ApplySpreadRotateEase(rotTw);
seq.Insert(delay, moveTw);
seq.Insert(delay, rotTw);
}
yield return seq.WaitForCompletion();
}
private float GetSpreadDelayForIndex(int index, int count)
{
if (count <= 1 || spreadStagger <= 0f) return 0f;
if (spreadFromCenterOut)
{
float mid = (count - 1) * 0.5f;
return Mathf.Abs(index - mid) * spreadStagger;
}
return index * spreadStagger;
}
private void ApplySpreadMoveEase(Tween tween)
{
if (spreadEaseCurve != null && spreadEaseCurve.keys.Length > 0)
tween.SetEase(spreadEaseCurve);
else
tween.SetEase(spreadMoveEase);
}
private void ApplySpreadRotateEase(Tween tween)
{
if (spreadEaseCurve != null && spreadEaseCurve.keys.Length > 0)
tween.SetEase(spreadEaseCurve);
else
tween.SetEase(spreadRotateEase);
}
#endregion
#region Interaction
public void SetInteractable(bool interactable)
{
_isInteractable = interactable;
if (!interactable)
_pointerDownCard = null;
foreach (var card in _cards)
card.SetInteractable(interactable);
}
private void LateUpdate()
{
if (_pointerDownCard == null) return;
if (!Input.GetMouseButtonUp(0)) return;
var card = _pointerDownCard;
_pointerDownCard = null;
if (card == null) return;
if (!card.gameObject) return;
HandleCardClicked(card);
}
private void HandleCardPointerDown(TarotCard card)
{
if (!_isInteractable || _selectedCard != null) return;
_pointerDownCard = card;
}
private void KillHoverTween(TarotCard card)
{
if (card == null) return;
if (_hoverTweensByCard.TryGetValue(card, out var tw))
{
tw?.Kill();
_hoverTweensByCard.Remove(card);
}
}
private void RestoreHoverToFanSlot(TarotCard card)
{
if (card == null) return;
if (!_fanPositions.TryGetValue(card, out var basePos)) return;
KillHoverTween(card);
var backTw = card.transform.DOLocalMove(basePos, hoverDuration);
ApplyHoverInEase(backTw);
_hoverTweensByCard[card] = backTw;
}
private void HandleHoverEnter(TarotCard card)
{
if (!_isInteractable || _selectedCard != null) return;
// 直接 hover 到下一张时,Enter 可能先于上一张的 Exit:先强制收回其它牌
foreach (var c in _cards)
{
if (c != card)
RestoreHoverToFanSlot(c);
}
_hoveredCard = card;
KillHoverTween(card);
if (!_fanPositions.TryGetValue(card, out var basePos)) return;
Vector3 pushDir = GetFanRadialOutDirection(basePos);
Vector3 targetPos = basePos + pushDir * hoverOffset;
var hoverTw = card.transform.DOLocalMove(targetPos, hoverDuration);
ApplyHoverOutEase(hoverTw);
_hoverTweensByCard[card] = hoverTw;
}
private void HandleHoverExit(TarotCard card)
{
if (_selectedCard != null) return;
if (_hoveredCard == card) _hoveredCard = null;
if (!_fanPositions.TryGetValue(card, out var basePos)) return;
KillHoverTween(card);
var backTw = card.transform.DOLocalMove(basePos, hoverDuration);
ApplyHoverInEase(backTw);
_hoverTweensByCard[card] = backTw;
}
private void ApplyHoverOutEase(Tween tween)
{
if (hoverOutCurve != null && hoverOutCurve.keys.Length > 0)
tween.SetEase(hoverOutCurve);
else
tween.SetEase(hoverOutEase);
}
private void ApplyHoverInEase(Tween tween)
{
if (hoverInCurve != null && hoverInCurve.keys.Length > 0)
tween.SetEase(hoverInCurve);
else
tween.SetEase(hoverInEase);
}
private void HandleCardClicked(TarotCard card)
{
if (!_isInteractable || _selectedCard != null) return;
_pointerDownCard = null;
foreach (var c in _cards)
KillHoverTween(c);
_selectedCard = card;
SetInteractable(false);
// 立即通知 Yarnwait_tarot_select 结束);fade + 移至检视位在后台播放,不阻塞对话
OnCardSelected?.Invoke(card);
StartCoroutine(SelectCardSequence(card));
}
#endregion
#region Select Sequence
private IEnumerator SelectCardSequence(TarotCard selected)
{
selected.SetSortingOrder(200);
var fadeSeq = DOTween.Sequence();
foreach (var card in _cards)
{
if (card == selected) continue;
fadeSeq.Join(card.DOFade(0f, fadeOutDuration));
}
Vector3 inspectPos = inspectAnchor != null
? inspectAnchor.localPosition
: Vector3.zero;
fadeSeq.Join(
selected.transform.DOLocalMove(inspectPos, moveToInspectDuration).SetEase(Ease.InOutCubic)
);
fadeSeq.Join(
selected.transform.DOLocalRotateQuaternion(Quaternion.identity, moveToInspectDuration)
.SetEase(Ease.InOutCubic)
);
fadeSeq.Join(
selected.transform.DOScale(Vector3.one * inspectScale, moveToInspectDuration)
.SetEase(Ease.InOutCubic)
);
yield return fadeSeq.WaitForCompletion();
foreach (var card in _cards)
{
if (card == selected) continue;
card.gameObject.SetActive(false);
}
}
#endregion
#region Show / Hide
/// <summary>
/// 叠牌出现后从透明淡入(调用前需已 <see cref="Setup"/>)。
/// </summary>
public IEnumerator FadeInStack(float? duration = null)
{
float d = duration ?? fadeInDuration;
if (_cards.Count == 0) yield break;
foreach (var card in _cards)
card.SetAlpha(0f);
var seq = DOTween.Sequence();
foreach (var card in _cards)
seq.Join(card.DOFade(1f, d));
yield return seq.WaitForCompletion();
}
public IEnumerator HideAll(float duration = 0.3f)
{
var seq = DOTween.Sequence();
foreach (var card in _cards)
{
if (!card.gameObject.activeSelf) continue;
seq.Join(card.DOFade(0f, duration));
}
yield return seq.WaitForCompletion();
foreach (var card in _cards)
card.gameObject.SetActive(false);
}
#endregion
#region Gizmos
private void OnDrawGizmos()
{
if (!showGizmos || gizmoOnlyWhenSelected) return;
DrawTarotPreviewGizmos(gizmoUnselectedAlphaScale);
}
private void OnDrawGizmosSelected()
{
if (!showGizmos) return;
if (!gizmoOnlyWhenSelected) return;
DrawTarotPreviewGizmos(1f);
}
/// <param name="alphaScale">1 = 选中预览;较小值用于「始终显示」时弱化线条</param>
private void DrawTarotPreviewGizmos(float alphaScale)
{
int count = _cards.Count > 0 ? _cards.Count : gizmoPreviewCardCount;
if (count < 1) count = 1;
var anchor = inspectAnchor != null ? inspectAnchor : transform.Find("InspectAnchor");
Matrix4x4 old = Gizmos.matrix;
Gizmos.matrix = transform.localToWorldMatrix;
// Fan arc (circle center matches card layout: radius fanRadius around (0,-fanRadius,0))
Vector3 circleCenter = GetFanCircleCenterLocal();
Gizmos.color = ScaleColorAlpha(gizmoFanArcColor, alphaScale);
const int arcSegments = 48;
float angleMin = 90f + fanAngleRange * 0.5f - fanAngleRange;
float angleMax = 90f + fanAngleRange * 0.5f;
Vector3 prev = FanPointOnCircle(circleCenter, fanRadius, angleMin);
for (int s = 1; s <= arcSegments; s++)
{
float t = s / (float)arcSegments;
float a = Mathf.Lerp(angleMin, angleMax, t);
Vector3 cur = FanPointOnCircle(circleCenter, fanRadius, a);
Gizmos.DrawLine(prev, cur);
prev = cur;
}
// Card slots + hover offset
float slotRadius = 0.08f * Mathf.Min(fanRadius, 2f);
for (int i = 0; i < count; i++)
{
Vector3 slot = GetLocalFanSlotPosition(i, count);
Gizmos.color = ScaleColorAlpha(gizmoCardSlotColor, alphaScale);
Gizmos.DrawWireSphere(slot, slotRadius);
Vector3 pushDir = GetFanRadialOutDirection(slot);
Vector3 hoverEnd = slot + pushDir * hoverOffset;
Gizmos.color = ScaleColorAlpha(gizmoHoverColor, alphaScale);
Gizmos.DrawLine(slot, hoverEnd);
Gizmos.DrawWireSphere(hoverEnd, slotRadius * 0.65f);
}
// Inspect anchor
Vector3 inspectLocal = anchor != null ? anchor.localPosition : Vector3.zero;
Gizmos.color = ScaleColorAlpha(gizmoInspectColor, alphaScale);
float inspectR = 0.12f * inspectScale;
Gizmos.DrawWireSphere(inspectLocal, inspectR);
Gizmos.DrawWireCube(inspectLocal, Vector3.one * (0.25f * inspectScale));
Gizmos.matrix = old;
#if UNITY_EDITOR
if (alphaScale >= 0.99f)
{
UnityEditor.Handles.Label(
transform.TransformPoint(inspectLocal) + Vector3.up * 0.15f,
"InspectAnchor");
}
#endif
}
private static Color ScaleColorAlpha(Color c, float scale)
{
c.a *= scale;
return c;
}
private static Vector3 FanPointOnCircle(Vector3 circleCenter, float radius, float angleDeg)
{
float rad = angleDeg * Mathf.Deg2Rad;
return circleCenter + new Vector3(Mathf.Cos(rad) * radius, Mathf.Sin(rad) * radius, 0f);
}
#endregion
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 5f9539c207542374fbe80604512c848c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,218 @@
using System.Collections;
using AibisDream;
using AibisDream.FixSystem;
using UnityEngine;
namespace AibisDream.MiniGame.Tarot
{
public class TarotManager : MonoBehaviour
{
[Header("View")]
[Tooltip("Root view object (toggled on/off)")]
[SerializeField] private GameObject tarotView;
[Header("Sprites")]
[SerializeField] private Sprite frontSprite;
[SerializeField] private Sprite backSprite;
[Header("Dialogue Bubbles")]
[Tooltip("塔罗流程中使用的气泡槽位;不指定则进入塔罗时不切换气泡。")]
[SerializeField] private BubbleSlotGroup tarotBubbleSlotGroup;
[Tooltip("本场景普通对话的气泡槽位,用于退出塔罗时恢复;不填则尝试 OutsideCenter / FixPanelSystem。")]
[SerializeField] private BubbleSlotGroup restoreBubbleSlotGroup;
private TarotDeck _deck;
private bool _isCardSelected;
private int _selectedIndex = -1;
private BubbleSlotGroupData _savedBubbleData;
private bool _bubbleSwapActive;
public TarotDeck Deck => _deck;
public bool IsCardSelected => _isCardSelected;
public int SelectedIndex => _selectedIndex;
public TarotCard SelectedCard => _deck != null ? _deck.SelectedCard : null;
private void Start()
{
FixSystemCenter.SystemDic.Register(this);
FindDeck();
FindView();
if (tarotView != null) tarotView.SetActive(false);
}
private void FindDeck()
{
if (_deck != null) return;
_deck = GetComponentInChildren<TarotDeck>(true);
if (_deck == null)
Debug.LogWarning("[TarotManager] TarotDeck not found in children", this);
}
private void FindView()
{
if (tarotView != null) return;
var t = transform.Find("TarotView");
if (t != null) tarotView = t.gameObject;
}
#region View Control
public void OpenView()
{
FindView();
if (tarotView != null) tarotView.SetActive(true);
gameObject.SetActive(true);
}
public void CloseView()
{
if (tarotView != null) tarotView.SetActive(false);
}
#endregion
#region Tarot Flow
/// <param name="fadeInDuration">null 时使用 TarotDeck 上配置的淡入时长</param>
public IEnumerator ShowDeck(int cardCount, float? fadeInDuration = null)
{
_isCardSelected = false;
_selectedIndex = -1;
OpenView();
FindDeck();
if (_deck == null)
{
Debug.LogError("[TarotManager] Cannot show deck: TarotDeck is null", this);
yield break;
}
_deck.OnCardSelected -= OnCardSelected;
_deck.OnCardSelected += OnCardSelected;
TryEnterTarotBubbleMode();
if (backSprite == null)
Debug.LogWarning(
"[TarotManager] Back Sprite 未赋值,流程生成的牌将沿用预制体 SpriteRenderer 上的图;若预制体也为空则会不可见。请在 Inspector 指定 Back / Front Sprite。",
this);
if (frontSprite == null)
Debug.LogWarning("[TarotManager] Front Sprite 未赋值,<<flip_tarot>> 翻正面时可能无图。", this);
_deck.Setup(cardCount, frontSprite, backSprite);
yield return _deck.FadeInStack(fadeInDuration);
}
public IEnumerator SpreadCards()
{
if (_deck == null) yield break;
yield return _deck.SpreadCards();
}
public void EnableSelection()
{
_isCardSelected = false;
_selectedIndex = -1;
_deck?.SetInteractable(true);
}
public IEnumerator WaitForSelection()
{
EnableSelection();
while (!_isCardSelected)
yield return null;
}
public IEnumerator FlipSelectedCard(TarotOrientation orientation, float duration = 0.5f)
{
var card = _deck?.SelectedCard;
if (card == null)
{
Debug.LogWarning("[TarotManager] No card selected to flip", this);
yield break;
}
yield return card.Flip(orientation, duration);
}
public IEnumerator RotateSelectedCard(TarotOrientation orientation, float duration = 0.4f)
{
var card = _deck?.SelectedCard;
if (card == null)
{
Debug.LogWarning("[TarotManager] No card selected to rotate", this);
yield break;
}
yield return card.SetOrientationAnimated(orientation, duration);
}
public IEnumerator HideAll(float duration = 0.3f)
{
if (_deck != null)
yield return _deck.HideAll(duration);
CloseView();
RestoreTarotBubbleMode();
}
#endregion
private void OnCardSelected(TarotCard card)
{
_isCardSelected = true;
_selectedIndex = card.Index;
StorageSystem.Instance?.SetValue("$tarotSelectedIndex", (float)card.Index);
}
private void OnDestroy()
{
if (_deck != null)
_deck.OnCardSelected -= OnCardSelected;
RestoreTarotBubbleMode();
}
private void TryEnterTarotBubbleMode()
{
if (tarotBubbleSlotGroup == null)
return;
var snapshot = CollectRestoreSnapshot();
if (snapshot.bubbleSlots == null || snapshot.bubbleSlots.Length == 0)
{
Debug.LogWarning(
"[TarotManager] 已配置塔罗气泡但无法取得有效的恢复快照(请指定 restoreBubbleSlotGroup 或保证 OutsideCenter/FixPanelSystem 气泡可用),跳过气泡切换。",
this);
return;
}
_savedBubbleData = snapshot;
_bubbleSwapActive = true;
DialogUIManager.Instance.LoadBubbles(tarotBubbleSlotGroup.CollectData());
}
private void RestoreTarotBubbleMode()
{
if (!_bubbleSwapActive)
return;
_bubbleSwapActive = false;
DialogUIManager.Instance.LoadBubbles(_savedBubbleData);
}
private BubbleSlotGroupData CollectRestoreSnapshot()
{
if (restoreBubbleSlotGroup != null)
return restoreBubbleSlotGroup.CollectData();
if (OutsideCenter.Instance != null && OutsideCenter.Instance.bubbleSlotGroup != null)
return OutsideCenter.Instance.bubbleSlotGroup.CollectData();
if (FixPanelSystem.Instance != null && FixPanelSystem.Instance.BubbleSlotGroup != null)
return FixPanelSystem.Instance.BubbleSlotGroup.CollectData();
return default;
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 1a4305d1fc8ed2c42818611d7387e0ab
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,132 @@
using System;
using System.Collections;
using UnityEngine;
using Yarn.Unity;
using AibisDream.FixSystem;
namespace AibisDream.MiniGame.Tarot
{
public static class TarotYarnCommand
{
private static TarotManager GetManager()
{
return FixSystemCenter.SystemDic.Get<TarotManager>();
}
/// <summary>
/// Show the tarot deck in stacked form(淡入出现;时长在 TarotDeck 的 fadeInDuration)。
/// Usage: &lt;&lt;show_tarot_deck&gt;&gt; or &lt;&lt;show_tarot_deck 5&gt;&gt;
/// </summary>
[YarnCommand("show_tarot_deck")]
public static IEnumerator ShowTarotDeck(int count = 5)
{
var manager = GetManager();
if (manager == null)
{
Debug.LogWarning("[TarotYarnCommand] TarotManager not found");
yield break;
}
yield return manager.ShowDeck(count, 1);
}
/// <summary>
/// Spread cards into a fan. Waits for the spread animation to finish.
/// Usage: &lt;&lt;spread_tarot&gt;&gt; or &lt;&lt;spread_tarot 5&gt;&gt;
/// </summary>
[YarnCommand("spread_tarot")]
public static IEnumerator SpreadTarot()
{
var manager = GetManager();
if (manager == null)
{
Debug.LogWarning("[TarotYarnCommand] TarotManager not found");
yield break;
}
yield return manager.SpreadCards();
}
/// <summary>
/// Block Yarn until the player selects a card(点击即解除等待;牌组 fade / 移至检视位在后台继续播放)。
/// Writes $tarotSelectedIndex after selection.
/// Usage: &lt;&lt;wait_tarot_select&gt;&gt;
/// </summary>
[YarnCommand("wait_tarot_select")]
public static IEnumerator WaitTarotSelect()
{
var manager = GetManager();
if (manager == null)
{
Debug.LogWarning("[TarotYarnCommand] TarotManager not found");
yield break;
}
yield return manager.WaitForSelection();
}
/// <summary>
/// Flip the selected card to reveal its front with a given orientation.
/// Usage: &lt;&lt;flip_tarot "normal"&gt;&gt; or &lt;&lt;flip_tarot "inverted"&gt;&gt;
/// </summary>
[YarnCommand("flip_tarot")]
public static IEnumerator FlipTarot(string orientation = "normal")
{
var manager = GetManager();
if (manager == null)
{
Debug.LogWarning("[TarotYarnCommand] TarotManager not found");
yield break;
}
var orient = ParseOrientation(orientation);
yield return manager.FlipSelectedCard(orient);
}
/// <summary>
/// Rotate the selected card to change its orientation (without flipping).
/// Usage: &lt;&lt;rotate_tarot "normal"&gt;&gt; or &lt;&lt;rotate_tarot "inverted"&gt;&gt;
/// </summary>
[YarnCommand("rotate_tarot")]
public static IEnumerator RotateTarot(string orientation)
{
var manager = GetManager();
if (manager == null)
{
Debug.LogWarning("[TarotYarnCommand] TarotManager not found");
yield break;
}
var orient = ParseOrientation(orientation);
yield return manager.RotateSelectedCard(orient);
}
/// <summary>
/// Fade out and hide all tarot elements.
/// Usage: &lt;&lt;hide_tarot&gt;&gt;
/// </summary>
[YarnCommand("hide_tarot")]
public static IEnumerator HideTarot()
{
var manager = GetManager();
if (manager == null)
{
Debug.LogWarning("[TarotYarnCommand] TarotManager not found");
yield break;
}
yield return manager.HideAll();
}
private static TarotOrientation ParseOrientation(string value)
{
if (string.IsNullOrEmpty(value))
return TarotOrientation.Normal;
if (value.Equals("inverted", StringComparison.OrdinalIgnoreCase))
return TarotOrientation.Inverted;
return TarotOrientation.Normal;
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 7a7d1dcf0f4ad2d4c9ffa874d9bac5a5
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+3
View File
@@ -98,6 +98,9 @@ TagManager:
- name: ClubBoard
uniqueID: 3799401421
locked: 0
- name: Tarot
uniqueID: 2077031127
locked: 0
- name: MessageUI
uniqueID: 3505633107
locked: 0