I GameDevDiary: Road Network and Improved Movement
Check out the progress in the making of version 0.4 of my strategy game
Hi! This time I have worked on the road network as I promised in the last entry. This involved connecting cities using my old algorithm and adding bridges to connect the rest of the map. I think that I have a lot of interesting features to talk about so…
…Let’s get started!
· Road Network
∘ Road Scene
∘ Connecting Cities
∘ Connecting Edges To Cities
∘ Bridges
· Improved Movement
∘ How it works
· Miscellaneous
∘ outline for forests:
∘ outline for units:
∘ new background:
∘ the game starts on the start screen:
∘ settings screen:
· Bug Fixes
· Conclusion
· Demo
∘ Check out the previous article
Road Network
Road Scene
I have created the road out of an area 2D with, a collision shape and a Line2D. Since a similar structure could be found inside the rivers, it wasn’t hard to implement.
Connecting Cities
I have rewritten my algorithm for connecting towns in Python and couldn’t help but notice, how shorter it became thanks to the built-in features of Godot which allow me to easily get the global position of nodes and to find the position between two points on a canvas.
The code works by finding the 2 closest cities to the city. If those cities aren’t connected to more than 3 cities themselves, the town connects itself to them by saving them inside of its connected cities array. It then instantiates roads between itself and the city using another function.
func instantiate_roads(start, end):
var road_instance = road_scene.instantiate() as Node2D
var collision_area = road_instance.get_node("Area2D")
collision_area.position = Vector2(start + end ) / 2
collision_area.rotation = start.direction_to(end).angle()
var length = start.distance_to(end)
var rect = RectangleShape2D.new()
var collision_shape = collision_area.get_node("CollisionShape2D")
rect.extents = Vector2(length / 2, 7)
collision_shape.shape = rect
road_instance.get_node("Line2D").add_point( end )
road_instance.get_node("Line2D").add_point( start )
$Structures.add_child(road_instance)
Connecting Edges To Cities
Here I first take a random point at each edge of the game viewport. Then I find the town whose center is closest to it and instantiate a road using the same function as in the previous paragraph. The code looks like this
func create_roads_to_edges():
var top_point = Vector2(randi_range(100, get_viewport().size.x -100), 0)
var right_point = Vector2( get_viewport().size.x , randi_range(100, get_viewport().size.y -100))
var left_point = Vector2( 0 , randi_range(100, get_viewport().size.y -100 ))
var bottom_point = Vector2(randi_range(100, get_viewport().size.x -100 ), get_viewport().size.y )
var edge_points = [top_point,right_point,left_point,bottom_point]
for edge_point in edge_points:
var closest_town_center_pos
for town in get_tree().get_nodes_in_group("towns"):
print(town, Utils. get_collision_shape_center(town ) )
print( Utils. get_collision_shape_center(town ).distance_to(edge_point) , closest_town_center_pos)
if closest_town_center_pos == null:
closest_town_center_pos = Utils. get_collision_shape_center(town )
elif Utils. get_collision_shape_center(town ).distance_to(edge_point) < closest_town_center_pos.distance_to(edge_point):
closest_town_center_pos = Utils. get_collision_shape_center(town )
if closest_town_center_pos == null:
return
instantiate_roads(closest_town_center_pos, edge_point)
Bridges
When a unit has a collision with a bridge it ignores collisions with the river, which allows it to traverse the bridge easily. I also made the bridges face the river at a 90-degree angle.
func add_bridges():
for river in get_tree().get_nodes_in_group("rivers"):
var has_crossing = false
for segment in river.get_children():
if has_crossing:
break
# print(segment.get_node("Area2D").get_overlapping_areas())
for area in segment.get_node("Area2D").get_overlapping_areas():
# print(area, area.get_parent() , area.get_parent().get_parent())
if area.get_parent() is Road:
has_crossing = true
print("ROAD CROSSES THIS RIVER", river)
break
if !has_crossing:
var segment_num = randi_range(0, len(river.get_children())-1)
var new_bridge_position = to_global(river.get_child(segment_num).get_node("Area2D").global_position)
var bridge_instance = bridge_scene.instantiate() as Sprite2D
bridge_instance.position = new_bridge_position
$Structures.add_child(bridge_instance)
print(river, " NEEDS A BRIDGE ", new_bridge_position )
Improved Movement
In the last version, the unit could move inside of a circle around its starting position. This didn't allow me to expand upon much, so I finally got around to adding a revamped movement system.
How it works
This time every time a unit moves a pixel, it subtracts 1 point in its remaining distance variable. When this value reaches zero a function to abort the movement is called moving the unit back to center resetting its value.
On top of that, I can augment the amount subtracted using a movement modifiers variable, where I put values for being in a forest or on a road.
var movement_modifieres:Dictionary = {
"base_modifier": 1
}
distance_just_traveled = floor( owner.center.distance_to(mouse_pos) ) * current_movement_modifier
Miscellaneous
outline for forests:
For better contrast, I have added an outline for the forests using a function that creates a line 2d out of a polygon 2d below.
func polygon_to_line2d(polygon: Polygon2D, width: float, color: Color = Color(1, 1, 1, 1)) -> Line2D:
var line = Line2D.new()
var vertecies = polygon.get_polygon()
vertecies.append(vertecies[0]) ## so the line is circumnavigating the whole polygon
# print(vertecies)
line.width = width
line.modulate = color
for i in range( len(vertecies) ):
line.add_point(vertecies[i])
return line
outline for units:
Using the same function I have added an outline for the units as well
new background:
The previous background was a little too bright for my taste, so I turned it down.
the game starts on the start screen:
To polish the game a bit, I finally got around to changing the beginning scene to the start screen so you aren’t immediately thrown in the middle of the battle. Here you can choose to go to the settings screen, start a new game, or end the game
settings screen:
You are now able to customize the battleground by setting the values in the settings screen. So far I have set up sliders for the income of players and for the generation of the game.
Bug Fixes
- The towns are no longer overlapping
- The visual connection between a support unit and a supported unit is now properly centered
- When a bullet hits a forest or the unit isn't able to attack an animation is played
Conclusion
I have just described the improvements in the movement and environment of my video game. I am striving to create a fun strategic experience and would be grateful for any feedback.
Demo
Download BattleForge 0.4 here: BattleForge 0.4