라운드 추가 로 플레이어가 자신의 진행도를 측정하고 평등한 경기장을 위한 정기적인 기회를 갖도록 게임플레이를 단계별로 구조화할 수 있습니다.이는 팀 기반 게임플레이에 특히 중요하며, 해당 라운드 동안 팀에 누가 있는지에 따라 플레이 스타일을 바꿀 수 있는 기회를 플레이어에게 제공합니다.
참조로 샘플 레이저 태그 경험을 사용하여 이 자습서의 이 섹션은 Roblox의 기본 기능을 사용하여 각 라운드를 구조화하는 방법, 스크립트 가이드에 대한 지침을 포함하여:
- 개별 및 팀 포인트를 재설정하여 라운드를 시작하고, 플레이어를 팀 스폰 영역으로 스폰합니다.
- 각 플레이어의 화면 상단에 라운드의 목표를 설정하는 변수를 사용자 정의합니다.
- 팀 점수에 대한 플레이어 포인트 기여를 추적합니다.
- 플레이어의 팀이 라운드에서 승리했는지 패배했는지에 따라 고유한 UI 화면을 트리거합니다.
- 플레이어를 연결 해제하고 중립 로비에서 생성하여 라운드를 종료합니다.
이 섹션을 완료하면 플레이어에게 정확하고 만족스러운 블래스터 동작을 구현하는 방법을 배웁니다.

루프 시작
ServerScriptService > 게임플레이 > 라운드 처리 대부분의 논리를 구현하기 위해 라운드 루프의 시작을 표시하기 위해 startRoundLoopAsync() 시작합니다.플레이어가 로비에 참여하고 팀으로 분류될 때까지 기다리는 동안, 는 서버스크립트서비스(ServerScriptService)의 함수를 호출하여 리더보드와 팀 포인트 모두를 재설정합니다.
점수 부여
function Scoring.resetScores()
for _, player in Players:GetPlayers() do
player.leaderstats.Points.Value = 0
end
for _, team in Teams:GetTeams() do
team:SetAttribute(GuiAttribute.teamPoints, 0)
end
end
이제 모두가 0점에서 시작하므로, 그런 다음 생성 위치의 중립 속성을 로 설정하여 스폰 위치의 동일한 속성을 가진 플레이어만 스폰할 수 있도록 합니다.스폰 위치의 속성이 샘플의 민트 또는 카네이션 핑크 팀 대신 흰색으로 설정되어 있기 때문에, 이 구성으로 모든 플레이어가 라운드가 활성화된 동안 거기에서 스폰하거나 재생성하지 못합니다.
로비에 현재 있는 플레이어의 경우, startRoundLoopAsync() 모든 플레이어를 현재 경험 내에 있는 모든 플레이어를 spawnPlayersInMap 함수에 전달하여 서버스크립트 서비스의 **** > 게임플레이 > 라운드 > spawnPlayersInMap 에서 모든 플레이어를 정렬하고 균형을 맞추어 대략적으로 동일한 수의 플레이어로 팀을 구성합니다.
로비 그룹이 팀으로 정렬된 후 경험에 새로 참여하는 모든 플레이어에 대해, startRoundLoopAsync() 는 Players.PlayerAdded:Connect 이벤트를 수신하고 다시 spawnPlayersInMap 함수를 호출하여 가장 적은 수의 플레이어로 팀에 추가합니다.이 프로세스에 대한 자세한 정보는 이전 생성 및 재생성 섹션의 튜토리얼에서 스폰 위치 구성 을 참조하십시오.
라운드
-- 맵에서 모든 플레이어 생성
neutralSpawn.Neutral = false
spawnPlayersInMap(Players:GetPlayers())
-- 가입할 때 맵에서 새 플레이어 생성
local playerAddedConnection = Players.PlayerAdded:Connect(function(player: Player)
spawnPlayersInMap({ player })
end)
목표 설정
이제 각 플레이어가 팀원과 함께 아레나에 있으므로 경험은 라운드 내에서 성공하기 위해 수행해야 할 지침을 제공해야 합니다.샘플 레이저 태그 경험은 각 플레이어의 화면 상단에 명확한 승리에 필요한 작업에 대한 목표 프롬프트를 제공하여 이 요구 사항을 처리합니다.

