블래스터 동작 구현

*이 콘텐츠는 AI(베타)를 사용해 번역되었으며, 오류가 있을 수 있습니다. 이 페이지를 영어로 보려면 여기를 클릭하세요.

블래스터 동작 구현은 1인칭 슈팅 게임에서 폭발 메커니즘을 프로그래밍하는 과정입니다. 플레이어는 단일 클릭이나 버튼 누르기로 폭발할 수 있지만, 만족스럽고 정확한 폭발 동작을 만드는 것이 중요합니다. 이는 플레이어의 전반적인 게임 플레이 즐거움을 향상시키기 때문입니다.

샘플 레이저 태그 게임을 참조하여, 이 튜토리얼의 이 섹션에서는 두 가지 유형의 블래스터에 대한 블래스터 동작 구현 뒤에 있는 스크립트에 대해 배우며, 다음과 같은 내용을 안내합니다:

  • 플레이어가 폭발 버튼을 누를 때 감지하기.
  • 플레이어가 최근에 폭발 버튼을 눌렀다면 블래스터를 사용할 수 있는지 확인하기.
  • 서버에 폭발을 시작한 사람, 폭발의 출처, 각 레이저 빔의 최종 목적지를 알려주는 폭발 데이터를 생성하기.
  • 폭발 데이터에 대해 서버에 알리기, 서버가 다른 플레이어와 충돌한 경우 적절한 작업을 수행할 수 있도록 하기.
  • 각 폭발 사이에 블래스터를 재설정하여 블래스터가 다시 폭발할 수 있도록 충분한 시간 동안 식도록 하기.

이 섹션을 완료한 후, 블래스터가 다른 플레이어와 충돌할 때 이를 감지하고 각 블래스터 유형에 따라 해당 체력을 차감하는 스크립트에 대해 배우게 됩니다.

플레이어 입력 감지

블래스터 동작을 구현하는 첫 번째 단계는 플레이어가 폭발 버튼을 누를 때를 듣는 것입니다. 플레이어가 폭발 버튼을 누르는 입력 유형은 게임에 접근하는 장치에 따라 다릅니다. 예를 들어, 샘플 레이저 태그 게임은 마우스 및 키보드 제어, 게임패드, 터치 제어를 지원합니다. 이러한 입력 유형은 ReplicatedStorageUserInputHandler에서 확인할 수 있습니다.

이 클라이언트 스크립트는 ContextActionService를 사용하여 MouseButton1ButtonR2를 폭발 동작에 바인딩합니다. 이는 플레이어가 왼쪽 마우스 버튼이나 게임패드의 R2 버튼을 누를 때마다 블래스터에서 레이저 빔이 폭발하도록 트리거합니다. 모바일 장치에서는 폭발을 위한 버튼이 HUDGui에 포함되어 있으며, 스크립트에서 나중에 연결됩니다.

UserInputHandler
ContextActionService:BindAction("_", onBlasterActivated, false,
Enum.UserInputType.MouseButton1,
Enum.KeyCode.ButtonR2
)

또한 onBlasterActivated() 정의에서 Enum.UserInputState.Begin을 사용하는 것이 중요합니다. 많은 사용자 인터페이스 상호작용, 예를 들어 이 예제에서 블래스터를 선택하는 것은 마우스 버튼이 올라올 때까지 발생하지 않으며(Enum.UserInputState.End), 이는 사용자가 상호작용을 피할 수 있는 마지막 기회를 제공합니다. 그러나 폭발 메커니즘은 버튼이 눌리는 즉시 발생하지 않으면 반응성이 떨어집니다.

예를 들어, Enum.UserInputState.BeginEnum.UserInputState.End로 변경한 후 플레이 테스트를 통해 폭발의 반응성이 게임 플레이에 미치는 영향을 확인할 수 있습니다. 예를 들어, 플레이어가 버튼을 누르고 있어도 폭발이 트리거되지 않는다면, 다른 플레이어를 태그하는 경험이 어떻게 달라질까요?

UserInputHandler
local function onBlasterActivated(_actionName: string,
inputState: Enum.UserInputState, _inputObject: InputObject)
if inputState == Enum.UserInputState.End then -- 업데이트된 줄, 반드시 되돌리기
attemptBlastClient()
end
end

플레이어가 폭발할 수 있는지 확인하기

UserInputHandler가 버튼 누르기 또는 화면 탭을 감지한 후, ReplicatedStorageBlasterattemptBlastClient를 호출하여 플레이어가 폭발할 수 있는지 확인합니다. 샘플 레이저 태그 게임의 대부분의 체크와 마찬가지로, 이는 클라이언트에서 먼저 발생한 후 서버에서 나중에 발생합니다. attemptBlastClientReplicatedStorageBlastercanLocalPlayerBlast를 호출하여 blasterStateClient 플레이어 속성의 간단한 체크를 수행합니다:

