Sunday Update: graphic and bots improvements, ConfigFile, menu settings

This commit is contained in:
Lurkars
2019-07-28 13:32:28 +02:00
commit c95bb8fb55
445 changed files with 186278 additions and 0 deletions
+36
View File
@@ -0,0 +1,36 @@
extends Node
var random_number_generator:RandomNumberGenerator = RandomNumberGenerator.new()
func _ready():
random_number_generator.randomize()
func randf():
return random_number_generator.randf()
func randf_range (from:float, to:float ):
return random_number_generator.randf_range(from,to)
func randfn (mean:float=0.0, deviation:float=1.0 ):
return random_number_generator.randfn(mean, deviation)
func randi():
return random_number_generator.randi()
func randi_range ( from:int, to:int ):
return random_number_generator.randi_range( from, to)
func clear_node(node:Node):
for idx in range(node.get_child_count()):
node.remove_child(node.get_child(0))
func curve_get_last_point(curve:Curve3D):
return curve.get_point_position(curve.get_point_count() - 1)
+28
View File
@@ -0,0 +1,28 @@
extends Node
const FILE_PATH = "user://local_storage"
const RESOLUTIONS = [Vector2(1920,1080),Vector2(1600,900),Vector2(1366,758),Vector2(1280,720),Vector2(1136,640),Vector2(1024,576)]
const CONTROL_ACTIONS = ["controls_thrust", "controls_break", "controls_add_road", "controls_next_road_type", "controls_prev_road_type", "controls_next_road_variant", "controls_prev_road_variant", "controls_reset", "controls_menu"]
const INPUT_UI_MAPPING = {"ui_accept" : "controls_add_road", "ui_select" : "controls_add_road", "ui_up" : "controls_next_road_variant", "ui_down" : "controls_prev_road_variant", "ui_left" : "controls_prev_road_type", "ui_right" : "controls_next_road_type"}
var config_file:ConfigFile = ConfigFile.new()
func _ready():
config_file.load(FILE_PATH)
func save():
config_file.save(FILE_PATH)
func get_value(section:String, key:String, default = null):
return config_file.get_value(section,key,default)
func set_value(section:String, key:String, value):
config_file.set_value(section,key,value)
+62
View File
@@ -0,0 +1,62 @@
extends Node
const FILE_PATH = "user://local_storage"
func _ready():
apply_settings()
func apply_settings():
apply_locale()
apply_game_server()
apply_resolution()
apply_controls()
func apply_locale():
TranslationServer.set_locale(config.get_value("system","locale","en"))
func apply_game_server():
var server_addr = config.get_value("game_server", "server_addr")
if server_addr != null && not server_addr.empty():
game_server.set_server_addr(server_addr)
var api_addr = config.get_value("game_server","api_addr")
if api_addr != null && not api_addr.empty():
game_server.set_api_addr(api_addr)
func apply_resolution():
var view_port = get_tree().get_root()
OS.set_window_fullscreen(config.get_value("graphics","fullscreen", true))
var resolution = config.get_value("graphics","resolution",config.RESOLUTIONS[0])
if OS.is_window_fullscreen():
var base_size = Vector2(1920, 1080)
var scale= base_size.x / resolution.x
get_tree().set_screen_stretch(SceneTree.STRETCH_MODE_2D,SceneTree.STRETCH_ASPECT_EXPAND,base_size,scale)
else:
OS.set_window_size(resolution)
get_tree().set_screen_stretch(SceneTree.STRETCH_MODE_VIEWPORT,SceneTree.STRETCH_ASPECT_IGNORE,OS.get_window_size(),1)
func apply_controls():
InputMap.load_from_globals()
var control_map = config.get_value("controls","mapping",{})
for action in InputMap.get_actions():
if control_map.has(action):
for event in InputMap.get_action_list(action):
if event is InputEventKey && control_map[action].has("key"):
InputMap.action_erase_event(action, event)
event.set_scancode(OS.find_scancode_from_string(control_map[action]["key"]))
InputMap.action_add_event(action,event)
elif event is InputEventJoypadButton && control_map[action].has("joypad"):
InputMap.action_erase_event(action, event)
event.set_button_index(control_map[action]["joypad"])
InputMap.action_add_event(action,event)
for ui_mapping in config.INPUT_UI_MAPPING:
for event in InputMap.get_action_list(config.INPUT_UI_MAPPING[ui_mapping]):
InputMap.action_add_event(ui_mapping, event)
+53
View File
@@ -0,0 +1,53 @@
extends Spatial
class_name Game
var players:Array
var route:Route
var first:Player
var last:Player
const REMOVE_LAST = 2
func _ready():
route = get_node("route")
find_node("sun").set_visible(config.get_value("graphics","light", false))
if find_node("sun").is_visible_in_tree():
find_node("sun").set_shadow(config.get_value("graphics","shadows", false))
if is_network_master():
route.rpc("add_road",roads_factory.START, -1)
func _physics_process(delta):
if is_network_master():
set_player_order()
check_autotrack()
func set_player_order():
players = get_node("players").get_children()
players.sort_custom(PlayerSorter,"sort")
if players.size() > 0 && players[0] != first:
new_first(players[0])
if players.size() > 0 && players[players.size()-1] != last:
last = players[players.size()-1]
func new_first(player):
if first != null:
first.rpc("set_first",false)
first = player
first.rpc("set_first",true)
func check_autotrack():
if first != null:
if first.position.x != -1 && route.get_last_road() != null:
if first.position.x == route.get_last_road().get_index():
route.rpc("add_road", roads_factory.STRAIGHT, -1)
class PlayerSorter:
static func sort(a, b):
return a.position.x > b.position.x || a.position.x == b.position.x && a.position.y > b.position.y
+152
View File
@@ -0,0 +1,152 @@
extends Node
const MAX_PEERS = 4
const LOBBY_READY_WAIT_TIME = 3
var Game = preload("res://scenes/game/Game.tscn")
var Player = preload("res://scenes/player/Player.tscn")
var HumanPlayer = preload("res://scenes/player/HumanPlayer.tscn")
var BotPlayer = preload("res://scenes/player/BotPlayer.tscn")
var game:Game
var players = {}
var game_name = ""
var bots:bool = false
var game_running:bool = false
signal players_changed(players)
signal game_ready(ready)
signal game_started()
signal game_ended()
remote func set_player(id, new_name:String = " ", new_color:Color = Color.black, new_ready:bool = false):
players[id] = {"name" : new_name, "color" : new_color, "ready" : new_ready, "prepared" : false}
emit_signal("players_changed", players)
if get_tree().is_network_server():
var all_ready = true
for p_id in players:
rpc_id(id, "set_player", p_id, players[p_id].name, players[p_id].color, players[p_id].ready)
rpc_id(p_id, "set_player", id, new_name, new_color, new_ready)
all_ready = all_ready && players[p_id].ready
rpc("game_ready", all_ready)
func update_player(new_name:String = " ", new_color:Color = Color.black, new_ready:bool = false):
if get_tree().is_network_server():
set_player(get_tree().get_network_unique_id(), new_name, new_color, new_ready)
else:
rpc("set_player",get_tree().get_network_unique_id(), new_name, new_color, new_ready)
remotesync func remove_player(id):
players.erase(id)
if game != null:
var game_players = game.get_node("players")
if game_players.has_node(str(id)):
game_players.remove_child(game_players.get_node(str(id)))
emit_signal("players_changed", players)
remotesync func game_ready(all_ready:bool):
if get_tree().is_network_server():
if all_ready:
game_running = true
else:
game_running = false
emit_signal("game_ready", all_ready)
remotesync func prepare_game():
get_tree().set_pause(true)
game = Game.instance()
get_tree().get_root().add_child(game)
get_tree().get_root().get_node("main_menu").hide()
for p_id in players:
var controls
var player = players[p_id]
var player_scene = Player.instance()
player_scene.set_network_master(p_id)
player_scene.set_name(str(p_id))
game.get_node("players").add_child(player_scene)
player_scene.set_player_name(player.name)
player_scene.set_player_color(player.color)
if p_id == get_tree().get_network_unique_id():
controls = HumanPlayer.instance()
controls.set_name("HumanControl_" + str(p_id))
game.add_child(controls)
controls.set_player(player_scene.get_path())
controls.set_network_master(p_id)
player_scene.set_start(player_scene.get_index())
if bots:
for index in range(MAX_PEERS-players.size()):
var bot_index = players.size() + index
var player_scene = Player.instance()
player_scene.set_name("bot_player" + str(bot_index))
game.get_node("players").add_child(player_scene)
player_scene.set_player_name("Bot " + str(bot_index))
player_scene.set_player_color(Color(randf(),randf(),randf()))
player_scene.add_to_group("bots")
if get_tree().is_network_server():
var bot = BotPlayer.instance()
bot.set_name("bot" + str(bot_index))
game.add_child(bot)
bot.set_player(player_scene.get_path())
bot.set_network_master(get_tree().get_network_unique_id())
player_scene.set_start(bot_index)
if players.has(get_tree().get_network_unique_id()):
rpc_id(1, "player_prepared", get_tree().get_network_unique_id())
if get_tree().is_network_server():
if players.has(get_tree().get_network_unique_id()):
player_prepared(get_tree().get_network_unique_id())
else:
rpc_id(1, "player_prepared", get_tree().get_network_unique_id())
remotesync func player_prepared(id):
if get_tree().is_network_server():
players[id].prepared = true
var all_prepared = true
for p_id in players:
all_prepared = all_prepared && players[p_id].prepared
if all_prepared:
rpc("post_start_game")
remotesync func post_start_game():
get_tree().set_pause(false)
emit_signal("game_started")
remotesync func set_bots(has_bots:bool):
bots = has_bots
func quit_game():
if game != null:
game.queue_free()
game = null
players.clear()
if get_tree().get_root().has_node("multiplayer_menu"):
get_tree().get_root().get_node("multiplayer_menu").show()
get_tree().get_root().get_node("main_menu").hide()
elif get_tree().get_root().has_node("main_menu"):
get_tree().get_root().get_node("main_menu").show()
game_running = false
bots = false
game_name = ""
emit_signal("game_ended")
+51
View File
@@ -0,0 +1,51 @@
extends Spatial
class_name Route
signal road_added(road)
signal road_removed(road)
func get_last_road():
if get_child_count() > 0:
return get_child(get_child_count() - 1)
else:
return null
func get_road(road_index):
if get_child_count() > road_index:
return get_child(road_index)
else:
return null
remotesync func add_road(type, creator):
var transform = get_global_transform()
var last_road = get_last_road()
if last_road != null:
transform = last_road.get_global_transform();
var curve = last_road.get_curve()
transform = transform.translated(curve.get_point_position(curve.get_point_count() - 1))
if last_road.get_end_rotation().length() != 0:
transform.basis = transform.basis.rotated(last_road.get_end_rotation().normalized(), last_road.get_end_rotation().length())
var new_road = roads_factory.get_road_instance(type)
new_road.set_global_transform(transform)
new_road.set_preview(false)
new_road.set_creator(creator)
if creator > 0:
var player = gamestate.game.get_node(str(creator))
if player != null:
new_road.set_color(player.get_player_color())
add_child(new_road)
emit_signal("road_added", new_road)
remotesync func remove_road(road_index):
var road = get_child(road_index)
remove_child(road)
emit_signal("road_removed", road)
+33
View File
@@ -0,0 +1,33 @@
extends Control
var LobbyMenu = preload("res://scenes/menus/LobbyMenu.tscn")
func _ready():
find_node("bots").set_pressed(config.get_value("game","bots", true))
func _draw():
find_node("host").grab_focus()
func _on_host_pressed():
var port = find_node("port").get_value()
var bots = find_node("bots").is_pressed()
var err = server.host_game(int(port), bots)
if err == OK:
var lobby_menu = LobbyMenu.instance()
get_tree().get_root().add_child(lobby_menu)
gamestate.set_player(get_tree().get_network_unique_id())
queue_free()
else:
_on_back_pressed()
get_tree().get_root().get_node("multiplayer_menu").show_error_dialog(tr("ERROR_SERVER_CREATION"))
func _on_back_pressed():
queue_free()
get_tree().get_root().get_node("multiplayer_menu").show()
+16
View File
@@ -0,0 +1,16 @@
extends Control
func _draw():
find_node("join").grab_focus()
func _on_join_pressed():
var ip = find_node("ip").text
var port = find_node("port").get_value()
client.join_game(ip, int(port))
queue_free()
func _on_back_pressed():
queue_free()
+17
View File
@@ -0,0 +1,17 @@
extends Control
func _draw():
find_node("resume").grab_focus()
func _on_resume_pressed():
hide()
func _on_settings_pressed():
pass
func _on_end_pressed():
gamestate.quit_game()
+101
View File
@@ -0,0 +1,101 @@
extends Control
onready var countdown_timer = get_node("countdown_timer")
onready var player_settings = find_node("player_settings")
onready var player_list = find_node("players")
func _ready():
if get_tree().get_root().has_node("multiplayer_menu"):
get_tree().get_root().get_node("multiplayer_menu").hide()
if get_tree().get_root().has_node("main_menu"):
get_tree().get_root().get_node("main_menu").hide()
get_node("menu/back").connect("pressed",self,"_on_back_pressed")
gamestate.connect("players_changed", self, "_players_changed")
gamestate.connect("game_ready", self, "_game_ready")
gamestate.connect("game_started", self, "_game_started")
client.connect("server_disconnected", self, "_server_disconnected")
player_settings.get_name_node().connect("text_changed",self,"_on_name_text_changed")
player_settings.get_color_node().connect("color_changed",self,"_on_color_color_changed")
player_settings.get_color_node().connect("draw",self,"_on_player_changed")
countdown_timer.set_wait_time(server.LOBBY_READY_WAIT_TIME)
if gamestate.game_name:
find_node("server_name").set_text(gamestate.game_name)
find_node("server_name").set_tooltip(gamestate.game_name)
func _draw():
find_node("ready").grab_focus()
func _physics_process(delta):
if not countdown_timer.is_stopped():
get_node("countdown").text = str(int(countdown_timer.get_time_left()) + 1)
func _players_changed(players):
player_list.clear()
for p_id in players:
var player = players[p_id]
if p_id == get_tree().get_network_unique_id():
player_list.add_item(player.name + " (You)")
else:
player_list.add_item(player.name)
player_list.set_item_custom_bg_color(player_list.get_item_count()-1, player.color)
if player.ready:
player_list.set_item_icon(player_list.get_item_count()-1, player_list.get_node("ready_icon").get_button_icon())
else:
player_list.set_item_icon(player_list.get_item_count()-1, player_list.get_node("not_ready_icon").get_button_icon())
find_node("server_bots").set_pressed(gamestate.bots)
func _game_ready(all_ready):
if all_ready:
get_node("countdown").show()
countdown_timer.start()
else:
countdown_timer.stop()
get_node("countdown").hide()
func _game_started():
queue_free()
func _on_name_text_changed(new_text):
_on_player_changed()
func _on_color_color_changed(color):
_on_player_changed()
func _on_ready_toggled(button_pressed):
_on_player_changed()
player_settings.get_name_node().set_editable(not button_pressed)
player_settings.get_color_node().set_disabled(button_pressed)
func _on_player_changed():
var name = player_settings.get_name_node().text
var color = player_settings.get_color_node().color
var ready = find_node("ready").pressed
gamestate.update_player(name,color,ready)
func _on_back_pressed():
gamestate.quit_game()
if get_tree().get_root().has_node("multiplayer_menu"):
get_tree().get_root().get_node("multiplayer_menu").show()
get_tree().get_root().get_node("main_menu").hide()
elif get_tree().get_root().has_node("main_menu"):
get_tree().get_root().get_node("main_menu").show()
queue_free()
func _server_disconnected():
_on_back_pressed()
+24
View File
@@ -0,0 +1,24 @@
extends Control
onready var player_settings = find_node("player_settings")
func _ready():
find_node("bots").set_pressed(config.get_value("game","bots", true))
func _draw():
find_node("start").grab_focus()
func _on_start_pressed():
var name = player_settings.get_name_node().text
var color = player_settings.get_color_node().color
var bots = find_node("bots").is_pressed()
queue_free()
server.local_game(name,color,bots)
func _on_back_pressed():
queue_free()
get_tree().get_root().get_node("main_menu").show()
+45
View File
@@ -0,0 +1,45 @@
extends Control
var MultiplayerMenu = preload("res://scenes/menus/MultiplayerMenu.tscn")
var LocalGameMenu = preload("res://scenes/menus/LocalGameMenu.tscn")
var SettingsMenu = preload("res://scenes/menus/SettingsMenu.tscn")
func _ready():
gamestate.connect("server_disconnected", self, "_server_disconnected")
func _draw():
find_node("multiplayer").grab_focus()
func _on_multiplayer_pressed():
var multiplayer_menu = MultiplayerMenu.instance()
get_tree().get_root().add_child(multiplayer_menu)
hide()
func _on_practice_pressed():
var local_game_menu = LocalGameMenu.instance()
get_tree().get_root().add_child(local_game_menu)
hide()
func _on_settings_pressed():
var settings_menu = SettingsMenu.instance()
get_tree().get_root().add_child(settings_menu)
hide()
func _on_quit_pressed():
get_tree().quit()
func _server_disconnected():
show_error_dialog(tr("SERVER_DISCONNECTED"))
func show_error_dialog(text:String):
var dialog = get_node("error_dialog")
dialog.set_text(text)
dialog.popup_centered()
+46
View File
@@ -0,0 +1,46 @@
extends Control
func _ready():
var player_name = config.get_value("game","player_name", false)
var game_title = "New Game"
if player_name:
game_title += " by " + player_name
find_node("name").set_text(game_title)
find_node("bots").set_pressed(config.get_value("game","bots", true))
func _draw():
find_node("create").grab_focus()
func _on_create_pressed():
var req = game_server.http()
req.connect_http(self,"_on_game_created")
var server_name = find_node("name").text
var bots = 0
if find_node("bots").is_pressed():
bots = 1
req.post_request('client/game/create', to_json({'name' : server_name, 'bots' : bots}))
func _on_game_created(result, response_code, headers, body):
if result == OK && response_code == HTTPClient.RESPONSE_OK:
var json = JSON.parse(body.get_string_from_utf8())
gamestate.game_name = json.result['name']
client.join_game(game_server.get_server_addr(), int(json.result['port']))
else:
get_tree().get_root().get_node("multiplayer_menu").show_error_dialog(tr("ERROR_GAME_CREATION"))
queue_free()
func _on_name_text_changed(new_text):
if new_text:
find_node("create").set_disabled(false)
else:
find_node("create").set_disabled(true)
func _on_back_pressed():
queue_free()
get_tree().get_root().get_node("multiplayer_menu").show()
+141
View File
@@ -0,0 +1,141 @@
extends Control
var ServerCreateGameMenu = preload("res://scenes/menus/ServerCreateGameMenu.tscn")
var LobbyMenu = preload("res://scenes/menus/LobbyMenu.tscn")
var DirectHostMenu = preload("res://scenes/menus/DirectHostMenu.tscn")
var DirectJoinMenu = preload("res://scenes/menus/DirectJoinMenu.tscn")
onready var games_list = get_node("menu/games")
var games = []
var selected_game = {}
func _ready():
get_node("menu/back").connect("pressed",self,"_on_back_pressed")
client.connect("connection_succeeded", self, "_connection_succeeded")
client.connect("connection_failed", self, "_connection_failed")
client.connect("server_disconnected", self, "_server_disconnected")
func _draw():
find_node("refresh").grab_focus()
func _on_multiplayer_menu_draw():
get_games(find_node("open").is_pressed())
get_node("refresh_timer").start()
func _on_multiplayer_menu_hide():
get_node("refresh_timer").stop()
func _on_back_pressed():
queue_free()
get_tree().get_root().get_node("main_menu").show()
func _on_direct_host_pressed():
var direct_host_menu = DirectHostMenu.instance()
get_tree().get_root().add_child(direct_host_menu)
get_tree().get_root().get_node("main_menu").hide()
func _on_direct_join_pressed():
var direct_join_menu = DirectJoinMenu.instance()
get_tree().get_root().add_child(direct_join_menu)
get_tree().get_root().get_node("main_menu").hide()
func _on_open_toggled(button_pressed):
get_games(button_pressed)
func _on_refresh_pressed():
if get_node("refresh_timer").is_stopped():
get_node("refresh_timer").start()
get_games(find_node("open").is_pressed())
func _on_refresh_timer_timeout():
get_games(find_node("open").is_pressed())
func _server_disconnected():
show_error_dialog(tr("SERVER_DISCONNECTED"))
func show_error_dialog(text:String):
var dialog = get_node("error_dialog")
dialog.set_text(text)
dialog.popup_centered()
func get_games(only_open:bool):
var req = game_server.http()
req.connect_http(self,"_on_get_games")
if only_open:
req.get_request('client/games?open')
else:
req.get_request('client/games')
func _on_get_games(result, response_code, headers, body):
if result == OK && response_code == HTTPClient.RESPONSE_OK:
find_node("create").set_disabled(false)
find_node("open").set_disabled(false)
var json = JSON.parse(body.get_string_from_utf8())
games_list.clear()
games = json.result
for game in games:
var name = game.name
name += " ("
name += str(game.player_count)
name += "/4)"
if game.bots:
name += " [with Bots]"
games_list.add_item(name)
if game.running:
games_list.set_item_icon(games_list.get_item_count()-1, games_list.get_node("running_icon").get_button_icon())
elif game.has('private') && game.private:
games_list.set_item_icon(games_list.get_item_count()-1, games_list.get_node("private_icon").get_button_icon())
else:
games_list.set_item_icon(games_list.get_item_count()-1, games_list.get_node("open_icon").get_button_icon())
else:
find_node("create").set_disabled(true)
find_node("join").set_disabled(true)
find_node("open").set_disabled(true)
show_error_dialog(tr("SERVER_NO_CONNECTION"))
get_node("refresh_timer").stop()
func _on_create_pressed():
var server_create_game_menu = ServerCreateGameMenu.instance()
get_tree().get_root().add_child(server_create_game_menu)
get_tree().get_root().get_node("main_menu").hide()
func _on_join_pressed():
client.join_game(game_server.get_server_addr(), int(selected_game['port']))
func _connection_succeeded():
var lobby_menu = LobbyMenu.instance()
if selected_game && selected_game.has('name'):
gamestate.game_name = selected_game.name
get_tree().get_root().add_child(lobby_menu)
get_node("refresh_timer").stop()
hide()
func _connection_failed():
show_error_dialog(tr("CONNECTION_FAILED"))
func _on_games_item_selected(index):
selected_game = games[index]
find_node("join").set_disabled(false)
func _on_games_nothing_selected():
find_node("join").set_disabled(true)
+124
View File
@@ -0,0 +1,124 @@
extends Control
onready var grid = find_node("grid")
onready var key_dialog = get_node("key_dialog")
const INPUT_TYPE_KEY = 0
const INPUT_TYPE_JOYPAD = 1
var last_action:String
var last_event:InputEvent
var new_inputs = {}
func _ready():
init_mapping()
func init_mapping():
new_inputs = {}
for action in config.CONTROL_ACTIONS:
var action_label = Label.new()
action_label.set_name(action + "_label")
action_label.set_text(action)
grid.add_child(action_label)
var key_action_button = Button.new()
key_action_button.set_h_size_flags(SIZE_SHRINK_CENTER)
key_action_button.set_flat(true)
key_action_button.set_meta("action",action)
key_action_button.set_button_icon(get_node("icons/key").get_button_icon())
var joypad_action_button = Button.new()
joypad_action_button.set_h_size_flags(SIZE_SHRINK_CENTER)
joypad_action_button.set_flat(true)
joypad_action_button.set_meta("action",action)
for event in InputMap.get_action_list(action):
if event is InputEventKey:
key_action_button.set_text(event.as_text())
key_action_button.set_tooltip(event.as_text())
elif event is InputEventJoypadButton:
joypad_action_button.set_tooltip(str(event.button_index))
if has_node("icons/joypad/" + str(event.button_index)):
joypad_action_button.set_button_icon(get_node("icons/joypad/" + str(event.button_index)).get_button_icon())
else:
joypad_action_button.set_button_icon(get_node("icons/joypad/other").get_button_icon())
joypad_action_button.set_text(str(event.button_index))
grid.add_child(key_action_button)
key_action_button.connect("pressed",self,"_on_button_pressed",[key_action_button, INPUT_TYPE_KEY])
grid.add_child(joypad_action_button)
joypad_action_button.connect("pressed",self,"_on_button_pressed",[joypad_action_button, INPUT_TYPE_JOYPAD])
func _unhandled_input(event):
if key_dialog.is_visible_in_tree():
var action_button = key_dialog.find_node("action_button")
var check_usage = false
if key_dialog.get_meta("type") == INPUT_TYPE_KEY && event is InputEventKey:
check_usage = true
last_event = event
action_button.set_button_icon(get_node("icons/key").get_button_icon())
action_button.set_text(event.as_text())
action_button.set_tooltip(event.as_text())
elif key_dialog.get_meta("type") == INPUT_TYPE_JOYPAD && event is InputEventJoypadButton:
check_usage = true
last_event = event
action_button.set_tooltip(str(event.button_index))
if has_node("icons/joypad/" + str(event.button_index)):
action_button.set_text("")
action_button.set_button_icon(get_node("icons/joypad/" + str(event.button_index)).get_button_icon())
else:
action_button.set_button_icon(get_node("icons/joypad/other").get_button_icon())
action_button.set_text(str(event.button_index))
if check_usage:
var has_event = ""
for action in config.CONTROL_ACTIONS:
if InputMap.event_is_action(event, action):
has_event = action
if not has_event == "" && not has_event == last_action:
key_dialog.set_text(tr("KEY_ALREADY_TAKEN") + '\n\'' + tr(has_event) + '\'')
key_dialog.get_ok().set_disabled(true)
else:
key_dialog.set_text(tr("PRESS_KEY"))
key_dialog.get_ok().set_disabled(false)
func _on_button_pressed(button, type):
last_action = button.get_meta("action")
last_event = null
var action_button = key_dialog.find_node("action_button")
action_button.set_text("")
action_button.set_button_icon(null)
key_dialog.set_text(tr("PRESS_KEY"))
key_dialog.set_meta("type", type)
key_dialog.connect("confirmed",self,"_on_dialog_confirmed",[button])
key_dialog.get_ok().set_disabled(true)
key_dialog.get_label().set_align(HALIGN_CENTER)
key_dialog.popup_centered()
func _on_dialog_confirmed(button):
if not new_inputs.has(last_action):
new_inputs[last_action] = {}
match key_dialog.get_meta("type"):
INPUT_TYPE_KEY:
if last_event is InputEventKey:
new_inputs[last_action]["key"] = OS.get_scancode_string(last_event.scancode)
button.set_text(last_event.as_text())
button.set_tooltip(last_event.as_text())
INPUT_TYPE_JOYPAD:
if last_event is InputEventJoypadButton:
new_inputs[last_action]["joypad"] = last_event.button_index
button.set_tooltip(str(last_event.button_index))
if has_node("icons/joypad/" + str(last_event.button_index)):
button.set_button_icon(get_node("icons/joypad/" + str(last_event.button_index)).get_button_icon())
else:
button.set_button_icon(get_node("icons/joypad/other").get_button_icon())
button.set_text(str(last_event.button_index))
+116
View File
@@ -0,0 +1,116 @@
extends Control
onready var player_settings = find_node("settings_player")
onready var game_tab = find_node("game")
onready var controls_tab = find_node("controls")
onready var graphics_tab = find_node("graphics")
onready var system_tab = find_node("system")
var locale
func _ready():
get_node("menu/back").connect("pressed",self,"_on_back_pressed")
# game
find_node("bots").set_pressed(config.get_value("game","bots", true))
# graphics
find_node("fullscreen").set_pressed(config.get_value("graphics","fullscreen", true))
find_node("light").set_pressed(config.get_value("graphics","light", false))
find_node("shadows").set_pressed(config.get_value("graphics","shadows", false))
find_node("shadows").set_disabled(not find_node("light").is_pressed())
for resolution in config.RESOLUTIONS:
find_node("resolution").add_item(str(resolution.x) + " * " + str(resolution.y))
find_node("resolution").select(config.RESOLUTIONS.find(config.get_value("graphics","resolution", config.RESOLUTIONS[0])))
# system
find_node("server_addr").set_text(game_server.get_server_addr())
find_node("api_addr").set_text(game_server.get_api_addr())
_init_locales()
func _draw():
game_tab.grab_focus()
func _on_back_pressed():
queue_free()
get_tree().get_root().get_node("main_menu").show()
func _on_locales_item_selected(index):
match index:
0:
locale = "en"
1:
locale = "de"
_:
locale = "en"
TranslationServer.set_locale(locale)
game_tab.set_name(tr("GAME"))
controls_tab.set_name(tr("CONTROLS"))
graphics_tab.set_name(tr("GRAPHICS"))
system_tab.set_name(tr("SYSTEM"))
func _init_locales():
var locales = find_node("locales")
locales.clear()
locales.add_item(tr("LOCALE_EN"))
locales.add_item(tr("LOCALE_DE"))
locale = config.get_value("system","locale","en")
match locale:
"en":
locales.select(0)
_on_locales_item_selected(0)
"de":
locales.select(1)
_on_locales_item_selected(1)
func _on_locales_tree_exiting():
config_apply.apply_locale()
func _on_save_pressed():
_on_apply_pressed()
_on_back_pressed()
func _on_apply_pressed():
# game
config.set_value("game","player_name",player_settings.get_name_node().get_text())
config.set_value("game","player_color",player_settings.get_color_node().color)
config.set_value("game","bots",find_node("bots").is_pressed())
# graphics
config.set_value("graphics","resolution",config.RESOLUTIONS[find_node("resolution").get_selected()])
config.set_value("graphics","fullscreen",find_node("fullscreen").is_pressed())
config.set_value("graphics","light",find_node("light").is_pressed())
config.set_value("graphics","shadows",find_node("shadows").is_pressed())
# controls
config.set_value("controls","mapping",find_node("settings_controls").new_inputs)
# system
config.set_value("system","locale",locale)
var server_addr = find_node("server_addr").get_text()
if server_addr.empty():
server_addr = game_server.SERVER_ADDR
config.set_value("system","server_addr",server_addr)
var api_addr = find_node("api_addr").get_text()
if api_addr.empty():
api_addr = game_server.API_ADDR
config.set_value("system","api_addr",api_addr)
config.save()
config_apply.apply_settings()
func _on_light_toggled(button_pressed):
find_node("shadows").set_disabled(not button_pressed)
+14
View File
@@ -0,0 +1,14 @@
extends Control
func _ready():
get_name_node().set_text(config.get_value("game","player_name", "Player"))
get_color_node().set_pick_color(config.get_value("game","player_color", Color.black))
func get_name_node():
return find_node("name")
func get_color_node():
return find_node("color")
+44
View File
@@ -0,0 +1,44 @@
extends Node
signal connection_failed()
signal connection_succeeded()
signal server_disconnected()
func join_game(ip, port:int):
get_tree().connect("connected_to_server", self, "_connected_ok")
get_tree().connect("connection_failed", self, "_connected_fail")
get_tree().connect("server_disconnected", self, "_server_disconnected")
gamestate.connect("game_ended",self,"_game_ended")
var host = NetworkedMultiplayerENet.new()
host.create_client(ip, port)
get_tree().set_network_peer(host)
func _connected_ok():
gamestate.rpc("set_player", get_tree().get_network_unique_id())
emit_signal("connection_succeeded")
func _connected_fail():
get_tree().disconnect("connected_to_server", self, "_connected_ok")
get_tree().disconnect("connection_failed", self, "_connected_fail")
get_tree().disconnect("server_disconnected", self, "_server_disconnected")
get_tree().set_network_peer(null)
emit_signal("connection_failed")
func _server_disconnected():
gamestate.quit_game()
emit_signal("server_disconnected")
func _game_ended():
get_tree().disconnect("connected_to_server", self, "_connected_ok")
get_tree().disconnect("connection_failed", self, "_connected_fail")
get_tree().disconnect("server_disconnected", self, "_server_disconnected")
gamestate.disconnect("game_ended",self,"_game_ended")
get_tree().set_refuse_new_network_connections(false)
get_tree().set_network_peer(null)
+45
View File
@@ -0,0 +1,45 @@
extends Spatial
class_name GameServer
const SERVER_ADDR = "mur-server.lh8.de"
const API_ADDR = "https://" + SERVER_ADDR + "/"
const HEADERS = ["Content-Type: application/json"]
const SSL = false
var server_addr:String = SERVER_ADDR
var api_addr:String = API_ADDR
var headers:Array = HEADERS
var ssl:bool = SSL
func http():
var game_server_requests = GameServerRequests.new()
add_child(game_server_requests)
return game_server_requests
func get_server_addr():
return server_addr
func set_server_addr(new_server_addr:String):
server_addr = new_server_addr
func get_api_addr():
return api_addr
func set_api_addr(new_api_addr:String):
if not new_api_addr.ends_with("/"):
new_api_addr += "/"
api_addr = new_api_addr
func get_headers():
return headers
func get_ssl():
return ssl
@@ -0,0 +1,35 @@
extends Spatial
class_name GameServerRequests
var http:HTTPRequest
func _ready():
http = HTTPRequest.new()
add_child(http)
http.connect("request_completed",self, "_self_destroy")
func connect_http(node,function):
http.connect("request_completed",node,function)
func get_request(path:String):
http.request(game_server.get_api_addr() + path, game_server.get_headers(), game_server.get_ssl(), HTTPClient.METHOD_GET)
func post_request(path:String, data:String = ""):
http.request(game_server.get_api_addr() + path, game_server.get_headers(), game_server.get_ssl(), HTTPClient.METHOD_POST, data)
func put_request(path:String, data:String = ""):
http.request(game_server.get_api_addr() + path, game_server.get_headers(), game_server.get_ssl(), HTTPClient.METHOD_PUT, data)
func delete_request(path:String, data:String = ""):
http.request(game_server.get_api_addr() + path, game_server.get_headers(), game_server.get_ssl(), HTTPClient.METHOD_DELETE, data)
func _self_destroy(result, response_code, headers, body):
queue_free()
+170
View File
@@ -0,0 +1,170 @@
extends Node
const MAX_PEERS = 4
const LOBBY_READY_WAIT_TIME = 3
const EMPTY_WAIT_TIME = 30
const EMPTY_CLOSING_TIME = 60
var port:int = -1
var dedicated_server:bool = false
var server_secret:String = ""
var server_id:String = "[GAME:-1] "
var timer:Timer
signal server_error(type, data)
func _ready():
for argument in OS.get_cmdline_args():
if argument.split("=")[0] == "--port":
dedicated_server = true
port = int(argument.split("=")[1])
if argument.split("=")[0] == "--server-id":
server_id = "[GAME:" + str(argument.split("=")[1]) + "] "
if argument.split("=")[0] == "--secret":
server_secret=argument.split("=")[1]
if argument.split("=")[0] == "--bots":
gamestate.set_bots(bool(int(argument.split("=")[1])))
if argument.split("=")[0] == "--server-addr":
game_server.set_server_addr(str(argument.split("=")[1]))
if argument.split("=")[0] == "--api-addr":
game_server.set_api_addr(str(argument.split("=")[1]))
if dedicated_server:
var err = host_game(port)
if err == OK:
print(server_id + "New game hosted: port=" + str(port) + " secret=" + str(server_secret) + " bots=" + str(gamestate.bots) + " server-addr=" + game_server.get_server_addr() + " api-addr=" + game_server.get_api_addr())
print(server_id + "Waiting for connection, closing server in " + str(EMPTY_CLOSING_TIME) + " seconds")
timer.set_wait_time(EMPTY_CLOSING_TIME)
timer.connect("timeout",self,"quit_server",[true])
timer.start()
else:
push_error(server_id + "Could not create Server! (port=" + str(port) + " secret=" + str(server_secret) + " server-addr=" + game_server.get_server_addr() + " api-addr=" + game_server.get_api_addr() + ")")
quit_server()
func host_game(port:int, set_bots:bool = false):
var host = NetworkedMultiplayerENet.new()
var err = host.create_server(port, MAX_PEERS)
get_tree().set_network_peer(host)
get_tree().connect("network_peer_connected", self, "_client_connected")
get_tree().connect("network_peer_disconnected", self,"_client_disconnected")
gamestate.connect("players_changed",self,"_players_changed")
gamestate.connect("game_ready",self,"_game_ready")
gamestate.connect("game_ended",self,"_game_ended")
if set_bots:
gamestate.bots = true
if timer == null:
timer = Timer.new()
timer.set_name("timer")
timer.set_timer_process_mode(Timer.TIMER_PROCESS_PHYSICS)
timer.set_one_shot(true)
timer.set_autostart(false)
add_child(timer)
if err != OK:
emit_signal("server_error", "HOST", err)
return err
func local_game(name:String, color:Color, bots:bool):
var localhost = NetworkedMultiplayerENet.new()
localhost.create_server(0, 0)
get_tree().set_network_peer(localhost)
gamestate.bots = bots
gamestate.set_player(get_tree().get_network_unique_id(), name, color)
gamestate.prepare_game()
gamestate.post_start_game()
func update_server_data():
var req = game_server.http()
var player_count = 0
if gamestate.players != null:
player_count = gamestate.players.size()
req.put_request("game",to_json({'secret' : server_secret, 'player_count' : player_count, 'running' : gamestate.game_running}))
func _client_connected(id):
if get_tree().is_network_server():
if dedicated_server:
print(server_id + "peer connected: " + str(id))
gamestate.rpc_id(id, "set_bots" ,gamestate.bots)
if not timer.is_stopped():
timer.disconnect("timeout",self,"quit_server")
timer.stop()
func _client_disconnected(id):
if get_tree().is_network_server():
if dedicated_server:
print(server_id + "peer disconnected: " + str(id))
if gamestate.game_running:
emit_signal("server_error", "DISCONNECTED", [id])
gamestate.rpc("remove_player" ,id)
else:
gamestate.rpc("remove_player" ,id)
func _players_changed(players):
if get_tree().is_network_server():
if dedicated_server:
update_server_data()
if players.empty():
if gamestate.game_running:
print(server_id + "All players disconnected, close server.")
quit_server()
else:
print(server_id + "All players disconnected, wait for closing...")
timer.set_wait_time(EMPTY_WAIT_TIME)
timer.connect("timeout",self,"quit_server",[true])
timer.start()
func quit_server(triggered:bool = false):
if dedicated_server && triggered:
print(server_id + "Closing time over...quit")
var req = game_server.http()
req.connect_http(self,"_on_delete_server")
req.delete_request("game",to_json({'secret' : server_secret}))
func _on_delete_server(result, response_code, headers, body):
if result != OK || response_code != HTTPClient.RESPONSE_OK:
print(server_id + "ERROR: _on_delete_server, server might be in undefined state!")
get_tree().quit()
func _start_game():
if get_tree().is_network_server():
get_tree().set_refuse_new_network_connections(true)
gamestate.rpc("prepare_game")
func _game_ready(all_ready):
if get_tree().is_network_server():
if all_ready:
timer.set_wait_time(LOBBY_READY_WAIT_TIME)
timer.connect("timeout",self,"_start_game")
timer.start()
else:
timer.disconnect("timeout",self,"_start_game")
timer.stop()
func _game_ended():
get_tree().disconnect("network_peer_connected", self, "_client_connected")
get_tree().disconnect("network_peer_disconnected", self,"_client_disconnected")
gamestate.disconnect("players_changed",self,"_players_changed")
gamestate.disconnect("game_ready",self,"_game_ready")
gamestate.disconnect("game_ended",self,"_game_ended")
get_tree().set_refuse_new_network_connections(false)
get_tree().set_network_peer(null)
+74
View File
@@ -0,0 +1,74 @@
extends Spatial
class_name BaseInventory
var road_straights = [
roads_factory.BUMP,
roads_factory.BUMP_SMALL,
roads_factory.STRAIGHT,
roads_factory.STRAIGHT_SMALL,
]
var roads_right = [
roads_factory.CURVE_RIGHT,
roads_factory.CURVE_LARGE_RIGHT,
roads_factory.CURVE_SMALL_RIGHT,
roads_factory.SKEW_RIGHT,
roads_factory.CURVED_RIGHT,
]
var roads_left = [
roads_factory.CURVE_LEFT,
roads_factory.CURVE_LARGE_LEFT,
roads_factory.CURVE_SMALL_LEFT,
roads_factory.SKEW_LEFT,
roads_factory.CURVED_LEFT,
]
var roads_up = [
roads_factory.RAMP_UP,
roads_factory.RAMP_CURVED_UP,
roads_factory.RAMP_SMALL_UP,
]
var roads_down = [
roads_factory.RAMP_DOWN,
roads_factory.RAMP_CURVED_DOWN,
roads_factory.RAMP_SMALL_DOWN,
]
var roads_special = [
roads_factory.LOOP,
]
var roads = [ road_straights, roads_right, roads_left, roads_up, roads_down, roads_special ]
var player:Player
var route:Route
var item:Road
var type:int = 0
var index:int = 0
signal item_changed(index, player)
func _ready():
route = gamestate.game.route
func set_player(new_player:Player):
player = new_player
func set_item():
if is_network_master():
if item:
item.free()
item = roads_factory.get_road_instance(roads[type][index])
if player != null:
item.set_color(player.get_player_color())
item.rotate_y(PI/2)
emit_signal("item_changed", roads[type][index], player)
+65
View File
@@ -0,0 +1,65 @@
extends Spatial
var player:Player
const MAX_OFFSET = 8.0
const OFFSET_STEPS = 0.01
var break_constrain = 0.0
export var overspeed_rate:float = 0.3
export var underspeed_rate:float = 0.1
func _physics_process(delta):
if is_network_master() && player != null:
if player.is_out:
if player.is_resetable:
player.reset()
else:
if player.get_road() != null:
var road = player.get_road()
var rate = util.randf()
var speed = player.current_speed
var offset = 0
var distance = player.follow.get_offset()
var tmp_break_constrain = 0.0
break_constrain = 0.0
while tmp_break_constrain == 0.0 and offset < MAX_OFFSET && road != null:
var constrain_index = road.get_constrain_index(distance)
var road_length = road.get_lane_curve(player.lane).get_baked_length()
if constrain_index >= 0:
tmp_break_constrain = road.speed_constrains[constrain_index].z
if tmp_break_constrain > break_constrain:
break_constrain = tmp_break_constrain
distance += OFFSET_STEPS
offset += OFFSET_STEPS
if distance >= road_length:
distance = 0
road = gamestate.game.route.get_road(road.get_index()+1)
if break_constrain > 0 && speed > break_constrain - 0.04 && rate > overspeed_rate:
player.thrust = -1
elif speed - 0.08 < break_constrain && rate > underspeed_rate:
player.thrust = 1
elif break_constrain == 0 && rate > underspeed_rate:
player.thrust = 1
else:
player.thrust = 0
func set_player(path:String):
player = get_node(path)
get_node("inventory").set_player(player)
func set_overspeed_rate(new_overspeed_rate:float):
overspeed_rate = new_overspeed_rate
func set_underspeed_rate(new_underspeed_rate:float):
underspeed_rate = new_underspeed_rate
+22
View File
@@ -0,0 +1,22 @@
extends BaseInventory
var rand:RandomNumberGenerator = RandomNumberGenerator.new()
func _ready():
rand.randomize()
func _on_raceCar_road_entered(road):
if is_network_master():
if player != null:
if player.is_in_group("first"):
if route.get_last_road().get_index() <= (road.get_index() +2):
type = rand.randi_range(0,roads.size() -2) # TODO: remove special, loop need fixes!
index = rand.randi_range(0, roads[type].size() -1)
route.rpc("add_road", roads[type][index], player.get_index())
func set_player(new_player:Player):
player = new_player
player.race_car.connect("road_entered",self,"_on_raceCar_road_entered")
+52
View File
@@ -0,0 +1,52 @@
extends Spatial
var player:Player
onready var camera:InterpolatedCamera = get_node("camera")
onready var ingame_menu:Spatial = find_node("ingame_menu")
func _physics_process(delta):
if is_network_master() && player != null:
if Input.is_action_just_pressed("controls_menu"):
ingame_menu.set_visible(not ingame_menu.is_visible_in_tree())
if player.is_out:
camera.set_speed(0.1)
if player.timer.get_time_left() > 0:
get_node("hud/reset").set_text(str(int(player.timer.get_time_left()) + 1))
else:
get_node("hud/reset").set_text(tr("RESET"))
if Input.is_action_pressed("controls_reset"):
if player.reset():
camera.set_speed(10)
get_node("hud/reset").set_text("")
elif not ingame_menu.is_visible_in_tree():
if Input.is_action_pressed("controls_thrust"):
player.thrust = 1
elif Input.is_action_pressed("controls_break"):
player.thrust = -1
else:
player.thrust = 0
get_node("hud/speed_slider").set_value(player.current_speed * 1000)
if Input.is_action_pressed("debug_camera_1"):
set_debug_camera(0)
elif Input.is_action_pressed("debug_camera_2"):
set_debug_camera(1)
elif Input.is_action_pressed("debug_camera_3"):
set_debug_camera(2)
elif Input.is_action_pressed("debug_camera_4"):
set_debug_camera(3)
func set_player(path:String):
player = get_node(path)
get_node("inventory").set_player(player)
camera.set_target_path(player.find_node("CameraTarget").get_path())
camera.set_interpolation_enabled(true)
camera.set_speed(10)
func set_debug_camera(idx):
if idx < gamestate.game.get_node("players").get_child_count():
camera.set_target_path(gamestate.game.get_node("players").get_child(idx).find_node("CameraTarget").get_path())
+62
View File
@@ -0,0 +1,62 @@
extends BaseInventory
var view:Spatial
var preview:Spatial
func _ready():
view = get_node("view")
preview = get_node("preview")
var hud_track = get_node("../hud/inventory/track_container/track")
hud_track.get_texture().set_viewport_path_in_scene(str(get_path()) + "/viewport")
connect("item_changed",self,"_on_item_changed")
connect("item_changed",preview,"_on_inventory_item_changed")
func _physics_process(delta):
if is_network_master():
if player != null:
if not player.is_out && player.is_in_group("first"):
get_node("../hud/inventory").show()
if item == null:
set_item()
if preview.item:
preview.item.show()
if Input.is_action_just_pressed("controls_add_road"):
route.rpc("add_road", roads[type][index], player.get_index())
if Input.is_action_just_pressed("controls_prev_road_type"):
type -= 1
if type < 0:
type = roads.size() -1
index = 0
set_item()
if Input.is_action_just_pressed("controls_next_road_type"):
type += 1
if type > roads.size() - 1:
type = 0
index = 0
set_item()
if Input.is_action_just_pressed("controls_prev_road_variant"):
index -= 1
if index < 0:
index = roads[type].size() -1
set_item()
if Input.is_action_just_pressed("controls_next_road_variant"):
index += 1
if index > roads[type].size() - 1:
index = 0
set_item()
else:
get_node("../hud/inventory").hide()
if preview.item:
preview.item.hide()
func _on_item_changed(road_identifier, player):
if is_network_master():
if view.get_child_count() > 0:
view.remove_child(view.get_child(0))
view.add_child(item)
get_node("../hud/inventory/track_container/type").set_text(tr(road_identifier))
+32
View File
@@ -0,0 +1,32 @@
extends Spatial
class_name Preview
var player:Player
var item:Road
func _ready():
gamestate.game.route.connect("road_added",self,"_on_route_road_added")
func _on_route_road_added(road):
if is_network_master() && item:
var transform = road.get_global_transform();
var curve = road.get_curve()
transform = transform.translated(curve.get_point_position(curve.get_point_count() -1))
if road.get_end_rotation().length() != 0:
transform.basis = transform.basis.rotated(road.get_end_rotation().normalized(), road.get_end_rotation().length())
item.set_global_transform(transform)
func _on_inventory_item_changed(road_identifier, player):
if is_network_master():
if item:
item.free()
item = roads_factory.get_road_instance(road_identifier)
item.set_preview(true)
if player != null:
item.set_color(player.get_player_color())
add_child(item)
_on_route_road_added(gamestate.game.route.get_last_road())
+229
View File
@@ -0,0 +1,229 @@
extends Node
class_name Player
const MAX_SPEED:float = 0.2
const START_OFFSET = [1.70223, 1.20223, 0.702227, 0.202227 ]
const LANE_OFFSET = [-0.085, 0.085, -0.255, 0.255 ]
export var player_color:Color
var player_name:String
var thrust:int = 0
var current_speed:float = 0.0
export var speed_factor:float = 0.001
export var brake_factor:float = 2.0
export var friction_brake_factor:float = 0.8
onready var race_car = get_node("Path/PathFollow/raceCar")
onready var timer:Timer = get_node("ResetTimer")
onready var path:Path = get_node("Path")
onready var follow:PathFollow = get_node("Path/PathFollow")
onready var route:Route
var lane:int
var start_init:bool = true
var has_next:bool = false
var is_resetable:bool = false
var buffered_curve:Curve3D
var buffered_translate:Vector3 = Vector3(0,0,0)
var buffered_rotation:Vector3 = Vector3(0,0,0)
var last_rotation:Vector3 = Vector3(0,0,0)
var torque_penalty:Vector3
var force_penalty:Vector3
var path_penalty:float
var is_out:bool = false
var position:Vector2
puppet var slave_position:Vector2
func _ready():
route = gamestate.game.route
race_car.road_ray.set_collision_mask_bit(get_index(),1)
path.curve = path.curve.duplicate()
path.curve.set_bake_interval(0.05)
func _physics_process(delta):
if is_network_master():
if not is_out:
var max_speed = MAX_SPEED
if get_road() != null:
var road = get_road()
if is_in_group("first"):
max_speed *= road.get_first_speed_factor()
elif road.get_creator() == get_index():
max_speed *= road.get_creator_speed_factor()
else:
max_speed *= road.get_chasers_speed_factor()
if thrust == 1:
current_speed += speed_factor
elif thrust == -1:
current_speed -= speed_factor * brake_factor
else:
current_speed -= speed_factor * friction_brake_factor
if current_speed >= max_speed:
current_speed = max_speed
elif current_speed < 0:
current_speed = 0
follow.set_offset(follow.get_offset() + current_speed)
if follow.get_offset() < 0:
follow.set_offset(0)
if has_next && (path.curve.get_point_count() == 0 || follow.get_unit_offset() >= 1.0):
has_next = false
if path.curve.get_point_count() > 0:
path.curve.clear_points()
path.curve.set_bake_interval(0.05)
for i in range(buffered_curve.get_point_count()):
var _pos = buffered_curve.get_point_position(i)
var _in = buffered_curve.get_point_in(i)
var _out = buffered_curve.get_point_out(i)
if buffered_rotation.length() != 0:
_pos = _pos.rotated(buffered_rotation.normalized(), buffered_rotation.length())
_in = _in.rotated(buffered_rotation.normalized(), buffered_rotation.length())
_out = _out.rotated(buffered_rotation.normalized(), buffered_rotation.length())
path.curve.add_point(buffered_translate + _pos, _in, _out)
path.curve.set_point_tilt(i, buffered_curve.get_point_tilt(i))
if not start_init:
follow.set_offset(0.001)
else:
follow.set_offset(START_OFFSET[lane])
start_init = false
if get_road() != null:
var road = get_road()
var penalty_index = road.penalty_index(follow.get_offset(), current_speed)
if penalty_index >= 0:
torque_penalty = road.get_torque_penalty(penalty_index)
force_penalty = road.get_force_penalty(penalty_index)
path_penalty = road.get_path_penalty(penalty_index)
is_out = true
is_resetable = false
timer.start()
check_position()
else:
var road = get_road()
race_car.get_node("ray").set_enabled(false)
if force_penalty.length() != 0:
race_car.move_and_slide(force_penalty * current_speed + Vector3(0,-0.5,0))
if torque_penalty.length() != 0:
race_car.rotate_object_local(torque_penalty.normalized(), torque_penalty.length() * current_speed)
if path_penalty > 0 && follow.get_offset() > 0.0:
follow.set_offset(follow.get_offset() - 0.01)
path_penalty -= 0.01
current_speed -= 0.0002
if current_speed < 0:
current_speed = 0
else:
position = slave_position
func get_road():
return race_car.road
func _on_raceCar_road_entered(road):
var prev_road = route.get_road(road.get_index()-1)
if prev_road != null:
prev_road.body.set_collision_layer_bit(get_index(),0)
buffered_curve = road.get_lane_curve(lane)
buffered_rotation = last_rotation
if path.curve.get_point_count() > 0:
buffered_translate = util.curve_get_last_point(path.curve)
if road.get_end_rotation().length() != 0:
last_rotation += road.get_end_rotation()
has_next = true
func get_player_name():
return player_name
func set_player_name(new_name):
player_name = new_name
func get_player_color():
return player_color
func set_player_color(new_color):
player_color = new_color
var material = SpatialMaterial.new()
material.set_albedo(player_color)
race_car.get_node("body").set_surface_material(1,material)
remotesync func set_first(is_first:bool):
if is_first:
add_to_group("first")
else:
remove_from_group("first")
master func check_position():
position = Vector2(race_car.road_index, follow.get_offset())
rset("slave_position", position)
master func reset():
if is_resetable:
has_next = false
current_speed = 0
var road = race_car.road
road.body.set_collision_layer_bit(get_index(),1)
while road.reset_index != 0:
road = route.get_road(road.get_index() - road.reset_index)
road.body.set_collision_layer_bit(get_index(),1)
path.curve.clear_points()
force_penalty = Vector3(0,0,0)
torque_penalty = Vector3(0,0,0)
buffered_translate = road.get_translation()
last_rotation = road.get_rotation()
race_car.road_index = road.get_index()
race_car.road = null
race_car.collider = null
race_car.transform = Transform()
race_car.get_node("ray").set_enabled(true)
follow.set_transform(road.get_transform())
is_out = false
is_resetable = false
return true
else:
return false
func set_start(new_lane:int):
lane = new_lane
follow.set_h_offset(LANE_OFFSET[lane])
func _on_ResetTimer_timeout():
is_resetable = true
+29
View File
@@ -0,0 +1,29 @@
extends Spatial
var road_ray:RayCast
var collider
var road:Road
var road_index:int = 0
puppet var slave_transform:Transform
signal road_entered(road)
func _ready():
road_ray = get_node("ray")
func _physics_process(delta):
if is_network_master():
if road_ray.is_colliding():
if road_ray.get_collider() != collider:
var parent = road_ray.get_collider().get_parent()
if parent is Road && (road == null && road_index == parent.get_index() || road.get_index() == parent.get_index() - 1) && !parent.is_preview():
collider = road_ray.get_collider()
road = parent
road_index = road.get_index()
emit_signal("road_entered",road)
rset_unreliable("slave_transform", get_global_transform())
else:
set_global_transform(slave_transform)
+144
View File
@@ -0,0 +1,144 @@
extends MeshInstance
class_name Road
export var end_rotation:Vector3 = Vector3(0,0,0)
export var first_speed_factor:float = 1.0
export var creator_speed_factor:float = 1.0
export var chasers_speed_factor:float = 1.0
export var reset_index:int = 0
export (PoolVector3Array) var speed_constrains = PoolVector3Array()
export (PoolVector3Array) var force_penalties = PoolVector3Array()
export (PoolVector3Array) var torque_penalties = PoolVector3Array()
export (Array,float) var path_penalties = []
var body:StaticBody
var creator:int = -1
var preview:bool = false
func _init():
if not has_node("StaticBody"):
body = StaticBody.new()
body.set_name("StaticBody")
var shape = CollisionShape.new()
shape.set_name("CollisionShape")
shape.shape = mesh.create_trimesh_shape()
body.add_child(shape)
body.set_collision_layer_bit(0,1)
body.set_collision_layer_bit(1,1)
body.set_collision_layer_bit(2,1)
body.set_collision_layer_bit(3,1)
add_child(body)
else:
body = get_node("StaticBody")
func get_creator():
return creator
func set_creator(new_creator):
creator = int(new_creator)
func set_color(new_color):
pass # TODO
func get_path():
return get_node("Path")
func get_curve():
return get_path().get_curve()
func get_lane_curve(lane:int):
if has_node("lanes"):
return get_node("lanes").get_child(lane).get_curve()
else:
return get_path().get_curve()
func get_end_rotation():
return end_rotation
func set_preview(prev):
preview = prev
if prev:
set_material_override(SpatialMaterial.new())
else:
set_material_override(null)
func is_preview():
return preview
func get_next_lane(lane):
return lane
func get_constrain_index(distance:float):
for index in range(speed_constrains.size()):
var constrain = speed_constrains[index]
if constrain.x <= distance && constrain.y >= distance:
return index
return -1
func penalty_index(distance:float, speed:float):
var constrain_index = get_constrain_index(distance)
if constrain_index >= 0:
var constrain = speed_constrains[constrain_index]
if constrain.z < 0 && speed < constrain.z * -1 || constrain.z > 0 && speed > constrain.z:
return constrain_index
return -1
func get_torque_penalty(index:int):
if index >= 0:
if torque_penalties.size() < (index + 1):
return get_torque_penalty(index - 1)
return torque_penalties[index]
return Vector3(0,0,0)
func get_force_penalty(index:int):
if index >= 0:
if force_penalties.size() < (index + 1):
return get_force_penalty(index - 1)
if get_rotation().length() != 0:
return force_penalties[index].rotated(get_rotation().normalized(), get_rotation().length())
else:
return force_penalties[index]
return Vector3(0,0,0)
func get_path_penalty(index:int):
if index >= 0:
if path_penalties.size() < (index + 1):
return get_path_penalty(index - 1)
return path_penalties[index]
return 0.0
func get_first_speed_factor():
return first_speed_factor
func get_creator_speed_factor():
return creator_speed_factor
func get_chasers_speed_factor():
return chasers_speed_factor
+33
View File
@@ -0,0 +1,33 @@
extends Node
class_name TracksFactory
const START = "Start"
const STRAIGHT = "StraightLong"
const STRAIGHT_SMALL = "Straight"
const CURVE_RIGHT = "CornerLarge"
const CURVE_LEFT = "CornerLargeFlipped"
const CURVE_LARGE_RIGHT = "CornerLarger"
const CURVE_LARGE_LEFT = "CornerLargerFlipped"
const CURVE_SMALL_RIGHT = "CornerSmall"
const CURVE_SMALL_LEFT = "CornerSmallFlipped"
const BUMP = "StraightLongBump"
const BUMP_SMALL = "Bump"
const SKEW_RIGHT = "StraightSkew"
const SKEW_LEFT = "StraightSkewFlipped"
const RAMP_UP = "RampLong"
const RAMP_DOWN = "RampLongFlipped"
const RAMP_CURVED_UP = "RampLongCurved"
const RAMP_CURVED_DOWN = "RampLongCurvedFlipped"
const RAMP_SMALL_UP = "Ramp"
const RAMP_SMALL_DOWN = "RampFlipped"
const CURVED_RIGHT = "CurvedFlipped"
const CURVED_LEFT = "Curved"
const LOOP = "Loop"
func get_road_instance(road):
var instance = load("res://scenes/road/road" + road + ".tscn").instance()
if !instance.get_script():
instance.set_script(load("res://scripts/road/road.gd"))
return instance