<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Tween on 山高月小</title><link>https://blog.dart.xin/tags/tween/</link><description>Recent content in Tween on 山高月小</description><generator>Hugo</generator><language>zh-cn</language><copyright>zwdart</copyright><lastBuildDate>Wed, 04 Nov 2026 09:51:01 +0800</lastBuildDate><atom:link href="https://blog.dart.xin/tags/tween/index.xml" rel="self" type="application/rss+xml"/><item><title>Godot Tween</title><link>https://blog.dart.xin/godot/gd102-tween/</link><pubDate>Wed, 04 Nov 2026 09:51:01 +0800</pubDate><guid>https://blog.dart.xin/godot/gd102-tween/</guid><description>&lt;p&gt;&lt;code&gt;Tween&lt;/code&gt; 是 Godot 中用于“在代码里顺手做一小段动画”的轻量级工具。它的核心用途很单纯：&lt;strong&gt;将一个属性从当前值平滑地插值到目标值&lt;/strong&gt;，创建后自动运行，完成后自动释放，非常适合 UI 反馈、简单的位移/透明度变化、镜头震动这类“即用即弃”的动效。&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="-先建立正确的心智模型"&gt;🧱 先建立正确的心智模型&lt;/h3&gt;
&lt;p&gt;使用 &lt;code&gt;Tween&lt;/code&gt; 时，有几个前置规则需要先刻在脑子里：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;① 必须用 &lt;code&gt;create_tween()&lt;/code&gt; 创建&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Tween.new()&lt;/code&gt; 是无效的，不能用来做补间。正确的入口只有两个：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-gdscript" data-lang="gdscript"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 方式一：从节点创建，Tween 会绑定到该节点的生命周期&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="n"&gt;tween&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;create_tween&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 方式二：从场景树创建，不绑定特定节点&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="n"&gt;tween&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;get_tree&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create_tween&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;&lt;strong&gt;② Tween 本质上是一条“时间线”&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;你往这条时间线上添加的每一个 &lt;code&gt;tween_property()&lt;/code&gt;、&lt;code&gt;tween_callback()&lt;/code&gt;、&lt;code&gt;tween_interval()&lt;/code&gt;，都是一个 &lt;strong&gt;Tweener&lt;/strong&gt;。默认情况下，&lt;strong&gt;这些 Tweener 会按添加顺序一个接一个地串行执行&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;③ 默认是串行，&lt;code&gt;set_parallel(true)&lt;/code&gt; 可以改为并行&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;这是控制 Tween 行为最关键的一个开关，后面会用具体示例展开。&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="-核心-api你只需要先掌握这几个"&gt;✂️ 核心 API：你只需要先掌握这几个&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style="text-align: left"&gt;方法&lt;/th&gt;
&lt;th style="text-align: left"&gt;作用&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style="text-align: left"&gt;&lt;strong&gt;&lt;code&gt;tween_property(object, property, final_val, duration)&lt;/code&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td style="text-align: left"&gt;最核心的方法，在 &lt;code&gt;duration&lt;/code&gt; 秒内将 &lt;code&gt;property&lt;/code&gt; 插值到 &lt;code&gt;final_val&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left"&gt;&lt;strong&gt;&lt;code&gt;tween_callback(callable)&lt;/code&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td style="text-align: left"&gt;在时间线的某个点执行一个函数&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left"&gt;&lt;strong&gt;&lt;code&gt;tween_interval(time)&lt;/code&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td style="text-align: left"&gt;在时间线上插入一段纯等待&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left"&gt;&lt;strong&gt;&lt;code&gt;set_parallel(true)&lt;/code&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td style="text-align: left"&gt;让后续的 Tweener 并行执行，而不是串行&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left"&gt;&lt;strong&gt;&lt;code&gt;chain()&lt;/code&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td style="text-align: left"&gt;从并行模式切回串行模式&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left"&gt;&lt;strong&gt;&lt;code&gt;set_loops(n)&lt;/code&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td style="text-align: left"&gt;设置循环次数，&lt;code&gt;0&lt;/code&gt; 或不传参表示无限循环&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left"&gt;&lt;strong&gt;&lt;code&gt;set_ease()&lt;/code&gt; / &lt;code&gt;set_trans()&lt;/code&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td style="text-align: left"&gt;控制缓动曲线（加速/减速的节奏）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left"&gt;&lt;strong&gt;&lt;code&gt;.from(value)&lt;/code&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td style="text-align: left"&gt;指定起始值，不依赖属性的当前值&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left"&gt;&lt;strong&gt;&lt;code&gt;.as_relative()&lt;/code&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td style="text-align: left"&gt;将目标值视为相对偏移量&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h3 id="-常用可运行示例"&gt;🍳 常用可运行示例&lt;/h3&gt;
&lt;p&gt;以下示例均假设脚本挂在某个节点上，可以直接复制到 &lt;code&gt;_ready()&lt;/code&gt; 或按钮回调中运行。&lt;/p&gt;</description><content:encoded><![CDATA[<p><code>Tween</code> 是 Godot 中用于“在代码里顺手做一小段动画”的轻量级工具。它的核心用途很单纯：<strong>将一个属性从当前值平滑地插值到目标值</strong>，创建后自动运行，完成后自动释放，非常适合 UI 反馈、简单的位移/透明度变化、镜头震动这类“即用即弃”的动效。</p>
<hr>
<h3 id="-先建立正确的心智模型">🧱 先建立正确的心智模型</h3>
<p>使用 <code>Tween</code> 时，有几个前置规则需要先刻在脑子里：</p>
<p><strong>① 必须用 <code>create_tween()</code> 创建</strong></p>
<p><code>Tween.new()</code> 是无效的，不能用来做补间。正确的入口只有两个：</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-gdscript" data-lang="gdscript"><span class="line"><span class="cl"><span class="c1"># 方式一：从节点创建，Tween 会绑定到该节点的生命周期</span>
</span></span><span class="line"><span class="cl"><span class="kd">var</span> <span class="n">tween</span> <span class="o">=</span> <span class="nf">create_tween</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 方式二：从场景树创建，不绑定特定节点</span>
</span></span><span class="line"><span class="cl"><span class="kd">var</span> <span class="n">tween</span> <span class="o">=</span> <span class="nf">get_tree</span><span class="p">()</span><span class="o">.</span><span class="nf">create_tween</span><span class="p">()</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p><strong>② Tween 本质上是一条“时间线”</strong></p>
<p>你往这条时间线上添加的每一个 <code>tween_property()</code>、<code>tween_callback()</code>、<code>tween_interval()</code>，都是一个 <strong>Tweener</strong>。默认情况下，<strong>这些 Tweener 会按添加顺序一个接一个地串行执行</strong>。</p>
<p><strong>③ 默认是串行，<code>set_parallel(true)</code> 可以改为并行</strong></p>
<p>这是控制 Tween 行为最关键的一个开关，后面会用具体示例展开。</p>
<hr>
<h3 id="-核心-api你只需要先掌握这几个">✂️ 核心 API：你只需要先掌握这几个</h3>
<table>
	<thead>
			<tr>
					<th style="text-align: left">方法</th>
					<th style="text-align: left">作用</th>
			</tr>
	</thead>
	<tbody>
			<tr>
					<td style="text-align: left"><strong><code>tween_property(object, property, final_val, duration)</code></strong></td>
					<td style="text-align: left">最核心的方法，在 <code>duration</code> 秒内将 <code>property</code> 插值到 <code>final_val</code></td>
			</tr>
			<tr>
					<td style="text-align: left"><strong><code>tween_callback(callable)</code></strong></td>
					<td style="text-align: left">在时间线的某个点执行一个函数</td>
			</tr>
			<tr>
					<td style="text-align: left"><strong><code>tween_interval(time)</code></strong></td>
					<td style="text-align: left">在时间线上插入一段纯等待</td>
			</tr>
			<tr>
					<td style="text-align: left"><strong><code>set_parallel(true)</code></strong></td>
					<td style="text-align: left">让后续的 Tweener 并行执行，而不是串行</td>
			</tr>
			<tr>
					<td style="text-align: left"><strong><code>chain()</code></strong></td>
					<td style="text-align: left">从并行模式切回串行模式</td>
			</tr>
			<tr>
					<td style="text-align: left"><strong><code>set_loops(n)</code></strong></td>
					<td style="text-align: left">设置循环次数，<code>0</code> 或不传参表示无限循环</td>
			</tr>
			<tr>
					<td style="text-align: left"><strong><code>set_ease()</code> / <code>set_trans()</code></strong></td>
					<td style="text-align: left">控制缓动曲线（加速/减速的节奏）</td>
			</tr>
			<tr>
					<td style="text-align: left"><strong><code>.from(value)</code></strong></td>
					<td style="text-align: left">指定起始值，不依赖属性的当前值</td>
			</tr>
			<tr>
					<td style="text-align: left"><strong><code>.as_relative()</code></strong></td>
					<td style="text-align: left">将目标值视为相对偏移量</td>
			</tr>
	</tbody>
</table>
<hr>
<h3 id="-常用可运行示例">🍳 常用可运行示例</h3>
<p>以下示例均假设脚本挂在某个节点上，可以直接复制到 <code>_ready()</code> 或按钮回调中运行。</p>
<hr>
<h4 id="示例-1基础位移--让节点滑到指定位置">示例 1：基础位移 —— 让节点滑到指定位置</h4>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-gdscript" data-lang="gdscript"><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">_ready</span><span class="p">()</span> <span class="o">-&gt;</span> <span class="kt">void</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="kd">var</span> <span class="n">tween</span> <span class="o">=</span> <span class="nf">create_tween</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">    <span class="n">tween</span><span class="o">.</span><span class="nf">tween_property</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="s2">&#34;position&#34;</span><span class="p">,</span> <span class="nc">Vector2</span><span class="p">(</span><span class="mi">400</span><span class="p">,</span> <span class="mi">300</span><span class="p">),</span> <span class="mf">1.0</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="o">.</span><span class="nf">set_trans</span><span class="p">(</span><span class="nc">Tween</span><span class="o">.</span><span class="n">TRANS_CUBIC</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="o">.</span><span class="nf">set_ease</span><span class="p">(</span><span class="nc">Tween</span><span class="o">.</span><span class="n">EASE_OUT</span><span class="p">)</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p><code>set_trans(Tween.TRANS_CUBIC)</code> 让运动带有“起步快、收尾缓”的节奏感，<code>.set_ease(Tween.EASE_OUT)</code> 表示缓出。常用的组合是 <strong><code>TRANS_CUBIC</code> + <code>EASE_OUT</code></strong>，对大多数 UI 动效都很自然。</p>
<hr>
<h4 id="示例-2淡入--淡出ui-最常用">示例 2：淡入 / 淡出（UI 最常用）</h4>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-gdscript" data-lang="gdscript"><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">fade_in</span><span class="p">(</span><span class="n">node</span><span class="p">:</span> <span class="nc">CanvasItem</span><span class="p">,</span> <span class="n">duration</span> <span class="o">:=</span> <span class="mf">0.3</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kt">void</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">node</span><span class="o">.</span><span class="n">modulate</span><span class="o">.</span><span class="n">a</span> <span class="o">=</span> <span class="mf">0.0</span>
</span></span><span class="line"><span class="cl">    <span class="nf">create_tween</span><span class="p">()</span><span class="o">.</span><span class="nf">tween_property</span><span class="p">(</span><span class="n">node</span><span class="p">,</span> <span class="s2">&#34;modulate:a&#34;</span><span class="p">,</span> <span class="mf">1.0</span><span class="p">,</span> <span class="n">duration</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">fade_out</span><span class="p">(</span><span class="n">node</span><span class="p">:</span> <span class="nc">CanvasItem</span><span class="p">,</span> <span class="n">duration</span> <span class="o">:=</span> <span class="mf">0.3</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kt">void</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="nf">create_tween</span><span class="p">()</span><span class="o">.</span><span class="nf">tween_property</span><span class="p">(</span><span class="n">node</span><span class="p">,</span> <span class="s2">&#34;modulate:a&#34;</span><span class="p">,</span> <span class="mf">0.0</span><span class="p">,</span> <span class="n">duration</span><span class="p">)</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>属性路径用 <code>&quot;modulate:a&quot;</code> 直接绑定到透明度分量，比操作整个 <code>Color</code> 更清晰。</p>
<hr>
<h4 id="示例-3串行序列--变红--缩小--释放">示例 3：串行序列 —— 变红 → 缩小 → 释放</h4>
<p>这是官方文档中的标准示例，展示了 Tween 的“时间线”本质：</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-gdscript" data-lang="gdscript"><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">_ready</span><span class="p">()</span> <span class="o">-&gt;</span> <span class="kt">void</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="kd">var</span> <span class="n">tween</span> <span class="o">=</span> <span class="nf">create_tween</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">    <span class="n">tween</span><span class="o">.</span><span class="nf">tween_property</span><span class="p">(</span><span class="nx">$Sprite</span><span class="p">,</span> <span class="s2">&#34;modulate&#34;</span><span class="p">,</span> <span class="nc">Color</span><span class="o">.</span><span class="n">RED</span><span class="p">,</span> <span class="mf">1.0</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">tween</span><span class="o">.</span><span class="nf">tween_property</span><span class="p">(</span><span class="nx">$Sprite</span><span class="p">,</span> <span class="s2">&#34;scale&#34;</span><span class="p">,</span> <span class="nc">Vector2</span><span class="o">.</span><span class="n">ZERO</span><span class="p">,</span> <span class="mf">1.0</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">tween</span><span class="o">.</span><span class="nf">tween_callback</span><span class="p">(</span><span class="nx">$Sprite</span><span class="o">.</span><span class="n">queue_free</span><span class="p">)</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>三个步骤严格按顺序执行：先变红，再缩小到零，最后调用 <code>queue_free()</code> 释放节点。</p>
<hr>
<h4 id="示例-4延迟回调--两秒后执行某个函数">示例 4：延迟回调 —— 两秒后执行某个函数</h4>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-gdscript" data-lang="gdscript"><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">_ready</span><span class="p">()</span> <span class="o">-&gt;</span> <span class="kt">void</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="kd">var</span> <span class="n">tween</span> <span class="o">=</span> <span class="nf">create_tween</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">    <span class="n">tween</span><span class="o">.</span><span class="nf">tween_callback</span><span class="p">(</span><span class="n">_on_delayed</span><span class="p">)</span><span class="o">.</span><span class="nf">set_delay</span><span class="p">(</span><span class="mf">2.0</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">_on_delayed</span><span class="p">()</span> <span class="o">-&gt;</span> <span class="kt">void</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="s2">&#34;2 秒后执行&#34;</span><span class="p">)</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p><code>.set_delay(2.0)</code> 让回调在加入时间线后等待 2 秒再执行，很适合替代手动的计时器来做简单的延迟逻辑。</p>
<hr>
<h4 id="示例-5并行动画--面板滑入的同时淡入">示例 5：并行动画 —— 面板滑入的同时淡入</h4>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span><span class="lnt">8
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-gdscript" data-lang="gdscript"><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">show_panel</span><span class="p">(</span><span class="n">panel</span><span class="p">:</span> <span class="nc">Control</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kt">void</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">panel</span><span class="o">.</span><span class="n">modulate</span><span class="o">.</span><span class="n">a</span> <span class="o">=</span> <span class="mf">0.0</span>
</span></span><span class="line"><span class="cl">    <span class="n">panel</span><span class="o">.</span><span class="n">position</span><span class="o">.</span><span class="n">x</span> <span class="o">=</span> <span class="o">-</span><span class="mi">200</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="kd">var</span> <span class="n">tween</span> <span class="o">=</span> <span class="nf">create_tween</span><span class="p">()</span><span class="o">.</span><span class="nf">set_parallel</span><span class="p">(</span><span class="kc">true</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">tween</span><span class="o">.</span><span class="nf">tween_property</span><span class="p">(</span><span class="n">panel</span><span class="p">,</span> <span class="s2">&#34;position:x&#34;</span><span class="p">,</span> <span class="mf">100.0</span><span class="p">,</span> <span class="mf">0.4</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="o">.</span><span class="nf">set_trans</span><span class="p">(</span><span class="nc">Tween</span><span class="o">.</span><span class="n">TRANS_CUBIC</span><span class="p">)</span><span class="o">.</span><span class="nf">set_ease</span><span class="p">(</span><span class="nc">Tween</span><span class="o">.</span><span class="n">EASE_OUT</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">tween</span><span class="o">.</span><span class="nf">tween_property</span><span class="p">(</span><span class="n">panel</span><span class="p">,</span> <span class="s2">&#34;modulate:a&#34;</span><span class="p">,</span> <span class="mf">1.0</span><span class="p">,</span> <span class="mf">0.4</span><span class="p">)</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>调用 <code>set_parallel(true)</code> 之后，<strong>后续添加的所有 Tweener 会同时开始</strong>，而不是排队执行。这是 UI 弹出动画最常用的模式：位移、透明度、缩放同时进行，整体感觉会更利落。</p>
<hr>
<h4 id="示例-6并行结束后接回调--chain-的用法">示例 6：并行结束后接回调 —— <code>chain()</code> 的用法</h4>
<p>如果并行块结束后还需要执行一段串行逻辑，必须用 <code>chain()</code> 切回串行：</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-gdscript" data-lang="gdscript"><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">popup_animation</span><span class="p">(</span><span class="n">node</span><span class="p">:</span> <span class="nc">Control</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kt">void</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="kd">var</span> <span class="n">tween</span> <span class="o">=</span> <span class="nf">create_tween</span><span class="p">()</span><span class="o">.</span><span class="nf">set_parallel</span><span class="p">(</span><span class="kc">true</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">tween</span><span class="o">.</span><span class="nf">tween_property</span><span class="p">(</span><span class="n">node</span><span class="p">,</span> <span class="s2">&#34;scale&#34;</span><span class="p">,</span> <span class="nc">Vector2</span><span class="p">(</span><span class="mf">1.1</span><span class="p">,</span> <span class="mf">1.1</span><span class="p">),</span> <span class="mf">0.2</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">tween</span><span class="o">.</span><span class="nf">tween_property</span><span class="p">(</span><span class="n">node</span><span class="p">,</span> <span class="s2">&#34;modulate:a&#34;</span><span class="p">,</span> <span class="mf">1.0</span><span class="p">,</span> <span class="mf">0.2</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">tween</span><span class="o">.</span><span class="nf">chain</span><span class="p">()</span><span class="o">.</span><span class="nf">tween_callback</span><span class="p">(</span><span class="n">_on_popup_ready</span><span class="p">)</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p><code>chain()</code> 的作用就是把“并行模式”关掉，恢复为串行，从而让后面的 <code>tween_callback</code> 等到前面的并行动画全部完成后才触发。</p>
<hr>
<h4 id="示例-7无限循环的往返移动">示例 7：无限循环的往返移动</h4>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-gdscript" data-lang="gdscript"><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">start_bobbing</span><span class="p">()</span> <span class="o">-&gt;</span> <span class="kt">void</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="kd">var</span> <span class="n">start_x</span> <span class="o">:=</span> <span class="n">position</span><span class="o">.</span><span class="n">x</span>
</span></span><span class="line"><span class="cl">    <span class="kd">var</span> <span class="n">end_x</span> <span class="o">:=</span> <span class="n">position</span><span class="o">.</span><span class="n">x</span> <span class="o">+</span> <span class="mf">100.0</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="kd">var</span> <span class="n">tween</span> <span class="o">=</span> <span class="nf">create_tween</span><span class="p">()</span><span class="o">.</span><span class="nf">set_loops</span><span class="p">()</span> <span class="c1"># 无限循环</span>
</span></span><span class="line"><span class="cl">    <span class="n">tween</span><span class="o">.</span><span class="nf">tween_property</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="s2">&#34;position:x&#34;</span><span class="p">,</span> <span class="n">end_x</span><span class="p">,</span> <span class="mf">1.0</span><span class="p">)</span><span class="o">.</span><span class="nf">from</span><span class="p">(</span><span class="n">start_x</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">tween</span><span class="o">.</span><span class="nf">tween_property</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="s2">&#34;position:x&#34;</span><span class="p">,</span> <span class="n">start_x</span><span class="p">,</span> <span class="mf">1.0</span><span class="p">)</span><span class="o">.</span><span class="nf">from</span><span class="p">(</span><span class="n">end_x</span><span class="p">)</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p><code>set_loops()</code> 不传参数表示无限循环。<code>.from()</code> 明确指定每段的起点，避免依赖属性当前值，让往返逻辑更可控。</p>
<hr>
<h4 id="示例-8相对位移--as_relative-的用法">示例 8：相对位移 —— <code>as_relative()</code> 的用法</h4>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-gdscript" data-lang="gdscript"><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">shake</span><span class="p">()</span> <span class="o">-&gt;</span> <span class="kt">void</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="kd">var</span> <span class="n">tween</span> <span class="o">=</span> <span class="nf">create_tween</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">    <span class="n">tween</span><span class="o">.</span><span class="nf">tween_property</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="s2">&#34;position:x&#34;</span><span class="p">,</span> <span class="mf">10.0</span><span class="p">,</span> <span class="mf">0.05</span><span class="p">)</span><span class="o">.</span><span class="nf">as_relative</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">    <span class="n">tween</span><span class="o">.</span><span class="nf">tween_property</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="s2">&#34;position:x&#34;</span><span class="p">,</span> <span class="o">-</span><span class="mf">20.0</span><span class="p">,</span> <span class="mf">0.05</span><span class="p">)</span><span class="o">.</span><span class="nf">as_relative</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">    <span class="n">tween</span><span class="o">.</span><span class="nf">tween_property</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="s2">&#34;position:x&#34;</span><span class="p">,</span> <span class="mf">10.0</span><span class="p">,</span> <span class="mf">0.05</span><span class="p">)</span><span class="o">.</span><span class="nf">as_relative</span><span class="p">()</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p><code>.as_relative()</code> 让目标值变成<strong>相对当前值的偏移量</strong>，非常适合做不需要关心绝对坐标的震动、抖动效果。</p>
<hr>
<h4 id="示例-9弹性缩放--按钮按压反馈">示例 9：弹性缩放 —— 按钮按压反馈</h4>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-gdscript" data-lang="gdscript"><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">press_feedback</span><span class="p">(</span><span class="n">button</span><span class="p">:</span> <span class="nc">Control</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kt">void</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="kd">var</span> <span class="n">tween</span> <span class="o">=</span> <span class="nf">create_tween</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">    <span class="n">tween</span><span class="o">.</span><span class="nf">tween_property</span><span class="p">(</span><span class="n">button</span><span class="p">,</span> <span class="s2">&#34;scale&#34;</span><span class="p">,</span> <span class="nc">Vector2</span><span class="p">(</span><span class="mf">0.9</span><span class="p">,</span> <span class="mf">0.9</span><span class="p">),</span> <span class="mf">0.1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">tween</span><span class="o">.</span><span class="nf">tween_property</span><span class="p">(</span><span class="n">button</span><span class="p">,</span> <span class="s2">&#34;scale&#34;</span><span class="p">,</span> <span class="nc">Vector2</span><span class="o">.</span><span class="n">ONE</span><span class="p">,</span> <span class="mf">0.3</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="o">.</span><span class="nf">set_trans</span><span class="p">(</span><span class="nc">Tween</span><span class="o">.</span><span class="n">TRANS_ELASTIC</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="o">.</span><span class="nf">set_ease</span><span class="p">(</span><span class="nc">Tween</span><span class="o">.</span><span class="n">EASE_OUT</span><span class="p">)</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>先用很短的时间缩小，再用弹性缓动弹回原始大小，是按钮点击反馈中很常见的“Q 弹”手感。</p>
<hr>
<h4 id="示例-10控制生命周期--保存引用随时终止">示例 10：控制生命周期 —— 保存引用，随时终止</h4>
<p>Tween 创建后会自动运行，但如果你需要中途取消（比如玩家在动画途中离开了状态），应当保存引用并调用 <code>kill()</code>：</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-gdscript" data-lang="gdscript"><span class="line"><span class="cl"><span class="kd">var</span> <span class="n">_move_tween</span><span class="p">:</span> <span class="nc">Tween</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">move_to</span><span class="p">(</span><span class="n">target</span><span class="p">:</span> <span class="nc">Vector2</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kt">void</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="n">_move_tween</span> <span class="ow">and</span> <span class="n">_move_tween</span><span class="o">.</span><span class="nf">is_valid</span><span class="p">():</span>
</span></span><span class="line"><span class="cl">        <span class="n">_move_tween</span><span class="o">.</span><span class="nf">kill</span><span class="p">()</span>  <span class="c1"># 先终止旧 Tween，避免多 Tween 争抢同一属性</span>
</span></span><span class="line"><span class="cl">    <span class="n">_move_tween</span> <span class="o">=</span> <span class="nf">create_tween</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">    <span class="n">_move_tween</span><span class="o">.</span><span class="nf">tween_property</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="s2">&#34;position&#34;</span><span class="p">,</span> <span class="n">target</span><span class="p">,</span> <span class="mf">0.5</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">cancel_movement</span><span class="p">()</span> <span class="o">-&gt;</span> <span class="kt">void</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="n">_move_tween</span> <span class="ow">and</span> <span class="n">_move_tween</span><span class="o">.</span><span class="nf">is_valid</span><span class="p">():</span>
</span></span><span class="line"><span class="cl">        <span class="n">_move_tween</span><span class="o">.</span><span class="nf">kill</span><span class="p">()</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>一个重要的实践规则：<strong>不要用多个 Tween 同时驱动同一个属性</strong>，否则行为会变得不可预测。在启动新 Tween 之前，先 <code>kill()</code> 旧的引用。</p>
<hr>
<h3 id="-缓动速查set_trans-与-set_ease-怎么选">🎚️ 缓动速查：<code>set_trans</code> 与 <code>set_ease</code> 怎么选</h3>
<table>
	<thead>
			<tr>
					<th style="text-align: left">场景</th>
					<th style="text-align: left">推荐组合</th>
			</tr>
	</thead>
	<tbody>
			<tr>
					<td style="text-align: left">UI 滑入 / 淡入</td>
					<td style="text-align: left"><code>TRANS_CUBIC</code> + <code>EASE_OUT</code></td>
			</tr>
			<tr>
					<td style="text-align: left">弹簧/弹性反馈</td>
					<td style="text-align: left"><code>TRANS_ELASTIC</code> + <code>EASE_OUT</code></td>
			</tr>
			<tr>
					<td style="text-align: left">自然往返（呼吸感）</td>
					<td style="text-align: left"><code>TRANS_SINE</code> + <code>EASE_IN_OUT</code></td>
			</tr>
			<tr>
					<td style="text-align: left">快速起步、缓慢收尾</td>
					<td style="text-align: left"><code>TRANS_QUAD</code> + <code>EASE_OUT</code></td>
			</tr>
			<tr>
					<td style="text-align: left">强调“砸下来”的感觉</td>
					<td style="text-align: left"><code>TRANS_BACK</code> + <code>EASE_IN</code></td>
			</tr>
	</tbody>
</table>
<p><code>set_ease</code> 和 <code>set_trans</code> 可以链式调用在单个 <code>tween_property</code> 上，也可以设置在 <code>create_tween()</code> 后作为整个 Tween 的默认值。</p>
<hr>
<h3 id="-总结">💎 总结</h3>
<p><code>Tween</code> 的学习曲线很短，关键是把三个概念分清楚：<strong>时间线是串行的</strong>（用 <code>set_parallel</code> 切换并行）、<strong>Tweener 是可链式配置的</strong>（<code>.from()</code>、<code>.set_trans()</code>、<code>.set_delay()</code> 都作用在单个步骤上）、<strong>Tween 对象本身是可终止的</strong>（保存引用，必要时 <code>kill()</code>）。把上面十个示例跑一遍，再组合出“并行位移+淡入，结束后回调”这类复合动效，你就能覆盖大多数日常需求了。</p>
]]></content:encoded></item></channel></rss>