暂存事件6
This commit is contained in:
Binary file not shown.
@@ -8,6 +8,21 @@
|
|||||||
<portraitPath>UI/HeroArt/Storytellers/Randy</portraitPath>
|
<portraitPath>UI/HeroArt/Storytellers/Randy</portraitPath>
|
||||||
<characterName>兰迪·随机</characterName>
|
<characterName>兰迪·随机</characterName>
|
||||||
<description>这是一个事件链的开端。选择第一个选项将会打开第二个事件窗口。</description>
|
<description>这是一个事件链的开端。选择第一个选项将会打开第二个事件窗口。</description>
|
||||||
|
<onOpenEffects>
|
||||||
|
<li Class="WulaFallenEmpire.Effect_ShowMessage">
|
||||||
|
<message>事件窗口已打开!</message>
|
||||||
|
<messageTypeDef>NeutralEvent</messageTypeDef>
|
||||||
|
</li>
|
||||||
|
</onOpenEffects>
|
||||||
|
<dismissEffects>
|
||||||
|
<li Class="WulaFallenEmpire.Effect_ShowMessage">
|
||||||
|
<message>事件窗口已关闭,进度已重置。</message>
|
||||||
|
<messageTypeDef>NeutralEvent</messageTypeDef>
|
||||||
|
</li>
|
||||||
|
<li Class="WulaFallenEmpire.Effect_ClearVariable">
|
||||||
|
<name>wula_event_progress</name>
|
||||||
|
</li>
|
||||||
|
</dismissEffects>
|
||||||
<options>
|
<options>
|
||||||
<li>
|
<li>
|
||||||
<label>继续事件</label>
|
<label>继续事件</label>
|
||||||
@@ -13,11 +13,11 @@
|
|||||||
<lihuiSize>(500, 800)</lihuiSize>
|
<lihuiSize>(500, 800)</lihuiSize>
|
||||||
<nameSize>(260, 130)</nameSize>
|
<nameSize>(260, 130)</nameSize>
|
||||||
<textSize>(650, 500)</textSize>
|
<textSize>(650, 500)</textSize>
|
||||||
<optionsWidth>610</optionsWidth>
|
<optionsWidth>650</optionsWidth>
|
||||||
|
|
||||||
<!-- Virtual Layout Offsets -->
|
<!-- Virtual Layout Offsets -->
|
||||||
<textNameOffset>20</textNameOffset>
|
<textNameOffset>0</textNameOffset>
|
||||||
<optionsTextOffset>20</optionsTextOffset>
|
<optionsTextOffset>0</optionsTextOffset>
|
||||||
|
|
||||||
</WulaFallenEmpire.EventUIConfigDef>
|
</WulaFallenEmpire.EventUIConfigDef>
|
||||||
|
|
||||||
@@ -45,10 +45,14 @@
|
|||||||
**字段说明:**
|
**字段说明:**
|
||||||
- `labelFont`: 事件标题 (`label`) 的字体大小。可选值: `Tiny`, `Small`, `Medium`, `Large`。
|
- `labelFont`: 事件标题 (`label`) 的字体大小。可选值: `Tiny`, `Small`, `Medium`, `Large`。
|
||||||
- `drawBorders`: 是否为立绘、名称和描述区域绘制白色边框。
|
- `drawBorders`: 是否为立绘、名称和描述区域绘制白色边框。
|
||||||
- `defaultBackgroundImagePath`: 所有事件窗口默认使用的背景图路径。
|
- `defaultBackgroundImagePath`: 所有事件窗口默认使用的背景图路径。**注意**: 为了完美适配默认的 1000x750 像素窗口,推荐使用宽高比为 4:3 的图片 (例如 1000x750, 800x600 等)。
|
||||||
- `lihuiSize`, `nameSize`, `textSize`, `optionsWidth`: 定义了UI各部分的基础虚拟尺寸,代码会根据窗口大小按比例缩放它们。
|
- `lihuiSize`, `nameSize`, `textSize`, `optionsWidth`: 定义了UI各部分的基础虚拟尺寸,代码会根据窗口大小按比例缩放它们。
|
||||||
- `textNameOffset`, `optionsTextOffset`: 定义了各部分之间的垂直间距。
|
- `textNameOffset`, `optionsTextOffset`: 定义了各部分之间的垂直间距。
|
||||||
|
|
||||||
|
**布局预览工具:**
|
||||||
|
为了帮助您设计背景图片,我们提供了一个动态的可视化布局预览工具。您可以将 `EventUIConfig.xml` 的内容粘贴进去,它会根据您的配置实时生成布局参考图。
|
||||||
|
- [**打开动态布局预览 (layout_preview.html)**](./layout_preview.html)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 3. 如何创建事件 (`CustomUIDef`)
|
## 3. 如何创建事件 (`CustomUIDef`)
|
||||||
@@ -78,6 +82,8 @@
|
|||||||
- `characterName`: 显示在名称框中的文本。
|
- `characterName`: 显示在名称框中的文本。
|
||||||
- `backgroundImagePath`: (可选)为此特定事件指定的背景图路径,它会覆盖 `EventUIConfigDef` 中的默认背景。
|
- `backgroundImagePath`: (可选)为此特定事件指定的背景图路径,它会覆盖 `EventUIConfigDef` 中的默认背景。
|
||||||
- `description`: 显示在描述框中的主要文本。
|
- `description`: 显示在描述框中的主要文本。
|
||||||
|
- `onOpenEffects`: (可选) 一个 `<li>` 列表,定义了在事件窗口**打开时**立即执行的所有 `Effect`。
|
||||||
|
- `dismissEffects`: (可选) 一个 `<li>` 列表,定义了在事件窗口**关闭时**(通过选项或关闭按钮)执行的所有 `Effect`。
|
||||||
- `options`: 一个 `<li>` 列表,定义了所有的交互选项。
|
- `options`: 一个 `<li>` 列表,定义了所有的交互选项。
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|||||||
186
Documentation/layout_preview.html
Normal file
186
Documentation/layout_preview.html
Normal file
@@ -0,0 +1,186 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>事件UI布局预览 (动态版)</title>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
background-color: #333;
|
||||||
|
color: white;
|
||||||
|
font-family: sans-serif;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
padding: 20px;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
.controls {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
width: 1000px;
|
||||||
|
}
|
||||||
|
textarea {
|
||||||
|
width: 100%;
|
||||||
|
height: 150px;
|
||||||
|
background-color: #222;
|
||||||
|
color: #ddd;
|
||||||
|
border: 1px solid #555;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
button {
|
||||||
|
padding: 10px 20px;
|
||||||
|
font-size: 16px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.window {
|
||||||
|
width: 1000px;
|
||||||
|
height: 750px;
|
||||||
|
background-color: #555;
|
||||||
|
border: 2px solid #ccc;
|
||||||
|
position: relative;
|
||||||
|
box-sizing: border-box;
|
||||||
|
background-size: cover;
|
||||||
|
background-position: center;
|
||||||
|
}
|
||||||
|
.element {
|
||||||
|
position: absolute;
|
||||||
|
box-sizing: border-box;
|
||||||
|
border: 2px solid white;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
font-size: 24px;
|
||||||
|
font-weight: bold;
|
||||||
|
text-shadow: 1px 1px 2px black;
|
||||||
|
}
|
||||||
|
.lihui { background-color: rgba(255, 0, 0, 0.4); }
|
||||||
|
.name { background-color: rgba(0, 255, 0, 0.4); }
|
||||||
|
.text { background-color: rgba(0, 0, 255, 0.4); }
|
||||||
|
.options { background-color: rgba(255, 255, 0, 0.4); }
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="controls">
|
||||||
|
<h3>动态布局预览</h3>
|
||||||
|
<p>请将您的 <code>EventUIConfig.xml</code> 文件内容完整粘贴到下面的文本框中,然后点击“生成预览”按钮。</p>
|
||||||
|
<textarea id="xmlInput" placeholder="在这里粘贴 EventUIConfig.xml 的内容..."></textarea>
|
||||||
|
<button onclick="generatePreview()">生成预览</button>
|
||||||
|
</div>
|
||||||
|
<div class="window" id="window">
|
||||||
|
<!-- 布局将在这里生成 -->
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
function parseVector2(str) {
|
||||||
|
const match = str.match(/\((\s*[\d.]+)\s*,\s*([\d.]+)\s*\)/);
|
||||||
|
return match ? { x: parseFloat(match[1]), y: parseFloat(match[2]) } : { x: 0, y: 0 };
|
||||||
|
}
|
||||||
|
|
||||||
|
function generatePreview() {
|
||||||
|
const xmlString = document.getElementById('xmlInput').value;
|
||||||
|
if (!xmlString) {
|
||||||
|
alert('请先粘贴XML内容!');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const parser = new DOMParser();
|
||||||
|
const xmlDoc = parser.parseFromString(xmlString, "text/xml");
|
||||||
|
|
||||||
|
// Need to escape the dot in the class name for querySelector
|
||||||
|
const configDef = xmlDoc.querySelector('WulaFallenEmpire\\.EventUIConfigDef');
|
||||||
|
if (!configDef) {
|
||||||
|
alert('无法找到 WulaFallenEmpire.EventUIConfigDef 节点,请检查XML内容是否正确。');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const config = {
|
||||||
|
lihuiSize: parseVector2(configDef.querySelector('lihuiSize')?.textContent || '(0,0)'),
|
||||||
|
nameSize: parseVector2(configDef.querySelector('nameSize')?.textContent || '(0,0)'),
|
||||||
|
textSize: parseVector2(configDef.querySelector('textSize')?.textContent || '(0,0)'),
|
||||||
|
optionsWidth: parseFloat(configDef.querySelector('optionsWidth')?.textContent || '0'),
|
||||||
|
textNameOffset: parseFloat(configDef.querySelector('textNameOffset')?.textContent || '0'),
|
||||||
|
optionsTextOffset: parseFloat(configDef.querySelector('optionsTextOffset')?.textContent || '0')
|
||||||
|
};
|
||||||
|
|
||||||
|
const windowRect = { width: 1000, height: 750 };
|
||||||
|
const windowDiv = document.getElementById('window');
|
||||||
|
windowDiv.innerHTML = ''; // Clear previous preview
|
||||||
|
|
||||||
|
// --- Calculation logic from Dialog_CustomDisplay.cs ---
|
||||||
|
const virtualWidth = config.lihuiSize.x + config.textSize.x;
|
||||||
|
const virtualHeight = config.lihuiSize.y;
|
||||||
|
|
||||||
|
const scaleX = windowRect.width / virtualWidth;
|
||||||
|
const scaleY = windowRect.height / virtualHeight;
|
||||||
|
const scale = Math.min(scaleX, scaleY) * 0.95;
|
||||||
|
|
||||||
|
const scaledLihuiWidth = config.lihuiSize.x * scale;
|
||||||
|
const scaledLihuiHeight = config.lihuiSize.y * scale;
|
||||||
|
const scaledNameWidth = config.nameSize.x * scale;
|
||||||
|
const scaledNameHeight = config.nameSize.y * scale;
|
||||||
|
const scaledTextWidth = config.textSize.x * scale;
|
||||||
|
const scaledTextHeight = config.textSize.y * scale;
|
||||||
|
const scaledOptionsWidth = config.optionsWidth * scale;
|
||||||
|
|
||||||
|
const totalContentWidth = scaledLihuiWidth + scaledTextWidth;
|
||||||
|
const totalContentHeight = scaledLihuiHeight;
|
||||||
|
const startX = (windowRect.width - totalContentWidth) / 2;
|
||||||
|
const startY = (windowRect.height - totalContentHeight) / 2;
|
||||||
|
|
||||||
|
// --- Create and position elements ---
|
||||||
|
|
||||||
|
// Lihui (Portrait)
|
||||||
|
const lihuiRect = { left: startX, top: startY, width: scaledLihuiWidth, height: scaledLihuiHeight };
|
||||||
|
createDiv('lihui', '立绘 (Portrait)', lihuiRect);
|
||||||
|
|
||||||
|
// Name
|
||||||
|
const nameRect = { left: lihuiRect.left + lihuiRect.width, top: lihuiRect.top, width: scaledNameWidth, height: scaledNameHeight };
|
||||||
|
createDiv('name', '名称 (Name)', nameRect);
|
||||||
|
|
||||||
|
// Text (Description)
|
||||||
|
const textRect = { left: nameRect.left, top: nameRect.top + nameRect.height + (config.textNameOffset * scale), width: scaledTextWidth, height: scaledTextHeight };
|
||||||
|
createDiv('text', '描述 (Description)', textRect);
|
||||||
|
|
||||||
|
// Options
|
||||||
|
const optionRect = { left: nameRect.left, top: textRect.top + textRect.height + (config.optionsTextOffset * scale), width: scaledOptionsWidth, height: lihuiRect.height - nameRect.height - textRect.height - ((config.textNameOffset + config.optionsTextOffset) * scale) };
|
||||||
|
createDiv('options', '选项 (Options)', optionRect);
|
||||||
|
}
|
||||||
|
|
||||||
|
function createDiv(className, text, rect) {
|
||||||
|
const div = document.createElement('div');
|
||||||
|
div.className = `element ${className}`;
|
||||||
|
div.textContent = text;
|
||||||
|
div.style.left = `${rect.left}px`;
|
||||||
|
div.style.top = `${rect.top}px`;
|
||||||
|
div.style.width = `${rect.width}px`;
|
||||||
|
div.style.height = `${rect.height}px`;
|
||||||
|
document.getElementById('window').appendChild(div);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Auto-populate with example content
|
||||||
|
document.getElementById('xmlInput').value = `<?xml version="1.0" encoding="utf-8" ?>
|
||||||
|
<Defs>
|
||||||
|
<WulaFallenEmpire.EventUIConfigDef>
|
||||||
|
<defName>Wula_EventUIConfig</defName>
|
||||||
|
|
||||||
|
<!-- General Style -->
|
||||||
|
<labelFont>Small</labelFont>
|
||||||
|
<drawBorders>true</drawBorders>
|
||||||
|
<defaultBackgroundImagePath></defaultBackgroundImagePath>
|
||||||
|
|
||||||
|
<!-- Virtual Layout Dimensions -->
|
||||||
|
<lihuiSize>(500, 800)</lihuiSize>
|
||||||
|
<nameSize>(260, 130)</nameSize>
|
||||||
|
<textSize>(650, 500)</textSize>
|
||||||
|
<optionsWidth>610</optionsWidth>
|
||||||
|
|
||||||
|
<!-- Virtual Layout Offsets -->
|
||||||
|
<textNameOffset>20</textNameOffset>
|
||||||
|
<optionsTextOffset>20</optionsTextOffset>
|
||||||
|
|
||||||
|
</WulaFallenEmpire.EventUIConfigDef>
|
||||||
|
</Defs>`;
|
||||||
|
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
Binary file not shown.
@@ -10,6 +10,8 @@ namespace WulaFallenEmpire
|
|||||||
public new string description;
|
public new string description;
|
||||||
public List<CustomUIOption> options;
|
public List<CustomUIOption> options;
|
||||||
public string backgroundImagePath; // Override default background
|
public string backgroundImagePath; // Override default background
|
||||||
|
public List<Effect> onOpenEffects;
|
||||||
|
public List<Effect> dismissEffects;
|
||||||
}
|
}
|
||||||
|
|
||||||
public class CustomUIOption
|
public class CustomUIOption
|
||||||
|
|||||||
@@ -47,6 +47,8 @@ namespace WulaFallenEmpire
|
|||||||
{
|
{
|
||||||
background = ContentFinder<Texture2D>.Get(bgPath);
|
background = ContentFinder<Texture2D>.Get(bgPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
HandleAction(def.onOpenEffects);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void DoWindowContents(Rect inRect)
|
public override void DoWindowContents(Rect inRect)
|
||||||
@@ -199,5 +201,11 @@ namespace WulaFallenEmpire
|
|||||||
}
|
}
|
||||||
return reason;
|
return reason;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override void PostClose()
|
||||||
|
{
|
||||||
|
base.PostClose();
|
||||||
|
HandleAction(def.dismissEffects);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user