canLocalPlayerBlast
local function canLocalPlayerBlast(): boolean
return localPlayer:GetAttribute(PlayerAttribute.blasterStateClient) == BlasterState.Ready
end

ReplicatedStorageBlasterBlasterState를 살펴보면, 게임에는 세 가지 블래스터 상태가 있습니다: Ready, Blasting, Disabled. 이러한 각 상태의 효과를 보려면 게임을 플레이 테스트하고, Players 서비스에서 플레이어를 선택한 후 Properties 창에서 blasterStateClient 속성을 관찰하십시오. 블래스터를 선택할 때 Disabled로 표시되고, 대부분의 시간 동안 Ready로 표시되며, 버튼을 누른 후에는 Blasting으로 표시되는 것을 확인할 수 있습니다.

이 약간의 지연은 클릭할 수 있는 속도만큼 빠르게 폭발할 수 없도록 합니다. 예를 들어, 함수를 항상 true를 반환하도록 변경하면 지연 없이 블래스터를 빠르게 폭발시킬 수 있으며, 이는 레이저 태그 게임 플레이에 비현실적입니다.

canLocalPlayerBlast
local function canLocalPlayerBlast(): boolean
return true -- 업데이트된 줄, 반드시 되돌리기
end

폭발 데이터 생성

플레이어의 블래스터가 Ready 상태에 있는지 확인한 후, attemptBlastClientReplicatedStorageattemptBlastClientblastClient를 호출합니다. blastClient가 수행하는 첫 번째 단계는 blasterStateClient 플레이어 속성을 Blasting으로 설정하여 이전의 빠른 발사 사례를 피하는 것입니다.

다음 단계는 폭발 데이터를 생성하는 것입니다. ReplicatedStorageBlasterBlastData를 검토하면 각 폭발이 세 가지 정보로 구성되어 있음을 알 수 있습니다:

  • 폭발을 시작한 플레이어.
  • 폭발의 출처를 나타내는 DataType.CFrame.
  • 각 레이저 빔의 최종 목적지와 다른 플레이어를 맞춘 경우 해당 플레이어를 포함하는 RayResult 테이블.

이 데이터를 생성하기 위해 blastClientReplicatedStorageattemptBlastClientblastClientgenerateBlastData를 호출합니다. 아래에서 검토할 수 있습니다.

generateBlastData
local function generateBlastData(): BlastData.Type
local blasterConfig = getBlasterConfig()
local rayDirections = getDirectionsForBlast(
currentCamera.CFrame, blasterConfig)
local rayResults = castLaserRay(
localPlayer, currentCamera.CFrame.Position, rayDirections)
local blastData: BlastData.Type = {
player = localPlayer,
originCFrame = currentCamera.CFrame,
rayResults = rayResults,
}
return blastData
end

이 함수는 getBlasterConfig를 사용하여 플레이어의 블래스터 유형을 검색하는 것으로 시작합니다. 샘플에서는 여러 개의 빔을 생성하는 넓고 수평으로 퍼지는 블래스터와 단일 빔을 생성하는 블래스터 두 가지 유형을 제공합니다. 이들의 구성은 ReplicatedStorageInstancesLaserBlastersFolder에서 확인할 수 있습니다.

그런 다음 이 함수는 currentCamera.CFrame을 폭발의 출처로 사용하여 getDirectionsForBlast에 전달합니다. 이 시점에서 코드는 더 이상 블래스터에 관한 것이 아니라 레이저 빔에 관한 것이며, 레이저 빔에 대해 더 배우게 될 것입니다. 충돌 감지 튜토리얼 섹션에서 확인할 수 있습니다. 마지막으로 rayResults 테이블을 생성한 후, generateBlastData는 폭발 데이터를 blastClient에 반환하는 데 필요한 모든 정보를 갖추게 됩니다.

서버에 알리기

blastClient가 폭발에 대한 완전한 데이터를 갖게 되면, 두 개의 이벤트를 발생시킵니다:

blastClient
local laserBlastedBindableEvent = ReplicatedStorage.Instances.LaserBlastedBindableEvent
local laserBlastedEvent = ReplicatedStorage.Instances.LaserBlastedEvent
laserBlastedBindableEvent:Fire(blastData)
laserBlastedEvent:FireServer(blastData)

BindableEvent는 다른 클라이언트 스크립트에 폭발을 알립니다. 예를 들어, ReplicatedStorageFirstPersonBlasterVisuals는 이 이벤트를 사용하여 폭발 애니메이션 및 쿨다운 바와 같은 시각 효과를 표시할 시점을 알립니다. 유사하게, RemoteEvent는 서버 스크립트에 폭발을 알리며, 이는 ServerScriptServiceLaserBlastHandler에서 폭발 처리를 시작합니다.

