Traffic implementation

This commit is contained in:
Segey Lapin
2021-11-01 14:27:27 +03:00
parent ba2444b592
commit daece19b55
9 changed files with 644 additions and 375 deletions

View File

@@ -11,104 +11,145 @@ onready var obj_names = {
var done = false
class radial_grid:
var radial_points = []
var max_r = 0.0
var grid = []
var width: int = 0
var height: int = 0
var nodes = []
func build(poly, center):
var height = center.y
max_r = 0.0
for p in range(poly.size()):
var ep1 = poly[p]
ep1.y = height
var ep2 = poly[(p + 1) % poly.size()]
ep2.y = height
var d = (ep2 - ep1).normalized()
radial_points.push_back(ep1)
var dst = ep1.distance_to(ep2)
while dst > 32:
ep1 += d * 32
radial_points.push_back(ep1)
dst -= 32
for p in range(radial_points.size()):
var ep = radial_points[p]
var dst = ep.distance_to(center)
if max_r < dst:
max_r = dst
width = radial_points.size()
height = int(max_r / 32)
grid.resize(width * height)
for p in range(width):
var start = radial_points[p]
var end = center
var step = (end - start).normalized() * (end - start).length() / float(height + 1)
var val = start
for q in range(height):
grid[p * height + q] = {"position": val, "node": null}
func get_grid_node(x, y):
return grid[x * height + y].node
func set_grid_node(x, y, node):
if !node in nodes:
nodes.push_back(node)
grid[x * height + y].node = node
func place_grid(aabb: AABB, node) -> void:
for u in range(width):
for v in range(height):
if aabb.has_point(grid[u * height + v].position):
set_grid_node(u, v, node)
func get_pos(x, y):
return grid[x * height + y].position
var side_wall: PackedScene = preload("res://objects/wall-side.scn")
var bottom_side: PackedScene = preload("res://objects/bottom-side.scn")
var bottom: PackedScene = preload("res://objects/bottom.scn")
var bottom_wheels: PackedScene = preload("res://objects/bottom-wheels.scn")
var entry: PackedScene = preload("res://objects/entry.scn")
var roof_floor: PackedScene = preload("res://objects/roof-floor.scn")
var roof_floor_range: PackedScene = preload("res://objects/roof-floor-range.scn")
var wall_internal: PackedScene = preload("res://objects/wall-internal.scn")
var window_narrow: PackedScene = preload("res://objects/window-narrow.scn")
var window_wide: PackedScene = preload("res://objects/window-wide.scn")
var wall_solid: PackedScene = preload("res://objects/wall-solid.scn")
onready var grid = radial_grid.new()
var courtyard_tile: PackedScene = preload("res://objects/courtyard-tile.scn")
var foundation_tile: PackedScene = preload("res://objects/foundation.scn")
var room_tile: PackedScene = preload("res://objects/block-room-corridoor.scn")
var tower_walls_tile: PackedScene = preload("res://objects/tower-walls.scn")
var tower_floor_tile: PackedScene = preload("res://objects/tower_floor.scn")
var stairs_tile: PackedScene = preload("res://objects/stairs.scn")
var gate_bottom_tile: PackedScene = preload("res://objects/gate_bottom.scn")
var gate_top_tile: PackedScene = preload("res://objects/gate-top.scn")
var entry_tile: PackedScene = preload("res://objects/block-room-entry.scn")
var roof_tile: PackedScene = preload("res://objects/roof.scn")
var tower_roof_tile: PackedScene = preload("res://objects/tower-roof.scn")
func debug_poly(poly):
for k in range(poly.size()):
var p1 = poly[k]
var p2 = poly[(k + 1) % poly.size()]
var l = p1.distance_to(p2)
var d = (p2 - p1).normalized()
var pt = p1
while l > 0.0:
for e in range(0, 30, 2):
var mi = MeshInstance.new()
mi.mesh = CubeMesh.new()
get_tree().root.add_child(mi)
mi.global_transform.origin = pt + Vector3(0, e, 0)
pt += d * 5.0
l -= 5.0
onready var palace_map_data = {
"courtyard_tile": courtyard_tile,
"foundation_tile": foundation_tile,
"room_tile": room_tile,
"tower_walls_tile": tower_walls_tile,
"tower_floor_tile": tower_floor_tile,
"stairs_tile": stairs_tile,
"gate_bottom_tile": gate_bottom_tile,
"gate_top_tile": gate_top_tile,
"entry_tile": entry_tile,
"roof_tile": roof_tile,
"tower_roof_tile": tower_roof_tile
}
func calc_border(poly, offt):
var height = RoadsData.get_site_avg_height(0)
var border = []
border.resize(poly.size())
for k in range(poly.size()):
var i = k - 1
if i < 0:
i += poly.size()
var p1 = poly[i]
var p2 = poly[k]
var p3 = poly[(k + 1) % poly.size()]
var p1x = Vector2(p1.x, p1.z)
var p2x = Vector2(p2.x, p2.z)
var p3x = Vector2(p2.x, p2.z)
var p4x = Vector2(p3.x, p3.z)
var n1 = (p2x - p1x).tangent().normalized()
var n2 = (p4x - p3x).tangent().normalized()
p1x -= n1 * offt
p2x -= n1 * offt
p3x -= n2 * offt
p4x -= n2 * offt
var xp = Geometry.segment_intersects_segment_2d(p1x, p2x, p3x, p4x)
if !xp:
xp = p2x.linear_interpolate(p3x, 0.5) - (n1 + n2).normalized() * offt
var tp = Vector3(xp.x, height, xp.y)
border[k] = tp
return border
#class radial_grid:
# var radial_points = []
# var max_r = 0.0
# var grid = []
# var width: int = 0
# var height: int = 0
# var nodes = []
# func build(poly, center):
# var height = center.y
# max_r = 0.0
# for p in range(poly.size()):
# var ep1 = poly[p]
# ep1.y = height
# var ep2 = poly[(p + 1) % poly.size()]
# ep2.y = height
# var d = (ep2 - ep1).normalized()
# radial_points.push_back(ep1)
# var dst = ep1.distance_to(ep2)
# while dst > 32:
# ep1 += d * 32
# radial_points.push_back(ep1)
# dst -= 32
# for p in range(radial_points.size()):
# var ep = radial_points[p]
# var dst = ep.distance_to(center)
# if max_r < dst:
# max_r = dst
# width = radial_points.size()
# height = int(max_r / 32)
# grid.resize(width * height)
# for p in range(width):
# var start = radial_points[p]
# var end = center
# var step = (end - start).normalized() * (end - start).length() / float(height + 1)
# var val = start
# for q in range(height):
# grid[p * height + q] = {"position": val, "node": null}
# func get_grid_node(x, y):
# return grid[x * height + y].node
# func set_grid_node(x, y, node):
# if !node in nodes:
# nodes.push_back(node)
# grid[x * height + y].node = node
# func place_grid(aabb: AABB, node) -> void:
# for u in range(width):
# for v in range(height):
# if aabb.has_point(grid[u * height + v].position):
# set_grid_node(u, v, node)
# func get_pos(x, y):
# return grid[x * height + y].position
# onready var grid = radial_grid.new()
#func debug_poly(poly):
# for k in range(poly.size()):
# var p1 = poly[k]
# var p2 = poly[(k + 1) % poly.size()]
# var l = p1.distance_to(p2)
# var d = (p2 - p1).normalized()
# var pt = p1
# while l > 0.0:
# for e in range(0, 30, 2):
# var mi = MeshInstance.new()
# mi.mesh = CubeMesh.new()
# get_tree().root.add_child(mi)
# mi.global_transform.origin = pt + Vector3(0, e, 0)
# pt += d * 5.0
# l -= 5.0
#
#func calc_border(poly, offt):
# var height = RoadsData.get_site_avg_height(0)
# var border = []
# border.resize(poly.size())
# for k in range(poly.size()):
# var i = k - 1
# if i < 0:
# i += poly.size()
# var p1 = poly[i]
# var p2 = poly[k]
# var p3 = poly[(k + 1) % poly.size()]
# var p1x = Vector2(p1.x, p1.z)
# var p2x = Vector2(p2.x, p2.z)
# var p3x = Vector2(p2.x, p2.z)
# var p4x = Vector2(p3.x, p3.z)
# var n1 = (p2x - p1x).tangent().normalized()
# var n2 = (p4x - p3x).tangent().normalized()
# p1x -= n1 * offt
# p2x -= n1 * offt
# p3x -= n2 * offt
# p4x -= n2 * offt
#
# var xp = Geometry.segment_intersects_segment_2d(p1x, p2x, p3x, p4x)
# if !xp:
# xp = p2x.linear_interpolate(p3x, 0.5) - (n1 + n2).normalized() * offt
# var tp = Vector3(xp.x, height, xp.y)
# border[k] = tp
# return border
#
var traffic_rnd: RandomNumberGenerator
var traffic_astar: AStar
var towns = 0
func setup_town(site):
if !RoadsData.site_is_town(site):
@@ -116,7 +157,7 @@ func setup_town(site):
return
var poly = RoadsData.get_site_polygon_3d(site)
var height = RoadsData.get_site_avg_height(site)
var border2 = calc_border(poly, 60)
var border2 = RoadsData.get_site_border(site, 60)
var aabbs = []
var poly2 = []
poly2.resize(border2.size())
@@ -127,8 +168,8 @@ func setup_town(site):
center += p
center /= poly.size()
center.y = height
grid.build(border2, center)
var radial_points = grid.radial_points
# grid.build(border2, center)
var radial_points = RoadsData.get_site_radial_points(site, 32.0, 64.0)
var max_r = 0.0
for p in range(radial_points.size()):
var ep = radial_points[p]
@@ -156,7 +197,7 @@ func setup_town(site):
var xform = Transform(Basis(), pstart).looking_at(pstart + d, Vector3.UP)
stream_obj("trailer_house", xform)
var aabb = AABB(pstart, Vector3())
aabb = aabb.grow(20)
aabb = aabb.grow(32)
aabbs.push_back(aabb)
print("placed to: ", pstart)
pstart = pstart + d * step
@@ -167,9 +208,9 @@ func setup_first_town():
assert(!done)
var poly = RoadsData.get_site_polygon_3d(0)
var height = RoadsData.get_site_avg_height(0)
var border = calc_border(poly, 32)
var border1a = calc_border(poly, 42)
var border2 = calc_border(poly, 60)
var border = RoadsData.get_site_border(0, 32)
var border1a = RoadsData.get_site_border(0, 42)
var border2 = RoadsData.get_site_border(0, 60)
var poly2 = []
poly2.resize(border2.size())
@@ -180,8 +221,8 @@ func setup_first_town():
center += p
center /= poly.size()
center.y = height
grid.build(border2, center)
var radial_points = grid.radial_points
# grid.build(border2, center)
var radial_points = RoadsData.get_site_radial_points(0, 32.0, 64.0)
var max_r = 0.0
for p in range(radial_points.size()):
var ep = radial_points[p]
@@ -227,7 +268,7 @@ func setup_first_town():
var xform = Transform(Basis(), pstart).looking_at(pstart + d, Vector3.UP)
stream_obj("trailer_house", xform)
var aabb = AABB(pstart, Vector3())
aabb = aabb.grow(20)
aabb = aabb.grow(32)
aabbs.push_back(aabb)
print("placed to: ", pstart)
pstart = pstart + d * step
@@ -235,9 +276,64 @@ func setup_first_town():
towns += 1
done = true
func setup_traffic(site):
var poly = RoadsData.get_site_polygon_3d(site)
var lp = get_tree().root
for p in range(poly.size()):
var p1 = poly[p]
var p2 = poly[(p + 1) % poly.size()]
var n = (p2 - p1).cross(Vector3.UP).normalized()
var t = (p2 - p1).normalized()
var l = p1.distance_to(p2)
var xpos = p1 + t * 8.0
var xe = 128.0
if l < xe + 16.0:
xpos = p1.linear_interpolate(p2, 0.5)
var x = xpos + n * 1.5 + Vector3.UP * 0.5
var xform = Transform(Basis(), x).looking_at(x + t * 3.0, Vector3.UP)
var c = Spatial.new()
lp.add_child(c)
c.transform = xform
c.add_to_group("spawn")
c.add_to_group("keep")
c.add_to_group("traffic_spawn")
else:
while l > xe + 16.0:
var x = xpos + n * 4.0 + Vector3.UP * 0.5
var xform = Transform(Basis(), x).looking_at(x + t * 3.0, Vector3.UP)
var c = Spatial.new()
lp.add_child(c)
c.transform = xform
c.add_to_group("spawn")
c.add_to_group("keep")
c.add_to_group("traffic_spawn")
xpos += t * xe
l -= xe
func _ready():
traffic_rnd = RandomNumberGenerator.new()
traffic_rnd.randomize()
traffic_astar = AStar.new()
for k in obj_names.keys():
Spawner.add_scene(k, obj_names[k])
for k in palace_map_data.keys():
Spawner.add_scene(k, palace_map_data[k])
var parts = {
"side_wall": side_wall,
"bottom_side": bottom_side,
"bottom": bottom,
"bottom_wheels": bottom_wheels,
"entry": entry,
"roof_floor": roof_floor,
"roof_floor_range": roof_floor_range,
"wall_internal": wall_internal,
"window_narrow": window_narrow,
"window_wide": window_wide,
"wall_solid": wall_solid
}
for k in parts.keys():
Spawner.add_scene(k, parts[k])
Traffic.add_traffic_vehicle(car)
# Called every frame. 'delta' is the elapsed time since the previous frame.
var delay = 3.0
@@ -249,7 +345,7 @@ func _process(delta):
if delay < 0:
state = 1
1:
Spawner.update_view(self, 300)
Spawner.update_view(self, 200)
var sc = get_tree().root
var viewport: = get_viewport()
if !viewport:
@@ -258,15 +354,143 @@ func _process(delta):
if !cam:
return
var cam_xform: = cam.global_transform
# building parts
call_deferred("real_spawn_child")
func stream_obj(obj: String, xform: Transform):
Spawner.place_scene(obj, xform)
func switch_to_distant_vehicle(n):
var sp = PhysicsServer.body_get_space(n.get_rid())
var l = n.get_linear_velocity()
n.set_meta("velocity", l)
n.set_meta("space", sp)
PhysicsServer.body_set_space(n.get_rid(), RID())
func switch_to_close_vehicle(n):
var sp = n.get_meta("space")
PhysicsServer.body_set_space(n.get_rid(), sp)
n.remove_meta("space")
if n.has_meta("velocity"):
n.set_linear_velocity(n.get_meta("velocity"))
n.remove_meta("velocity")
func _physics_process(delta):
var cam = get_viewport().get_camera()
if !cam:
return
match state:
1:
# convert to distant traffic here
for n in get_tree().get_nodes_in_group("traffic_vehicle"):
var p1 = cam.global_transform.origin
var p2 = n.global_transform.origin
var check_coords = cam.global_transform.xform_inv(p2)
var steer = 0.0
var x_target = Vector3()
var next_target = Vector3()
var orientation = n.global_transform
orientation.origin = Vector3()
var direction = orientation.xform(Vector3(0, 0, -1))
var good_path = false
var engine_force = n.engine_force
if !n.has_meta("curve"):
create_path(n, p2, direction * 10.0)
if n.has_meta("curve"):
var curve = n.get_meta("curve")
if curve.get_point_count() > 0:
var plength = n.get_meta("curve_length")
var offt = curve.get_closest_offset(p2)
var offt_ext = 8.0
if n.has_meta("velocity"):
offt_ext = n.get_meta("velocity").length()
offt = clamp(offt + offt_ext, 0, plength)
var p0 = curve.interpolate_baked(offt, false)
next_target = p0
if false: # p0.distance_squared_to(p2) > 16.0:
n.remove_meta("curve")
steer = 0.0
x_target = Vector3()
next_target = p2 + direction * 4.0
else:
var xt0 = n.global_transform.xform_inv(p0)
x_target = xt0
if xt0.z < 0.0:
steer = xt0.x
if steer == 0.0:
steer = -1
else:
steer = x_target.x
steer = sign(steer)
# if abs(steer) < 0.005:
# steer = 0.0
n.set_meta("x_target", x_target)
print("position: ", p2, " direction: ", direction, " next_target: ", next_target, " x_target: ", x_target, " steer: ", steer, " ! ", (next_target - p2).normalized())
else:
assert(false)
# if check_coords.z > 160 || check_coords.z < -120 || abs(check_coords.x) > 100:
# n.queue_free()
if false: # check_coords.z > 40.0 || check_coords.z < -25.0 || abs(check_coords.x) > 20.0:
if !n.has_meta("space"):
switch_to_distant_vehicle(n)
var xvel = (next_target - p2).normalized() * 6.0
n.set_meta("velocity", xvel)
var pos = n.global_transform.origin
var vel = (next_target - p2).normalized() * 6.0
if n.has_meta("velocity"):
vel = n.get_meta("velocity")
var speed = vel.length()
var stf = (next_target - pos).normalized() * speed
# stf.y = vel.y
vel = vel.linear_interpolate(stf, delta)
var target_pos = pos + vel
# vel.y = vel.y * delta
var newpos = pos.linear_interpolate(target_pos, delta)
n.set_meta("velocity", vel)
# why?
var xform = Transform(Basis(), newpos).looking_at(newpos - vel * 4.0, Vector3.UP)
n.global_transform = xform
else:
if n.has_meta("space"):
switch_to_close_vehicle(n)
var v = n.get_linear_velocity()
n.set_meta("velocity", v)
var l = v.length()
# if abs(steer) > 3.0 || !good_path:
# # vehicle totally lost
# n.brake = 60000
# n.engine_force = 0
# elif abs(steer) > 2.0:
# # vehicle lost
# n.engine_force = 0
if next_target.length_squared() == 0:
engine_force = 0.0
steer = 0.0
else:
if abs(steer) > 3.0:
engine_force *= 0.9
engine_force = clamp(engine_force, 2500.0, max(2500, engine_force))
else:
if abs(steer) > 4.0 && l > 5.0:
engine_force = engine_force * 0.9996
if l > 7.0:
engine_force = engine_force * 0.9996
elif l < 1.1:
engine_force = clamp(engine_force * 1.004, 6000, 8000)
elif l < 2.5:
engine_force = clamp(engine_force * 1.002, 5000, 7000)
elif l < 5.0:
engine_force = clamp(engine_force * 1.001, 4000, 6000)
elif l < 6.0:
engine_force = clamp(engine_force * 1.001, 3000, 5000)
# engine_force = 0.0
engine_force = clamp(engine_force, 0, 8500)
print("engine_force: ", engine_force)
n.engine_force = engine_force
n.brake = 0
# n.steering = clamp(steer, -1, 1)
var base_steering = n.steering
var main_steering = base_steering * 0.95 + steer * 0.05
n.steering = clamp(main_steering, -1, 1)
n.set_meta("steering", n.steering)
var space_state = get_viewport().get_world().direct_space_state
# probaly should not be here
for n in get_tree().get_nodes_in_group("spawn"):
@@ -289,8 +513,114 @@ func _physics_process(delta):
elif n.is_in_group("female"):
characters.replace_character(n, "female", ["cmdq", "marker", "hurtboxes", "student"])
elif n.is_in_group("car"):
var c = car.instance()
var p = get_tree().root
p.add_child(c)
c.global_transform = n.global_transform
n.queue_free()
var p1 = cam.global_transform.origin
var p2 = n.global_transform.origin
if p1.distance_squared_to(p2) < 5000.0:
var c = car.instance()
c.add_to_group("saved_vehicle")
var p = get_tree().root
p.add_child(c)
c.global_transform = n.global_transform
n.queue_free()
# elif n.is_in_group("traffic_spawn"):
# var p1 = cam.global_transform.origin
# var p2 = n.global_transform.origin
# if !n.has_meta("cooldown") && p1.distance_squared_to(p2) < 10000.0:
# var c = car.instance()
# c.add_to_group("traffic_vehicle")
# var p = get_tree().root
# p.add_child(c)
# c.global_transform = n.global_transform
# c.parked = false
# c.mode = c.MODE_RIGID
# c.engine_force = 2500
# c.steering = 0
# var xf = c.global_transform
# xf.origin = Vector3()
# var vel = xf.xform(Vector3(0, 0, -10))
# c.set_linear_velocity(vel)
# var sp = PhysicsServer.body_get_space(c.get_rid())
# c.set_meta("space", sp)
# PhysicsServer.body_set_space(c.get_rid(), RID())
# n.set_meta("cooldown", 2.0 + randi() % 8)
# # create_path(c, p2, vel)
# elif n.has_meta("cooldown"):
# var cd = n.get_meta("cooldown")
# cd -= delta
# if cd < 0:
# n.remove_meta("cooldown")
func get_curve_closest(curve, p2):
var test_offt = curve.get_closest_offset(p2)
var testp = curve.interpolate_baked(test_offt, false)
return testp
func test_curve(curve, p2):
var testp = get_curve_closest(curve, p2)
return testp.distance_squared_to(p2) < 16.0
func create_path(c, p2, vel):
c.set_meta("velocity", vel)
print("create_path: velocity: ", vel)
var rangle = traffic_rnd.randf() * PI * 2.0
var randa = 500.0 + traffic_rnd.randf() * 500.0
var xt = cos(rangle) * randa
var yt = cos(rangle) * randa
var rv = Vector3(xt, 0, yt)
var target = RoadsData.get_closest_point(p2 + rv, false)
var cur = RoadsData.get_closest_point(p2, false)
while cur == target:
rangle = traffic_rnd.randf() * PI * 2.0
randa = 500.0 + traffic_rnd.randf() * 500.0
xt = cos(rangle) * randa
yt = sin(rangle) * randa
rv = Vector3(xt, 0, yt)
target = RoadsData.get_closest_point(p2 + rv, false)
c.set_meta("target", target)
var path = RoadsData.get_point_path(cur, target);
assert(cur != target)
assert(path.size() > 0)
var curve = Curve3D.new()
for e in range(path.size() - 1):
var pt1 = path[e]
var pt2 = path[e + 1]
var nt = (pt2 - pt1).cross(Vector3.UP).normalized()
var d = (pt2 - pt1).normalized()
var l = pt1.distance_to(pt2)
while l > 16.0:
pt1 += d * 8.0
curve.add_point(pt1 + nt * 3.0 + Vector3.UP * 0.5)
l -= 8.0
if (!test_curve(curve, p2)):
var testp = get_curve_closest(curve, p2)
var e = p2 + (testp - p2).normalized() * 2.0
var nt = (testp - p2).cross(Vector3.UP).normalized()
curve.add_point(e + nt * 3.0 + Vector3.UP * 0.5, Vector3(), Vector3(), 0)
assert(test_curve(curve, p2))
c.set_meta("curve", curve)
c.set_meta("curve_length", curve.get_baked_length())
# buildings
var spawn = []
func spawn_child(n: String, xform: Transform) -> void:
var sp = {"node": n, "xform": xform}
spawn.push_back(sp)
func real_spawn_child():
var count = 0
while spawn.size() > 0:
var e = spawn.pop_front()
Spawner.place_scene(e.node, e.xform)
count += 1
func update_node_position(n):
var space_state = get_viewport().get_world().direct_space_state
var where = n.get_global_transform().origin
var from = where
var to = where
from.y -= 8.0
to.y += 8.0
var result = space_state.intersect_ray(from, to)
if result.empty() || !result.has("collider"):
return
else:
n.global_transform.origin = result.position