Basic Movement and Map Generation #22
8 changed files with 326 additions and 0 deletions
BIN
Assets/Sprites/PlaceHolderA.png
Normal file
BIN
Assets/Sprites/PlaceHolderA.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 78 B |
34
Assets/Sprites/PlaceHolderA.png.import
Normal file
34
Assets/Sprites/PlaceHolderA.png.import
Normal file
|
@ -0,0 +1,34 @@
|
|||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://bjyry6vvtr8h5"
|
||||
path="res://.godot/imported/PlaceHolderA.png-e2c024c9601592007fcae5cbf8aa801d.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://Assets/Sprites/PlaceHolderA.png"
|
||||
dest_files=["res://.godot/imported/PlaceHolderA.png-e2c024c9601592007fcae5cbf8aa801d.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/hdr_compression=1
|
||||
compress/normal_map=0
|
||||
compress/channel_pack=0
|
||||
mipmaps/generate=false
|
||||
mipmaps/limit=-1
|
||||
roughness/mode=0
|
||||
roughness/src_normal=""
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/normal_map_invert_y=false
|
||||
process/hdr_as_srgb=false
|
||||
process/hdr_clamp_exposure=false
|
||||
process/size_limit=0
|
||||
detect_3d/compress_to=1
|
BIN
Assets/Sprites/PlaceHolderB.png
Normal file
BIN
Assets/Sprites/PlaceHolderB.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 79 B |
34
Assets/Sprites/PlaceHolderB.png.import
Normal file
34
Assets/Sprites/PlaceHolderB.png.import
Normal file
|
@ -0,0 +1,34 @@
|
|||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://cbtiuvqgnulmf"
|
||||
path="res://.godot/imported/PlaceHolderB.png-e4349525f46542a37c6106a7ccfeea94.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://Assets/Sprites/PlaceHolderB.png"
|
||||
dest_files=["res://.godot/imported/PlaceHolderB.png-e4349525f46542a37c6106a7ccfeea94.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/hdr_compression=1
|
||||
compress/normal_map=0
|
||||
compress/channel_pack=0
|
||||
mipmaps/generate=false
|
||||
mipmaps/limit=-1
|
||||
roughness/mode=0
|
||||
roughness/src_normal=""
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/normal_map_invert_y=false
|
||||
process/hdr_as_srgb=false
|
||||
process/hdr_clamp_exposure=false
|
||||
process/size_limit=0
|
||||
detect_3d/compress_to=1
|
25
Assets/Test_Tileset.tres
Normal file
25
Assets/Test_Tileset.tres
Normal file
|
@ -0,0 +1,25 @@
|
|||
[gd_resource type="TileSet" load_steps=5 format=3 uid="uid://b7cqbf6xdbeal"]
|
||||
|
||||
[ext_resource type="Texture2D" uid="uid://bjyry6vvtr8h5" path="res://Assets/Sprites/PlaceHolderA.png" id="1_nuhua"]
|
||||
[ext_resource type="Texture2D" uid="uid://cbtiuvqgnulmf" path="res://Assets/Sprites/PlaceHolderB.png" id="2_jl0te"]
|
||||
|
||||
[sub_resource type="TileSetAtlasSource" id="TileSetAtlasSource_urqd5"]
|
||||
texture = ExtResource("1_nuhua")
|
||||
texture_region_size = Vector2i(8, 8)
|
||||
0:0/0 = 0
|
||||
0:0/0/physics_layer_0/linear_velocity = Vector2(0, 0)
|
||||
0:0/0/physics_layer_0/angular_velocity = 0.0
|
||||
0:0/0/physics_layer_0/polygon_0/points = PackedVector2Array(-4, -4, 4, -4, 4, 4, -4, 4)
|
||||
|
||||
[sub_resource type="TileSetAtlasSource" id="TileSetAtlasSource_7bjb0"]
|
||||
texture = ExtResource("2_jl0te")
|
||||
texture_region_size = Vector2i(8, 8)
|
||||
0:0/0 = 0
|
||||
0:0/0/physics_layer_0/linear_velocity = Vector2(0, 0)
|
||||
0:0/0/physics_layer_0/angular_velocity = 0.0
|
||||
|
||||
[resource]
|
||||
tile_size = Vector2i(8, 8)
|
||||
physics_layer_0/collision_layer = 1
|
||||
sources/0 = SubResource("TileSetAtlasSource_urqd5")
|
||||
sources/1 = SubResource("TileSetAtlasSource_7bjb0")
|
13
Scenes/Cave.tscn
Normal file
13
Scenes/Cave.tscn
Normal file
|
@ -0,0 +1,13 @@
|
|||
[gd_scene load_steps=3 format=3 uid="uid://chfp8mm3vwh2e"]
|
||||
|
||||
[ext_resource type="TileSet" uid="uid://b7cqbf6xdbeal" path="res://Assets/Test_Tileset.tres" id="1_8lepy"]
|
||||
[ext_resource type="Script" path="res://Scripts/MapGenerator.gd" id="2_qvwn8"]
|
||||
|
||||
[node name="Node2D" type="Node2D"]
|
||||
|
||||
[node name="TileMap" type="TileMap" parent="."]
|
||||
tile_set = ExtResource("1_8lepy")
|
||||
cell_quadrant_size = 8
|
||||
collision_visibility_mode = 1
|
||||
format = 2
|
||||
script = ExtResource("2_qvwn8")
|
216
Scripts/MapGenerator.gd
Normal file
216
Scripts/MapGenerator.gd
Normal file
|
@ -0,0 +1,216 @@
|
|||
extends TileMap
|
||||
|
||||
@export var width := 128
|
||||
@export var height := 75
|
||||
@export var fill_percentage := 0.65
|
||||
|
||||
@export var solid_id := 0
|
||||
@export var non_solid_id := 1
|
||||
|
||||
@export var solid_threshold := 7
|
||||
@export var nonsolid_threshold := 4
|
||||
|
||||
@export var start_area_size := 5
|
||||
@export var start_area_corner_size := 2
|
||||
|
||||
@export var cave_gen_iterations := 3
|
||||
@export var cave_mine_size_threshold := 80
|
||||
|
||||
func _ready():
|
||||
var start_time = Time.get_unix_time_from_system()
|
||||
randomize()
|
||||
random_fill()
|
||||
make_cave_areas()
|
||||
make_borders()
|
||||
prepare_player_start_area()
|
||||
connect_caves(get_caves())
|
||||
make_cave_areas()
|
||||
make_borders()
|
||||
print(Time.get_unix_time_from_system() - start_time)
|
||||
|
||||
func random_fill():
|
||||
for x in width:
|
||||
for y in height:
|
||||
if randf() < fill_percentage:
|
||||
self.set_cell(0, Vector2i(x,y),solid_id, Vector2i(0, 0))
|
||||
else:
|
||||
self.set_cell(0, Vector2i(x,y),non_solid_id, Vector2i(0, 0))
|
||||
pass
|
||||
|
||||
func make_borders():
|
||||
for x in width:
|
||||
self.set_cell(0, Vector2i(x,0),solid_id, Vector2i(0, 0))
|
||||
self.set_cell(0, Vector2i(x,height-1),solid_id, Vector2i(0, 0))
|
||||
for y in height:
|
||||
self.set_cell(0, Vector2i(0,y),solid_id, Vector2i(0, 0))
|
||||
self.set_cell(0, Vector2i(width-1,y),solid_id, Vector2i(0, 0))
|
||||
|
||||
func prepare_player_start_area():
|
||||
var center = Vector2i(width/2, height/2)
|
||||
for x in range(center.x - start_area_size, center.x + start_area_size):
|
||||
|
||||
# Getting a P factor for the corner "radius" Decission
|
||||
var p := 0
|
||||
if x <= center.x - start_area_size + start_area_corner_size:
|
||||
p = center.x - start_area_size + start_area_corner_size - x
|
||||
if x >= center.x + start_area_size - start_area_corner_size:
|
||||
p = x - ( center.x + start_area_size) + start_area_corner_size + 1
|
||||
var p2 = p
|
||||
|
||||
for y in range(center.y - start_area_size, center.y + start_area_size):
|
||||
# Decide if the tile is part of the Corner or not
|
||||
if !(p2 > 0 or p2 <= - (start_area_size*2 - p*2)):
|
||||
self.set_cell(0, Vector2i(x,y),non_solid_id, Vector2i(0, 0))
|
||||
p2 -= 1
|
||||
|
||||
func make_cave_areas():
|
||||
for i in cave_gen_iterations:
|
||||
for x in range(1, width):
|
||||
for y in range(1, height):
|
||||
# Count Solid Neighbor Cells
|
||||
var count := 0
|
||||
#y-1
|
||||
if self.get_cell_source_id(0, Vector2i(x-1, y-1)) == solid_id: count +=1
|
||||
if self.get_cell_source_id(0, Vector2i(x, y-1)) == solid_id: count +=1
|
||||
if self.get_cell_source_id(0, Vector2i(x+1, y-1)) == solid_id: count +=1
|
||||
#y
|
||||
if self.get_cell_source_id(0, Vector2i(x-1, y)) == solid_id: count +=1
|
||||
if self.get_cell_source_id(0, Vector2i(x+1, y)) == solid_id: count +=1
|
||||
#y+1
|
||||
if self.get_cell_source_id(0, Vector2i(x-1, y+1)) == solid_id: count +=1
|
||||
if self.get_cell_source_id(0, Vector2i(x, y+1)) == solid_id: count +=1
|
||||
if self.get_cell_source_id(0, Vector2i(x+1, y+1)) == solid_id: count +=1
|
||||
|
||||
# Check Wether to Change the Cell or Not
|
||||
if count < nonsolid_threshold:
|
||||
self.set_cell(0, Vector2i(x,y),non_solid_id, Vector2i(0, 0))
|
||||
|
||||
if count >= solid_threshold:
|
||||
self.set_cell(0, Vector2i(x,y),solid_id, Vector2i(0, 0))
|
||||
pass
|
||||
|
||||
func get_caves() -> Array:
|
||||
# get caves
|
||||
var caves := []
|
||||
|
||||
for x in range (2, width-2):
|
||||
for y in range (2, height-2):
|
||||
if self.get_cell_source_id(0, Vector2i(x, y)) == non_solid_id:
|
||||
flood_fill(x,y, caves)
|
||||
|
||||
for cave in caves:
|
||||
for tile in cave:
|
||||
self.set_cell(0, Vector2i(tile.x,tile.y),non_solid_id, Vector2i(0, 0))
|
||||
return caves
|
||||
|
||||
func flood_fill(tilex, tiley, caves) -> Array:
|
||||
var cave := []
|
||||
var to_fill := [Vector2i(tilex, tiley)]
|
||||
while to_fill:
|
||||
var tile = to_fill.pop_back()
|
||||
|
||||
if !cave.has(tile):
|
||||
cave.append(tile)
|
||||
self.set_cell(0, Vector2i(tile.x,tile.y),solid_id, Vector2i(0, 0))
|
||||
|
||||
#check adjacent cells
|
||||
var north = Vector2i(tile.x, tile.y+1)
|
||||
var south = Vector2i(tile.x, tile.y-1)
|
||||
var east = Vector2i(tile.x+1, tile.y)
|
||||
var west = Vector2i(tile.x-1, tile.y)
|
||||
|
||||
for dir in [north,south,east,west]:
|
||||
if self.get_cell_source_id(0, dir) == non_solid_id:
|
||||
if !to_fill.has(dir) and !cave.has(dir):
|
||||
to_fill.append(dir)
|
||||
if cave.size() >= cave_mine_size_threshold:
|
||||
caves.append(cave)
|
||||
return caves
|
||||
|
||||
func choose(choices):
|
||||
randomize()
|
||||
|
||||
var rand_index = randi() % choices.size()
|
||||
return choices[rand_index]
|
||||
|
||||
func connect_caves(caves):
|
||||
var prev_cave = null
|
||||
var tunnel_caves = caves.duplicate()
|
||||
|
||||
for cave in tunnel_caves:
|
||||
if prev_cave:
|
||||
var new_point = choose(cave)
|
||||
var prev_point = choose(prev_cave)
|
||||
|
||||
# ensure not the same point
|
||||
if new_point != prev_point:
|
||||
create_tunnel(new_point, prev_point, cave)
|
||||
|
||||
prev_cave = cave
|
||||
pass
|
||||
|
||||
func create_tunnel(point1, point2, cave):
|
||||
randomize() # for randf
|
||||
var max_steps = 500 # so editor won't hang if walk fails
|
||||
var steps = 0
|
||||
var drunk_x = point2[0]
|
||||
var drunk_y = point2[1]
|
||||
|
||||
while steps < max_steps and !cave.has(Vector2i(drunk_x, drunk_y)):
|
||||
steps += 1
|
||||
|
||||
# set initial dir weights
|
||||
var n = 1.0
|
||||
var s = 1.0
|
||||
var e = 1.0
|
||||
var w = 1.0
|
||||
var weight = 1
|
||||
|
||||
# weight the random walk against edges
|
||||
if drunk_x < point1.x: # drunkard is left of point1
|
||||
e += weight
|
||||
elif drunk_x > point1.x: # drunkard is right of point1
|
||||
w += weight
|
||||
if drunk_y < point1.y: # drunkard is above point1
|
||||
s += weight
|
||||
elif drunk_y > point1.y: # drunkard is below point1
|
||||
n += weight
|
||||
|
||||
# normalize probabilities so they form a range from 0 to 1
|
||||
var total = n + s + e + w
|
||||
n /= total
|
||||
s /= total
|
||||
e /= total
|
||||
w /= total
|
||||
|
||||
var dx
|
||||
var dy
|
||||
|
||||
# choose the direction
|
||||
var choice = randf()
|
||||
|
||||
if 0 <= choice and choice < n:
|
||||
dx = 0
|
||||
dy = -1
|
||||
elif n <= choice and choice < (n+s):
|
||||
dx = 0
|
||||
dy = 1
|
||||
elif (n+s) <= choice and choice < (n+s+e):
|
||||
dx = 1
|
||||
dy = 0
|
||||
else:
|
||||
dx = -1
|
||||
dy = 0
|
||||
|
||||
# ensure not to walk past edge of map
|
||||
if (2 < drunk_x + dx and drunk_x + dx < width-2) and \
|
||||
(2 < drunk_y + dy and drunk_y + dy < height-2):
|
||||
drunk_x += dx
|
||||
drunk_y += dy
|
||||
|
||||
|
||||
if self.get_cell_source_id(0, Vector2i(drunk_x, drunk_y)) == solid_id:
|
||||
self.set_cell(0, Vector2i(drunk_x, drunk_y),non_solid_id, Vector2i(0, 0))
|
||||
#make tunnel wider
|
||||
self.set_cell(0, Vector2i(drunk_x+1, drunk_y),non_solid_id, Vector2i(0, 0))
|
||||
self.set_cell(0, Vector2i(drunk_x+1, drunk_y+1),non_solid_id, Vector2i(0, 0))
|
|
@ -15,6 +15,10 @@ run/main_scene="res://Scenes/Test.tscn"
|
|||
config/features=PackedStringArray("4.0", "GL Compatibility")
|
||||
config/icon="res://icon.svg"
|
||||
|
||||
[layer_names]
|
||||
|
||||
2d_physics/layer_1="Map"
|
||||
|
||||
[rendering]
|
||||
|
||||
renderer/rendering_method="gl_compatibility"
|
||||
|
|
Reference in a new issue