UI 커리큘럼에서 목표 UI 구성 요소를 구성하고 표시하는 방법에 대해 자세히 알아볼 수 있지만, 이 섹션에서는 라운드가 시작되면서 목표 목표를 구현하는 방법에 초점을 둡니다. 라운드를 완료하기 위해 각 팀이 필요한 점수 수를 설정하는 방법을 시작으로 합니다.
런타임에 목표 프롬프트가 플레이어에게 승리하려면 세 점을 득점해야 한다는 정보를 제공하지만, StarterGui > HUDGui 에서 프롬프트를 검사하면 점 값에 대한 구성 가능한 ""이 포함되어 있음을 알 수 있습니다.

“ ”는 언제든지 업데이트하여 게임플레이 요구 사항을 충족시킬 수 있는 자리 표시자 문자열로, 변수를 ReplicatedStorage > TEAM_SCORE_LIMIT 에서 업데이트하여 사용할 수 있습니다.예를 들어, 이 숫자를 과도하게 높은 200로 설정하면 프롬프트와 팀 포인트 카운터가 적절히 업데이트됩니다.
팀_점수_제한
local TEAM_SCORE_LIMIT = 200 -- 업데이트된 라인, 반드시 되돌려야 뒤로return TEAM_SCORE_LIMIT

이 간단한 변수 업데이트는 라운드가 시작되기 때문에 런타임에 작동합니다. ReplicatedStorage > HUDGuiSetup > SetObjective 는 UI 목표의 TEAM_SCORE_LIMIT 개체에서 자리 표시자 문자열을 교체할 수 있도록 TextLabel 모듈 스크립트가 필요하기 때문입니다.
팀_점수_제한
local TEAM_SCORE_LIMIT = require(ReplicatedStorage.TEAM_SCORE_LIMIT)
local function setObjective(gui: ScreenGui)
local bodyTextLabel = gui.Objective.ObjectiveDisplay.Body.BodyTextLabel
bodyTextLabel.Text = bodyTextLabel.Text:format(TEAM_SCORE_LIMIT)
end
추적 포인트
이제 플레이어가 라운드에 대한 목표를 가지게 되었으므로 경험은 목표에 도달할 때까지 각 팀의 점수를 추적해야 합니다.서비스의 기본 동작은 각 플레이어를 팀 아래에 자동으로 그룹화하고 각 플레이어의 기여도를 팀 점수에 추가하지만, 라운드 기반 게임플레이에서는 플레이어가 점수를 기록한 후 라운드가 끝나기 전에 연결을 끊으면 리더보드에서 각 플레이어의 기여도가 공제되기 때문에 별도의 위치에서 점수를 저장하고 모니터링하는 것이 중요합니다.
이런 일이 발생하지 않고 팀 목표에 대한 모든 기여가 보존되도록 하려면 ReplicatedStorage > HUDGuiSetup > 팀 포인트 동기화 시작 서비스에서 특성의 모든 포인트를 별도로 저장합니다.As teamPoints 증가로, 이 모듈 스크립트는 목표 UI 구성 요소 내에서 팀 카운터 startSyncingTeamPoints 를 찾기 위해 함수 Class.GuiObjects 를 호출합니다.
팀 카운터와 팀 카운터를 찾으면 팀 스폰 영역과 관련된 특성을 얻습니다. TeamACounter는 녹색 팀의 점수를 표시하고 TeamBCounter는 핑크 팀의 점수를 추적합니다.
팀 포인트 동기화 시작
local function startSyncingTeamPoints(gui: ScreenGui)
for _, teamPointCounter in gui.Objective.TeamPointCounter:GetChildren() do
if not teamPointCounter:IsA("GuiObject") then
continue
end
local iconTeamColor = teamPointCounter:GetAttribute(GuiAttribute.teamColor)
모듈 스크립트는 그런 다음 getTeamFromTeamColor 민트 teamColor 및 TeamBCounter's teamColor``Class.Team.Color 특성이 해당 서비스 아래에서 일치하는지 확인하기 위해 Teams 스크립트를 호출합니다.그렇다면 두 팀 모두를 반환합니다.
팀 포인트 동기화 시작
local function getTeamFromTeamColor(teamColor: Color3): Team?
for _, team in Teams:GetTeams() do
if team.TeamColor == teamColor then
return team
end
end
return nil
end
이 발생하면 startSyncingTeamPoints 는 두 팀 카운터의 TextLabel 개체를 각각의 teamPoints 값으로 설정하고, 플레이어가 반대 팀의 다른 플레이어를 태그하여 포인트를 득점할 때마다 업데이트를 계속합니다.
팀 포인트 동기화 시작
teamPointCounter.TextLabel.Text = team:GetAttribute(GuiAttribute.teamPoints)
team:GetAttributeChangedSignal(GuiAttribute.teamPoints):Connect(function()
teamPointCounter.TextLabel.Text = team:GetAttribute(GuiAttribute.teamPoints)
지금까지 이 섹션의 모든 것은 플레이어의 화면에서 포인트를 추적하는 방법에 초점을 맞췄지만, 서버에서 추적 포인트를 처리하는 논리를 검토하여 팀이 목표 목표에 도달하고 라운드를 승리할 때를 알 수 있습니다.서버 스크립트 서비스 > 게임플레이 > 점수 산정 을 다시 방문하면 모듈 스크립트가 플레이어가 포인트를 득점할 때마다 발생하는 바인더 가능한 이벤트를 생성하여 시작한다는 것을 확인할 수 있습니다.
점수 부여
local teamScoreChangedBindable = Instance.new("BindableEvent")local Scoring = {teamScoreChanged = teamScoreChangedBindable.Event,}
그런 다음 incrementScore 함수를 호출하여 다음 작업을 수행합니다:
- 서비스의 개체에서 플레이어의 팀과 현재 팀 포인트 값을 가져서 하나 추가합니다.
- 리더보드에서 플레이어의 개별 점수를 가져와 하나 추가합니다.
- 플레이어의 팀과 점수를 모두 사용하여 앞서 언급한 바인더블 이벤트를 발사합니다.
이 프로세스는 클라이언트와 서버가 플레이어의 개별 점수와 팀 점수 모두에 대해 일치하도록 유지하여 효과적으로 작동합니다.
점수 부여
function Scoring.incrementScore(player: Player, amount: number)
local team = player.Team
assert(team, `Player {player.Name} must be on a team to score a point, but has no team`)
local teamPoints = team:GetAttribute(GuiAttribute.teamPoints)
teamPoints += amount
team:SetAttribute(GuiAttribute.teamPoints, teamPoints)
local leaderstat = player.leaderstats.Points
leaderstat.Value += amount
teamScoreChangedBindable:Fire(team, teamPoints)
end
결과 표시
플레이어가 서로 태그를 지정하고 팀에 대한 점수를 기록할 때, ServerScriptService > 게임플레이 > 라운드 는 팀이 점수를 달성했는지 확인하기 위해 라운드 목표에 도달했는지 확인합니다.팀 점수가 ReplicatedStorage의 TEAM_SCORE_LIMIT 변수보다 낮으면 서버는 팀 중 하나가 다시 점수를 얻을 때까지 계속 대기합니다.
그러나 팀의 점수가 TEAM_SCORE_LIMIT에 도달하면 스크립트는 플레이어의 이름과 팀을 가진 roundWinnerRemote를 발동합니다.
라운드
-- 각 점수 후에 라운드가 종료되었는지 확인local team: Teamlocal score: number = 0while score < TEAM_SCORE_LIMIT doteam, score = Scoring.teamScoreChanged:Wait()end-- 승리한 팀 표시for _, player in Players:GetPlayers() do-- 라운드가 끝날 때 플레이어가 속한 팀 전송-- 플레이어의 팀이 제거될 예정이므로 클라이언트-- 자신의 팀을 확인할 수 없을 것입니다roundWinnerRemote:FireClient(player, team, player.Team)end
각 클라이언트 목록의 ReplicatedStorage > RoundResultsGuiSetup 스크립트는 이 이벤트 인스턴스를 수신하여 다음을 수행할 수 있습니다.
- 라운드 결과와 플레이어가 승리 팀에 있었는지 여부를 알리는 독특한 StarterGui > RoundResultsGui UI 화면을 표시합니다.
- 승리나 패배 오디오 클립 재생.
예를 들어, 플레이어가 승리 포인트를 득점한 팀에 있는 경우, 승리 텍스트와 기쁜 소리가 표시되는 UI 화면의 형태로 라운드 결과에 대한 여러 피드백을 받습니다.반대로, 플레이어가 승리 포인트를 득점한 팀에 없으면 패배 텍스트가 표시되는 UI 화면과 불길한 소리가 재생되는 오디오 클립을 받습니다.
라운드결과GUI설정
local function onRoundWinner(winner: Team, localTeam: Team?)
local victoryDefeatText = "Round ended!"
if localTeam then
-- 팀이 승리하면 승리를 표시합니다! 그렇지 않으면 패배를 표시합니다...
local isVictory = winner == localTeam
if isVictory then
victorySound:Play()
victoryDefeatText = VICTORY_TEXT
else
defeatSound:Play()
victoryDefeatText = DEFEAT_TEXT
end
end
팀 재설정
동시에 ServerScriptService > 게임플레이 > 라운드 가 팀이 라운드 목표를 달성했는지 확인하고 각 플레이어에 대해 적절한 UI 표시를 트리거하면서 모든 플레이어를 아레나에서 로비로 전송하여 라운드를 연결 해제하면, 각 플레이어에 대한 모든 플레이어를 로비로 전송하여 라운드를 연결 해제하면, 각 플레이어에 대한 모든 플레이어를 로비로 전송하여 라운드를 연결 해제하면, 각 플레이어에 대한 모든 플레이어를 로비로 전송하여 라운드를 연결 해제하면, 각 플레이어에 대한 모든 플레이어를 로비로 전송하여 라운드를 연결 해제하면, 각 플레이어에 대한 모든 플레이어를 로비로 전송하여 라운드를 연결 해제하면, 각 플레이어에 대한 모든 플레이어를 로비로 전송하여 라운드를 연결 해제하면, 각 플레이어에 대한 모든 플레이어를 로비로 전송하여 라운드를 연결 해제하면, 각 플레이어에 대한 모든 플레이어를 로비로 전송하여 라운드를 연결 해제하면, 각 플레이어에 대한 모든 플레이어를 로비로 전송하여 라운드를 연결 해제하면, 각 플레이어에 대한 모든 플레이어를 로비로 전송하여 라운드를 연결 해제하면, 각 플레이어에 대한 모든 플레이어를 로비로 전송하여 라운드를 연결 해제하면, 동시에 모든 플레이어를 로비로 전송하여 라운드를 연결 해제하면, 동시에서 모든 플레이어를 연결하면, 모든 플레이어를 로비로 전송하면, 라운드를 연결하면, 라운드를 연결하면, 모든 플레이를 연결하면, 모든 플레이를 연결하면, 라운드를 연결하면, 라운드를 연결하면, 라운드를 연결하면, 연결하면, 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면, 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연결하면 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 연으로 이로써 라운드를 공식적으로 종료하고 두 팀을 재설정하는 프로세스가 시작됩니다.
스폰 위치 구성 에서 동일한 논리를 사용하고, 라운드에서는 중립 스폰 위치의 속성을 트루로 설정하여 플레이어가 팀 상태에 관계없이 거기에서 스폰할 수 있습니다.즉, 로비가 플레이어가 라운드에서 연결 해제된 후 스폰할 수 있는 유일한 위치가 됩니다.
라운드
-- 모두를 로비로 보내기playerAddedConnection:Disconnect()neutralSpawn.Neutral = truespawnPlayersInLobby(Players:GetPlayers())
중단을 위해 10초 동안 기다린 후, 라운드 서버 스크립트는 모두의 점수를 재설정하고 새로운 팀으로 정렬하여 루프를 다시 시작합니다.샘플은 서버 내에 플레이어가 없을 때까지 이 순환 라운드 프로세스를 다시 반복합니다.
이제 플레이어가 자신의 팀으로 맵에 스폰하고 전체 라운드를 플레이할 수 있으므로 다음 섹션에서는 각 블래스터의 동작 뒤에 있는 스크립트에 대해 알려줍니다.