【GDScript】Godot 中生成 2D 随机地图

Godot 3.2.4

roguelike 中生成 2D 地图非常常见,现在我也用到,所以写下代码以供参考

根节点为 PanelContainer 节点,命名为 MapPanel。在它下面是一个 ScrollContainer 节点。最后是一个 Control 节点,命名为 Container
在这里插入图片描述

在脚本里写入如下代码

## Map Panel
## 地图面板
extends PanelContainer


# 方向列表
const DirectionList = [
	Vector2.LEFT, Vector2.RIGHT, 
	Vector2.UP, Vector2.DOWN
]

# 产生下一个方向的砖块的几率
const Chance = 0.4

export var map_size = Vector2(40, 40)	# 地图大小
export var tile_size = Vector2(32, 32)	# 砖块大小
export var separate = Vector2(8, 8)	# 每个 tile 分隔的距离


onready var scroll_container = $ScrollContainer	# 滚动条容器
onready var container = $ScrollContainer/Container	# 添加 tile 的容器


# 地图 tile 位置列表
var map_tile_pos_list = {}



#==============================
# 内置方法
#==============================
func _ready() -> void:
	# 每次随机不一样
	randomize()
	
	# 初始化地图
	init_map()
	
	# tile 偏移距离
	var offset_size = tile_size + separate
	
	# tile 容器大小
	container.rect_min_size = offset_size * map_size + Vector2.ONE * 600
	
	# 添加 tile 
	var tile_pos_list = map_tile_pos_list.keys()
	var tile_list = []
	for pos in tile_pos_list:
		var button = Button.new()
		button.rect_position = pos * offset_size
		button.rect_size = tile_size
		if map_tile_pos_list[pos] == 1000:
			print(button)
		container.add_child(button)
		tile_list.push_back(button)
	
	# 将起始位置的 tile 设置为红色
	var first_tile = tile_list[0] as Button
	first_tile.modulate = Color.red
	
	# Scroll 容器滚动条的值发生改变的时候
	# 滚动条滚动到第一个 tile 的位置
	yield(scroll_container.get_h_scrollbar(), "changed")
	scroll_container.scroll_horizontal = int(first_tile.rect_position.x - 200)
	scroll_container.scroll_vertical = int(first_tile.rect_position.y - 200)



#==============================
# 自定义方法
#==============================
## 初始化地图
func init_map():
	# 起始位置在地图中间
	var start_pos = map_size / 2
	add_pos(start_pos, 1000)
	
	# 开始延伸向四周
	for dir in DirectionList:
		next_tile(start_pos, dir)


## 下一个瓷砖
## @pos 移动前的位置
## @dir 移动的方向
## @count 递归次数
func next_tile(pos: Vector2, dir: Vector2, count=0):
	for temp_dir in DirectionList:
		if temp_dir == dir * -1:
			# 方向不能向反方向移动
			# 当前 dir 是向左移动,即 dir 为 Vector2.LEFT
			# 那么 temp_dir 就不能向右移动,即不能为 Vector2.RIGHT
			continue
		
		# 随机 `Chance` 的几率添加下一个
		var rand = randf()
		if rand <= Chance:
			var temp_pos = pos + temp_dir
			add_pos(temp_pos)
			
			# 开始进行添加下一个位置
			if valid_next_pos(temp_pos):
				# 防止堆栈溢出,超过 1024 则错误
				if count > 1000:
					return
				next_tile(temp_pos, temp_dir, count+1)


## 返回当前位置还能否向其他位置移动
## @pos 位置
func valid_next_pos(pos: Vector2) -> bool:
	var left = pos + Vector2.LEFT
	var right = pos + Vector2.RIGHT
	var up = pos + Vector2.UP
	var down = pos + Vector2.DOWN
	if (has_pos(left)
		&& has_pos(right)
		&& has_pos(up)
		&& has_pos(down)
	):
		# 所有方向已经存在,则返回 false
		return false
	
	return true


## 添加位置
## @pos 位置
## @type 地图 tile 类型
func add_pos(pos: Vector2, type = 1) -> void:
	if pos > Vector2.ZERO && pos <= map_size:
		map_tile_pos_list[pos] = type

## 是否已经有了这个位置
func has_pos(pos: Vector2) -> bool:
	return map_tile_pos_list.has(pos)

下图是生成后的效果图:
在这里插入图片描述

  • 5
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值