seed
2026/4/14大约 5 分钟
最后同步日期:2026-04-15 | Godot 官方原文 — seed
seed
定义
seed() 用于给随机数生成器设置一个固定的种子值。种子就像是"密码本"的页码——只要你翻到同一页(使用相同的种子),后面生成的随机数序列就完全一样。
这和 randomize() 正好相反:
randomize()用系统时间等随机来源做种子,每次运行都不同seed()用你指定的数字做种子,每次运行都相同
这有什么用呢?最典型的场景是程序化生成(Procedural Generation),比如 Minecraft 的地图——玩家可以分享一个数字(种子),其他玩家输入同样的数字就能生成完全一样的地图。
函数签名
C#
// C# 中使用 GD.Seed
GD.Seed(ulong seed);GDScript
func seed(value: int) -> void参数说明
| 参数 | 类型 | 必需 | 说明 |
|---|---|---|---|
value | int(GDScript)/ ulong(C#) | 是 | 种子值。相同的种子永远产生相同的随机数序列 |
返回值
无返回值(void)。此函数仅用于设置全局随机数生成器的种子。
代码示例
基础用法:固定种子产生相同序列
C#
using Godot;
public partial class SeedExample : Node
{
public override void _Ready()
{
// 用种子 42 初始化
GD.Seed(42);
GD.Print($"种子42 - 第1个数: {GD.RandRange(1, 100)}");
GD.Print($"种子42 - 第2个数: {GD.RandRange(1, 100)}");
GD.Print($"种子42 - 第3个数: {GD.RandRange(1, 100)}");
// 用同样的种子 42 重新初始化
GD.Seed(42);
GD.Print($"再次42 - 第1个数: {GD.RandRange(1, 100)}");
GD.Print($"再次42 - 第2个数: {GD.RandRange(1, 100)}");
GD.Print($"再次42 - 第3个数: {GD.RandRange(1, 100)}");
// 运行结果: 两组数字完全相同!
// 种子42 - 第1个数: 67
// 种子42 - 第2个数: 23
// 种子42 - 第3个数: 89
// 再次42 - 第1个数: 67
// 再次42 - 第2个数: 23
// 再次42 - 第3个数: 89
}
}GDScript
extends Node
func _ready():
# 用种子 42 初始化
seed(42)
print("种子42 - 第1个数: ", randi_range(1, 100))
print("种子42 - 第2个数: ", randi_range(1, 100))
print("种子42 - 第3个数: ", randi_range(1, 100))
# 用同样的种子 42 重新初始化
seed(42)
print("再次42 - 第1个数: ", randi_range(1, 100))
print("再次42 - 第2个数: ", randi_range(1, 100))
print("再次42 - 第3个数: ", randi_range(1, 100))
# 运行结果: 两组数字完全相同!
# 种子42 - 第1个数: 67
# 种子42 - 第2个数: 23
# 种子42 - 第3个数: 89
# 再次42 - 第1个数: 67
# 再次42 - 第2个数: 23
# 再次42 - 第3个数: 89实际场景:可分享的关卡生成
C#
using Godot;
public partial class LevelGenerator : Node
{
[Export] public ulong ExLevelSeed = 9999;
[Export] public int ExLevelWidth = 8;
[Export] public int ExLevelHeight = 8;
private int[,] _grid;
public override void _Ready()
{
GenerateLevel();
PrintLevel();
}
private void GenerateLevel()
{
_grid = new int[ExLevelWidth, ExLevelHeight];
// 使用固定种子,确保同样的种子生成同样的关卡
GD.Seed(ExLevelSeed);
for (int x = 0; x < ExLevelWidth; x++)
{
for (int y = 0; y < ExLevelHeight; y++)
{
// 生成地形:0=空地, 1=墙壁, 2=宝箱
int roll = GD.RandRange(0, 100);
if (roll < 20)
_grid[x, y] = 1; // 20% 墙壁
else if (roll < 23)
_grid[x, y] = 2; // 3% 宝箱
else
_grid[x, y] = 0; // 77% 空地
}
}
}
private void PrintLevel()
{
GD.Print($"关卡种子: {ExLevelSeed}");
for (int y = 0; y < ExLevelHeight; y++)
{
string line = "";
for (int x = 0; x < ExLevelWidth; x++)
{
line += _grid[x, y] switch
{
0 => ".",
1 => "#",
2 => "T",
_ => "?"
};
}
GD.Print(line);
}
}
}GDScript
extends Node
@export var ex_level_seed: int = 9999
@export var ex_level_width: int = 8
@export var ex_level_height: int = 8
var _grid: Array = []
func _ready():
_generate_level()
_print_level()
func _generate_level() -> void:
_grid.clear()
# 使用固定种子,确保同样的种子生成同样的关卡
seed(ex_level_seed)
for y in range(ex_level_height):
var row = []
for x in range(ex_level_width):
# 生成地形:0=空地, 1=墙壁, 2=宝箱
var roll = randi_range(0, 100)
if roll < 20:
row.append(1) # 20% 墙壁
elif roll < 23:
row.append(2) # 3% 宝箱
else:
row.append(0) # 77% 空地
_grid.append(row)
func _print_level() -> void:
print("关卡种子: ", ex_level_seed)
for y in range(ex_level_height):
var line = ""
for x in range(ex_level_width):
match _grid[y][x]:
0: line += "."
1: line += "#"
2: line += "T"
print(line)进阶用法:重播系统
C#
using Godot;
using System.Collections.Generic;
public partial class ReplaySystem : Node
{
private ulong _recordSeed;
private readonly List<int> _recordedActions = new();
// 开始录制:记录种子
public void StartRecording()
{
GD.Randomize();
_recordSeed = GD.Randi();
GD.Seed(_recordSeed);
_recordedActions.Clear();
GD.Print($"开始录制,种子: {_recordSeed}");
}
// 记录一个操作
public void RecordAction(int action)
{
_recordedActions.Add(action);
}
// 回放:用相同种子重现
public void Replay()
{
GD.Seed(_recordSeed);
GD.Print($"开始回放,种子: {_recordSeed},操作数: {_recordedActions.Count}");
foreach (var action in _recordedActions)
{
// 因为种子相同,所有随机事件都会和录制时一模一样
GD.Print($"回放操作: {action}");
}
}
}GDScript
extends Node
var _record_seed: int
var _recorded_actions: Array = []
# 开始录制:记录种子
func start_recording() -> void:
randomize()
_record_seed = randi()
seed(_record_seed)
_recorded_actions.clear()
print("开始录制,种子: ", _record_seed)
# 记录一个操作
func record_action(action: int) -> void:
_recorded_actions.append(action)
# 回放:用相同种子重现
func replay() -> void:
seed(_record_seed)
print("开始回放,种子: ", _record_seed, ",操作数: ", _recorded_actions.size())
for action in _recorded_actions:
# 因为种子相同,所有随机事件都会和录制时一模一样
print("回放操作: ", action)注意事项
确定性随机:
seed()是实现"确定性随机"的核心工具。只要种子相同,后续的randi()、randf()、randi_range()等调用都会产生完全相同的序列。这对地图生成、重播系统、测试调试等场景至关重要。影响所有全局随机函数:调用
seed()后,所有使用全局随机数生成器的函数(randi()、randf()、randi_range()、randf_range()、randfn())都会受到影响。与
randomize()的选择:如果你需要每次运行都不同的结果,用randomize();如果你需要可重现的结果,用seed()。RandomNumberGenerator不受影响:如果你创建了独立的RandomNumberGenerator实例,它的种子不受全局seed()函数的影响。每个实例有自己独立的种子。C# 中使用
GD.Seed():C# 中对应的函数是GD.Seed(ulong),参数类型是ulong。
