extends CraftyGame
const MOVE_SPEED := 8.0
const GRAVITY := 20.0
const ROUND_SECONDS := 300.0
const TEAM_SCORE_TO_WIN := 15
const RED_GOAL_X_MIN := 22.0
const BLUE_GOAL_X_MAX := -22.0
var _red_spawns: Array[Vector3] = []
var _blue_spawns: Array[Vector3] = []
func get_prediction_params() -> Dictionary:
return {"move_speed": MOVE_SPEED, "gravity": GRAVITY}
func _game_init() -> void:
Crafty.teams.create("red", {"color": Color.RED, "max_size": 16})
Crafty.teams.create("blue", {"color": Color.BLUE, "max_size": 16})
var red_root := get_node_or_null("SpawnPointsRed")
if red_root:
for child in red_root.get_children():
if child is Node3D:
_red_spawns.append(child.global_position)
var blue_root := get_node_or_null("SpawnPointsBlue")
if blue_root:
for child in blue_root.get_children():
if child is Node3D:
_blue_spawns.append(child.global_position)
if _red_spawns.is_empty():
_red_spawns = [Vector3(-15, 1, -8), Vector3(-15, 1, 8)]
if _blue_spawns.is_empty():
_blue_spawns = [Vector3(15, 1, -8), Vector3(15, 1, 8)]
func _game_start() -> void:
Crafty.teams.auto_balance()
Crafty.set_time_limit(ROUND_SECONDS)
Crafty.send_announcement("Red vs Blue started")
func _game_end() -> void:
var red_score := Crafty.score.get_team("red")
var blue_score := Crafty.score.get_team("blue")
if red_score > blue_score:
Crafty.send_announcement("Red wins %d - %d" % [red_score, blue_score])
elif blue_score > red_score:
Crafty.send_announcement("Blue wins %d - %d" % [blue_score, red_score])
else:
Crafty.send_announcement("Draw %d - %d" % [red_score, blue_score])
func _player_joined(player) -> void:
var assigned := _assign_team(player)
var spawn := _team_spawn_for(assigned)
if player.has_method("respawn"):
player.respawn(spawn)
player.set_synced("team", assigned)
func _player_left(player) -> void:
Crafty.teams.remove_player(player)
func _process(delta: float) -> void:
super._process(delta)
if not Crafty.is_server():
return
for p in get_players():
apply_default_movement(p, delta, MOVE_SPEED, GRAVITY)
_check_goal_score(p)
func _assign_team(player) -> String:
var red_count := Crafty.teams.get_members("red").size()
var blue_count := Crafty.teams.get_members("blue").size()
var target := "red" if red_count <= blue_count else "blue"
if not Crafty.teams.assign(player, target):
target = "blue" if target == "red" else "red"
Crafty.teams.assign(player, target)
return target
func _team_spawn_for(team_id: String) -> Vector3:
if team_id == "red":
return _red_spawns.pick_random()
return _blue_spawns.pick_random()
func _check_goal_score(player) -> void:
var team_id := Crafty.teams.get_team(player)
if team_id == "":
return
if team_id == "red" and player.position.x >= RED_GOAL_X_MIN:
_award_team_score("red", player)
elif team_id == "blue" and player.position.x <= BLUE_GOAL_X_MAX:
_award_team_score("blue", player)
func _award_team_score(team_id: String, scorer) -> void:
Crafty.score.add_team(team_id, 1)
var score := Crafty.score.get_team(team_id)
Crafty.send_announcement("%s team scored (%d/%d) by %s" % [team_id.capitalize(), score, TEAM_SCORE_TO_WIN, str(scorer.get("display_name"))])
var current_team := Crafty.teams.get_team(scorer)
scorer.teleport(_team_spawn_for(current_team))
if score >= TEAM_SCORE_TO_WIN:
end_game(false)