diff --git a/map.png b/map.png new file mode 100644 index 0000000..6aa2e53 Binary files /dev/null and b/map.png differ diff --git a/map.png.import b/map.png.import new file mode 100644 index 0000000..1a95dd4 --- /dev/null +++ b/map.png.import @@ -0,0 +1,35 @@ +[remap] + +importer="texture" +type="StreamTexture" +path="res://.import/map.png-9eea34967fae34f4388f4a32a16da936.stex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://map.png" +dest_files=[ "res://.import/map.png-9eea34967fae34f4388f4a32a16da936.stex" ] + +[params] + +compress/mode=0 +compress/lossy_quality=0.7 +compress/hdr_mode=0 +compress/bptc_ldr=0 +compress/normal_map=0 +flags/repeat=0 +flags/filter=true +flags/mipmaps=false +flags/anisotropic=false +flags/srgb=2 +process/fix_alpha_border=true +process/premult_alpha=false +process/HDR_as_SRGB=false +process/invert_color=false +process/normal_map_invert_y=false +stream=false +size_limit=0 +detect_3d=true +svg/scale=1.0 diff --git a/menu/MainMenu.tscn b/menu/MainMenu.tscn index cc63e15..afb6f2c 100644 --- a/menu/MainMenu.tscn +++ b/menu/MainMenu.tscn @@ -47,10 +47,6 @@ margin_right = 360.0 margin_bottom = 377.0 text = "Quitter" -[node name="Viewport" type="Viewport" parent="."] -size = Vector2( 2048, 2048 ) -own_world = true - [connection signal="pressed" from="VBoxContainer/NewButton" to="." method="_on_NewButton_pressed"] [connection signal="pressed" from="VBoxContainer/LoadButton" to="." method="_on_LoadButton_pressed"] [connection signal="pressed" from="VBoxContainer/QuitButton" to="." method="_on_QuitButton_pressed"] diff --git a/project.godot b/project.godot index f7a4337..8d54fdf 100644 --- a/project.godot +++ b/project.godot @@ -30,6 +30,11 @@ _global_script_classes=[ { "path": "res://utils/loading/LoadingHelper.gd" }, { "base": "Reference", +"class": "Map", +"language": "GDScript", +"path": "res://utils/map/map.gd" +}, { +"base": "Reference", "class": "PoissonDiscSampling", "language": "GDScript", "path": "res://addons/PoissonDiscSampling/PoissonDiscSampling.gd" @@ -54,6 +59,7 @@ _global_script_class_icons={ "CameraOutline": "", "Delaunator": "", "LoadingHelper": "", +"Map": "", "PoissonDiscSampling": "", "Terrain": "", "TerrainMesh": "", @@ -70,6 +76,10 @@ config/icon="res://icon.png" Global="*res://utils/Global.gd" +[display] + +window/dpi/allow_hidpi=true + [editor_plugins] enabled=PoolStringArray( ) diff --git a/ui/map/cursor/Cursor.gd b/ui/map/cursor/Cursor.gd index e4d7547..ca5fc07 100644 --- a/ui/map/cursor/Cursor.gd +++ b/ui/map/cursor/Cursor.gd @@ -3,6 +3,9 @@ extends Sprite func _on_Camera_camera_moved(new_location): var map_x = new_location.x var map_y = new_location.z - position.x = map_x - position.y = map_y - pass # Replace with function body. + position.x = map_x / 4.0 + position.y = map_y / 4.0 + +func _ready(): + scale.x = 1 + scale.y = 1 diff --git a/ui/map/map.gd b/ui/map/map.gd index a7fc20c..e7e1d7e 100644 --- a/ui/map/map.gd +++ b/ui/map/map.gd @@ -1,113 +1,18 @@ -extends Node2D +extends TextureRect signal map_clicked -func heightmap(): - draw_rect(Rect2(Vector2(0, 0), Vector2(2048, 2048)), Color("#0e88bd")) - var coastline = PoolVector2Array() - - for center in Global.terrain.get_centers(): - if not center.get_data("ocean"): - var colors = Gradient.new() - colors.add_point(0.999, Color("#9e0142")) # red - colors.add_point(0.5, Color("#dc865d")) # orange - colors.add_point(0.25, Color("#fbf8b0")) # yellow - colors.add_point(0.0, Color("#89cfa5")) # green - colors.add_point(-0.999, Color("#5e4fa2")) # blue - var color = colors.interpolate(min(center.get_elevation() + 0.001, 0.999)) - var moisture = center.get_data("moisture") - if moisture: - color = colors.interpolate(max(min(moisture + 0.001, 0.999), 0.001)) - # color = Color.green - if center.get_data("ocean"): - # var factor = pow((center.get_elevation()+1.001), 10) / 5.0 - color = Color("#5e4fa2") -# if center.get_data("snow"): -# color = Color.white - # if center.get_data("coast"): - # color = Color.black - if center.polygon().size() > 2: - draw_polygon(center.polygon(), PoolColorArray([color])) - - if center.get_data("coast"): - for border in center.borders(): - if (border.end_center().get_data("ocean")): - coastline.append(border.line()[0]) - coastline.append(border.line()[1]) - - # for edge in Global.terrain.get_edges(): - # if edge.get_data("coast"): - - # if edge.get_data("river"): - # draw_line(edge.line()[0], edge.line()[1], Color.blue, 5.0) - draw_multiline(coastline, Color.black) - -func draw_triangles_edges(color=Color("#000000")): - for line in Global.terrain.get_edges_as_line(): - draw_line(line[0], line[1], color) - -func draw_voronoi_edges(color=Color("#000000")): - for line in Global.terrain.get_voronoi_edges_as_line(): - draw_line(line[0], line[1], color) - -func draw_voronoi_cells_old(): - var seen = [] - for edge_idx in Global.terrain.edges(): - var triangles = [] - var vertices = [] - var p = Global.terrain._triangles[Global.terrain.next_half_edge(edge_idx)] - if not seen.has(p): - seen.append(p) - var edges = Global.terrain.edges_around_point(edge_idx) - for edge_around_idx in edges: - triangles.append(Global.terrain.triangle_of_edge(edge_around_idx)) - for triangle in triangles: - vertices.append(Global.terrain.triangle_center(triangle)) - - if triangles.size() > 2: - var color = Color(randf(), randf(), randf(), 1) - var voronoi_cell = PoolVector2Array() - for vertice in vertices: - voronoi_cell.append(Vector2(vertice.x, vertice.z)) - draw_polygon(voronoi_cell, PoolColorArray([color])) -func draw_voronoi_cells(): - for polygon in Global.terrain.get_voronoi_cells_as_polygon(): - var color = Color(randf(), randf(), randf(), 1) - if polygon.size() > 2: - draw_polygon(polygon, PoolColorArray([color])) - -func draw_voronoi_cells_convex_hull(): - for point_idx in Global.terrain.points(): - var triangles = [] - var vertices = [] - var incoming = Global.terrain._points_to_half_edges.get(point_idx) - - if incoming == null: - triangles.append(0) - else: - var edges = Global.terrain.edges_around_point(incoming) - for edge_idx in edges: - triangles.append(Global.terrain.triangle_of_edge(edge_idx)) - - for triangle_idx in triangles: - vertices.append(Global.terrain.triangle_center(triangle_idx)) - - if triangles.size() > 2: - var color = Color(randf(), randf(), randf(), 1) - var voronoi_cell = PoolVector2Array() - for vertice in vertices: - voronoi_cell.append(Vector2(vertice[0], vertice[1])) - draw_polygon(voronoi_cell, PoolColorArray([color])) - -func _draw(): - heightmap() -# draw_voronoi_cells() -# draw_triangles_edges() - # draw_voronoi_cells_convex_hull() -# draw_voronoi_edges(Color("#ff0000")) +func _ready(): + var file_name = 'user://terrain/%s/map.png' % (Global.terrain_name) + var image = Image.new() + var err = image.load(file_name) + if err != OK: + print('Image load failed : %s' % (file_name)) + texture = ImageTexture.new() + texture.create_from_image(image, Image.FORMAT_RGBA8) func _process(_delta): if Input.is_action_pressed("alt_command"): - var new_position = get_viewport().get_mouse_position() / scale - if new_position.x <= 2000 and new_position.y <= 2000: + var new_position = get_viewport().get_mouse_position() + if new_position.x <= 512 and new_position.y <= 512: emit_signal("map_clicked", new_position) diff --git a/ui/map/map.tscn b/ui/map/map.tscn index 31f5e94..9d8b8a4 100644 --- a/ui/map/map.tscn +++ b/ui/map/map.tscn @@ -4,7 +4,11 @@ [ext_resource path="res://ui/map/cursor/cursor.png" type="Texture" id=2] [ext_resource path="res://ui/map/cursor/Cursor.gd" type="Script" id=3] -[node name="Map" type="Node2D"] +[node name="Map" type="TextureRect"] +anchor_right = 0.5 +anchor_bottom = 0.852 +margin_right = 3.0 +margin_bottom = 0.799988 script = ExtResource( 1 ) [node name="Cursor" type="Sprite" parent="."] diff --git a/utils/Global.gd b/utils/Global.gd index f1ffb16..9eb42ff 100644 --- a/utils/Global.gd +++ b/utils/Global.gd @@ -4,6 +4,7 @@ var debug = true var terrain_name = "" var terrain_mesh: Mesh var terrain = Terrain.new() +var map = Map.new(terrain) # var loading = LoadingHelper.new() var loadings = {} var materials @@ -14,6 +15,64 @@ func _ready(): file.open("res://world/materials/materials.json", File.READ) materials = JSON.parse(file.get_as_text()).result file.close() + +func polygon_area(polygon): + var a = 0.0 + var b = 0.0 + var next = 0 + var size = polygon.size() + if(Geometry.is_polygon_clockwise(polygon)): + for idx in range(size-1, -1, -1): + next = idx - 1 + if(next == 0): + next = size - 1 + a += polygon[idx].x * polygon[next].y + b += polygon[idx].y * polygon[next].x + else: + for idx in size: + next = idx + 1 + if(next == size): + next = 0 + a += polygon[idx].x * polygon[next].y + b += polygon[idx].y * polygon[next].x + return((a - b) / 2.0) + +func polygon_bounding_box(polygon): + var size = polygon.size() + var min_x = 99999999 + var max_x = -99999999 + var min_y = 99999999 + var max_y = -99999999 + var polygon_xmin = 0 + var polygon_xmax = 1 + var polygon_ymin = 0 + var polygon_ymax = 1 + for idx in size: + polygon_xmin = int(polygon[idx].x) + polygon_xmax = polygon_xmin + 1 + polygon_ymin = int(polygon[idx].y) + polygon_ymax = polygon_ymin + 1 + if(polygon_xmin < min_x): + min_x = polygon_xmin + if(polygon_xmax > max_x): + max_x = polygon_xmax + if(polygon_ymin < min_y): + min_y = polygon_ymin + if(polygon_ymax > max_y): + max_y = polygon_ymax + return(Rect2(min_x,min_y,max_x - min_x, max_y - min_y)) + +func pixel_area(voronoi, pixel): + var polygons = Geometry.intersect_polygons_2d(voronoi, pixel) + var number = polygons.size() + var area = 0.0 + if(number == 0): + return(0.0) + if(number > 1): + print_debug("Number of polygons : %d" % (number)) + for idx in number: + area += polygon_area(polygons[idx]) + return(area) # Debuging messages func print_debug(message): diff --git a/utils/camera/CameraController.gd b/utils/camera/CameraController.gd index bd4007f..fff62f3 100644 --- a/utils/camera/CameraController.gd +++ b/utils/camera/CameraController.gd @@ -50,7 +50,7 @@ func change_action(action): CAMERA_ACTIONS.ROTATING_VIEW: Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED) -func _process(delta): +func _process(_delta): match(current_action): CAMERA_ACTIONS.MOVING: @@ -121,8 +121,8 @@ func rotate_view(axis : Vector2): rotation.y = yaw func teleport(position): - global_transform.origin.x = position.x - global_transform.origin.z = position.y + global_transform.origin.x = position.x * 4.0 + global_transform.origin.z = position.y * 4.0 var y_offset = 0 var space_state = get_world().direct_space_state diff --git a/utils/camera/CameraInput.gd b/utils/camera/CameraInput.gd index 4c0e185..466da10 100644 --- a/utils/camera/CameraInput.gd +++ b/utils/camera/CameraInput.gd @@ -139,7 +139,7 @@ func _input(event): mouse_wheel += direction * get_process_delta_time() * 1000 ###################PC -func _process(delta): +func _process(_delta): #PC###### match(current_action): diff --git a/utils/map/map.gd b/utils/map/map.gd new file mode 100644 index 0000000..9454c16 --- /dev/null +++ b/utils/map/map.gd @@ -0,0 +1,51 @@ +extends Reference + +# Build terrain from delaunay graph +class_name Map + +var image +var terrain + +# Called when the node enters the scene tree for the first time. +func _init(a_terrain): + self.terrain = a_terrain + a_terrain.set_data("map",self) + +func gen_map(): + Global.loadings["world_creation"].new_phase("Generation de la carte...", terrain._points.size()) + image = Image.new() + image.create(terrain._width,terrain._height,false,Image.FORMAT_RGBA8) + image.lock() + image.fill(Color('#5aa6ca')) + image.unlock() + var file_name = "user://terrain/%s/map.png" % (terrain.get_name()) + + for center in terrain.get_centers(): + if not center.get_data("water"): + var voronoi = center.get_data("voronoi") + var voronoi_bounding_box = center.get_data("voronoi_bounding_box") +# print_debug("Creat voronoi image") + var voronoi_image = Image.new() + voronoi_image.create(int(voronoi_bounding_box.size.x), int(voronoi_bounding_box.size.y),false,Image.FORMAT_RGBA8) + voronoi_image.lock() + for x in int(voronoi_bounding_box.size.x): + for y in int(voronoi_bounding_box.size.y): + var pixel = [] + pixel.append(Vector2(voronoi_bounding_box.position.x + x, voronoi_bounding_box.position.y + y)) + pixel.append(Vector2(voronoi_bounding_box.position.x + x + 1, voronoi_bounding_box.position.y + y)) + pixel.append(Vector2(voronoi_bounding_box.position.x + x + 1, voronoi_bounding_box.position.y + y + 1)) + pixel.append(Vector2(voronoi_bounding_box.position.x + x, voronoi_bounding_box.position.y + y + 1)) + var alpha = Global.pixel_area(voronoi, pixel) +# print_debug("Alpha : %f" % (alpha)) + var color + if center.get_data("coast"): + color = Color(0.708, 0.646, 0.138, alpha) + else: + color = Color(0.253, 0.621, 0.229, alpha) + voronoi_image.set_pixel(x,y,color) + image.lock() + image.blend_rect(voronoi_image,Rect2(0.0,0.0,voronoi_bounding_box.size.x,voronoi_bounding_box.size.y),voronoi_bounding_box.position) + image.unlock() + voronoi_image.unlock() + Global.loadings["world_creation"].increment_step() + image.save_png(file_name) diff --git a/utils/terrain/Terrain.gd b/utils/terrain/Terrain.gd index 8b4767e..53300cf 100644 --- a/utils/terrain/Terrain.gd +++ b/utils/terrain/Terrain.gd @@ -106,7 +106,8 @@ class VoronoiCenter: func corners(): var list_corners = [] - for triangle in to_point().triangles_around(): + var a_point = to_point() + for triangle in a_point.triangles_around(): var corner = VoronoiCorner.new(triangle) list_corners.append(corner) return list_corners @@ -291,7 +292,6 @@ class Triangle: ) set_data("center2d", circumcenter) - return circumcenter return circumcenter # return (points[0].point2d() + points[1].point2d() + points[2].point2d()) / 3.0 @@ -314,7 +314,6 @@ class Triangle: ) set_data("center3d", circumcenter) - return circumcenter return circumcenter # var center2d = center2d() # return Vector3(center2d.x, ) @@ -430,15 +429,16 @@ class Point: func edges_around(): var list_edges = [] - var incoming = _terrain._points_to_halfedges.get(_idx) - var incoming_edge = Edge.new(incoming, _terrain) - var outgoing_edge - while true: - list_edges.append(incoming_edge); - outgoing_edge = incoming_edge.next_half() - incoming_edge = Edge.new(_terrain._halfedges[outgoing_edge._idx], _terrain); - if not (incoming_edge._idx != -1 and incoming_edge._idx != incoming): - break + if _terrain._points_to_halfedges.has(_idx): + var incoming = _terrain._points_to_halfedges.get(_idx) + var incoming_edge = Edge.new(incoming, _terrain) + var outgoing_edge + while true: + list_edges.append(incoming_edge); + outgoing_edge = incoming_edge.next_half() + incoming_edge = Edge.new(_terrain._halfedges[outgoing_edge._idx], _terrain); + if not (incoming_edge._idx != -1 and incoming_edge._idx != incoming): + break return list_edges func points_around(): @@ -579,7 +579,7 @@ var _path = "" var _list = [] # Terrain constructor -func _init(width:int=1600, height:int=800, spacing:int=30, create=false, name:String=""): +func _init(): var directory = Directory.new() var file = File.new() var file_name = "" @@ -616,18 +616,6 @@ func _init(width:int=1600, height:int=800, spacing:int=30, create=false, name:St directory_name = directory.get_next() directory.list_dir_end() - # Create or Load Terrain - _path = "user://terrain/%s" % (name) - parameter_file_name = "%s/param.save" % (_path) - graph_file_name = "%s/graph.save" % (_path) - data_file_name = "%s/data.save" % (_path) - if directory.open(_path) == OK and file.file_exists(parameter_file_name) and file.file_exists(graph_file_name) and file.file_exists(data_file_name) and not create: - Global.print_debug("loading : %s ..." % (name)) - load(name) - else: - if name: - create(width, height, spacing, name) - func create(width:int, height:int, spacing:int, name:String): Global.print_debug("Creating : %s ..." % (name)) var delaunay: Delaunator @@ -643,15 +631,6 @@ func create(width:int, height:int, spacing:int, name:String): _triangles = PoolIntArray(delaunay.triangles) Global.loadings["world_creation"].new_phase("Initialisation du terrain...", get_points().size() + get_edges().size()) - - # Initialize find_point - _data["find_point"]=[] - _data["find_point"].resize(1024) - for idx in 1024: - _data["find_point"][idx]=[] - for point in get_points(): - _data["find_point"][point.find_index()].append(point.get_index()) - Global.loadings["world_creation"].increment_step() # Initialize _points_to_halfedges for edge in get_edges(): @@ -660,6 +639,7 @@ func create(width:int, height:int, spacing:int, name:String): _points_to_halfedges[endpoint] = edge.get_index() Global.loadings["world_creation"].increment_step() + _create_find_point_table() # Initialise _points_data for point_idx in self.get_points().size(): _points_data.append({}) @@ -677,6 +657,22 @@ func create(width:int, height:int, spacing:int, name:String): _created = true save() + +# Create a table to find a point from vector2 +func _create_find_point_table(): + var find_point = [] +# var corners = {} +# var edges = {} + find_point.resize(1024) + for idx in 1024: + find_point[idx]=[] + for point in get_points(): + var point_index = point.get_index() + find_point[point.find_index()].append(point_index) + + var center = point.to_center() + + set_data("find_point",find_point) # Create points on the terrain func _create_points(): @@ -698,6 +694,9 @@ func set_temp_data(key, value): func get_data(key): if _data.has(key): return _data[key] + +func get_name(): + return _name func get_temp_data(key): if _temp_data.has(key): diff --git a/utils/world_generation/WorldGeneration.gd b/utils/world_generation/WorldGeneration.gd index bc8fa34..f3bf358 100644 --- a/utils/world_generation/WorldGeneration.gd +++ b/utils/world_generation/WorldGeneration.gd @@ -26,7 +26,7 @@ func _init(): Global.loadings["world_creation"].start(coeffs, "Chargement...", 100) Global.terrain.load(Global.terrain_name) else: - var coeffs = [0, 1, 2, 2, 2, 2, 2, 8] + var coeffs = [0, 1, 2, 2, 2, 2, 2, 8, 8] Global.loadings["world_creation"].start(coeffs, "Start", 100) Global.terrain.create(width,height,spacing,Global.terrain_name) @@ -36,6 +36,7 @@ func _init(): Global.terrain.save() var terrain_mesh = TerrainMesh.new() Global.terrain.set_temp_data("mesh", terrain_mesh.create_mesh()) + Global.map.gen_map() if Global.terrain.is_loaded(): var terrain_mesh = TerrainMesh.new() @@ -73,6 +74,7 @@ func init_data(): center.set_data("material", "stone") if center.get_data("coast"): center.set_data("material", "sand") + if ( not center.get_data("coast") and not center.get_data("mountain") @@ -80,6 +82,13 @@ func init_data(): and center.get_data("moisture") > 0.3 ): center.set_data("forest", true) + + if not center.get_data("water"): + var voronoi = center.polygon() + center.set_data("voronoi",voronoi) + var voronoi_bounding_box = Global.polygon_bounding_box(voronoi) + center.set_data("voronoi_bounding_box",voronoi_bounding_box) + Global.loadings["world_creation"].increment_step() diff --git a/world/game.tscn b/world/game.tscn index 7cf1029..8534227 100644 --- a/world/game.tscn +++ b/world/game.tscn @@ -165,7 +165,12 @@ shader_param/outline_color = Color( 0, 0, 0, 1 ) [node name="UI" parent="." instance=ExtResource( 1 )] [node name="Map" parent="UI" index="0"] -scale = Vector2( 0.25, 0.25 ) +anchor_right = 0.0 +anchor_bottom = 0.0 +margin_right = 512.0 +margin_bottom = 512.0 +expand = true +stretch_mode = 1 [node name="Cursor" parent="UI/Map" index="0"] scale = Vector2( 4, 4 )