diff --git a/Assets/Sprites/PlaceHolderA.png b/Assets/Sprites/PlaceHolderA.png new file mode 100644 index 0000000..9bac857 Binary files /dev/null and b/Assets/Sprites/PlaceHolderA.png differ diff --git a/Assets/Sprites/PlaceHolderA.png.import b/Assets/Sprites/PlaceHolderA.png.import new file mode 100644 index 0000000..b23dd9c --- /dev/null +++ b/Assets/Sprites/PlaceHolderA.png.import @@ -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 diff --git a/Assets/Sprites/PlaceHolderB.png b/Assets/Sprites/PlaceHolderB.png new file mode 100644 index 0000000..ceae8aa Binary files /dev/null and b/Assets/Sprites/PlaceHolderB.png differ diff --git a/Assets/Sprites/PlaceHolderB.png.import b/Assets/Sprites/PlaceHolderB.png.import new file mode 100644 index 0000000..62f9ec7 --- /dev/null +++ b/Assets/Sprites/PlaceHolderB.png.import @@ -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 diff --git a/Assets/Test_Tileset.tres b/Assets/Test_Tileset.tres new file mode 100644 index 0000000..bdce79f --- /dev/null +++ b/Assets/Test_Tileset.tres @@ -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") diff --git a/Scenes/Cave.tscn b/Scenes/Cave.tscn new file mode 100644 index 0000000..ff0ce79 --- /dev/null +++ b/Scenes/Cave.tscn @@ -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") diff --git a/Scripts/MapGenerator.gd b/Scripts/MapGenerator.gd new file mode 100644 index 0000000..7267c96 --- /dev/null +++ b/Scripts/MapGenerator.gd @@ -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)) diff --git a/project.godot b/project.godot index 7d4e427..5e401af 100644 --- a/project.godot +++ b/project.godot @@ -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"