LaserBlastHandler
local function onLaserBlastedEvent(playerBlasted: Player, blastData: BlastData.Type)
local validatedBlastData = getValidatedBlastData(playerBlasted, blastData)
if not validatedBlastData then
return
end
if not canPlayerBlast(playerBlasted) then
return
end
blastServer(playerBlasted)
processTaggedPlayers(playerBlasted, blastData)
for _, replicateToPlayer in Players:GetPlayers() do
if playerBlasted == replicateToPlayer then
continue
end
replicateBlastEvent:FireClient(replicateToPlayer, playerBlasted, blastData)
end
end

부정 행위를 방지하기 위해, 서버는 각 클라이언트가 보낸 모든 데이터를 검증해야 합니다. 이러한 체크에는 다음이 포함됩니다:

  1. BlastData가 테이블인가? Class.CFramerayResults라는 또 다른 테이블을 포함하고 있는가?
  2. 플레이어가 블래스터를 장착하고 있는가?
  3. 플레이어가 캐릭터와 월드 내 위치를 가지고 있는가?
  4. 폭발 데이터를 보낸 후, 플레이어가 레이저 빔을 발사한 위치에서 과도한 거리를 이동했는가?

마지막 체크는 판단이 필요한 부분이며, 서버 지연 및 플레이어 이동 속도에 따라, 자신의 게임에 대해 과도하다고 판단할 수 있는 값이 다를 수 있습니다. 이 판단을 내리는 방법을 보여주기 위해, getValidatedBlastData에 print 문을 추가하고 게임을 플레이 테스트하여 일반적인 위치 변화의 크기를 감지할 수 있습니다.

getValidatedBlastData
local distanceFromCharacterToOrigin = blastData.originCFrame.Position - rootPartCFrame.Position
print(distanceFromCharacterToOrigin.Magnitude) -- 업데이트된 줄, 반드시 제거
if distanceFromCharacterToOrigin.Magnitude > ToleranceValues.DISTANCE_SANITY_CHECK_TOLERANCE_STUDS then
warn(`Player {player.Name} failed an origin sanity check while blasting`)
return
end

이동하고 폭발할 때 출력 결과를 주목하십시오. 다음과 같은 결과가 나올 수 있습니다:

1.9019629955291748
3.1549558639526367
2.5742883682250977
4.8044586181640625
2.6434271335601807

ReplicatedStoragePlayerStateHandlertogglePlayerMovement에서 플레이어의 이동 속도를 증가시키면, 다시 플레이 테스트를 진행할 때 폭발 간 과도한 이동으로 인해 많은 실패한 체크를 경험할 수 있습니다.

togglePlayerMovement
local ENABLED_WALK_SPEED = 60 -- 업데이트된 줄, 반드시 되돌리기

서버는 다음을 수행합니다:

  • rayResults를 검증합니다.
  • 플레이어가 폭발할 수 있는지 확인합니다.
  • 블래스터 상태를 재설정합니다.
  • 태그된 플레이어의 체력을 감소시킵니다.
  • 모든 다른 플레이어에게 폭발을 복제하여 3인칭 시각 효과를 볼 수 있도록 합니다.

이러한 서버 작업에 대한 자세한 내용은 튜토리얼의 충돌 감지 섹션을 참조하십시오.

블래스터 재설정

샘플 레이저 태그 게임에서 블래스터는 열 메커니즘을 사용합니다. 정해진 수의 폭발 후 재장전하는 대신, 각 폭발 사이에 "식는" 시간이 필요합니다. 이 쿨다운 지연은 클라이언트(blastClient)와 서버(blastServer) 모두에서 발생하며, 서버가 진실의 출처 역할을 합니다.

blastServer
local blasterConfig = getBlasterConfig(player)
local secondsBetweenBlasts = blasterConfig:GetAttribute("secondsBetweenBlasts")
task.delay(secondsBetweenBlasts, function()
local currentState = player:GetAttribute(PlayerAttribute.blasterStateServer)
if currentState == BlasterState.Blasting then
player:SetAttribute(PlayerAttribute.blasterStateServer, BlasterState.Ready)
end
end)

secondsBetweenBlasts 속성은 ReplicatedStorageInstancesLaserBlastersFolder의 블래스터 구성의 일부입니다. secondsBetweenBlasts 지연이 지나면 플레이어는 다시 폭발할 수 있으며, 전체 프로세스가 반복됩니다. 플레이어가 다시 폭발할 수 있는 시점을 이해할 수 있도록 게임에는 쿨다운 바가 포함되어 있습니다.

이 시점에서 플레이어는 스폰하고 리스폰하며, 조준하고 폭발할 수 있지만, 게임은 여전히 각 폭발의 결과를 결정해야 합니다. 튜토리얼의 다음 섹션에서는 블래스터가 폭발이 다른 플레이어를 맞출 때 이를 감지하고, 블래스터 설정에 따라 적절한 양의 플레이어 체력을 감소시키는 기능을 프로그래밍하는 방법을 배우게 됩니다.

©2026 Roblox Corporation. Roblox 및 Roblox 로고, 'Powering Imagination'은 미국 및 기타 국가 내 당사의 등록 및 미등록 상표입니다.