적중 탐지는 플레이어와 폭발물이 충돌할 때 식별하고 그에 따라 체력을 줄이는 과정입니다. 는 고도의 작업으로 이를 다음과 같이 생각할 수 있습니다.
- 물리적으로 시뮬레이션된 검사는 발사체가 목표물을 타격했는지 여부입니다.
- 블래스터가 대상을 조준했는지 즉시 확인합니다.
사용하는 히트 감지 유형은 경험의 게임 플레이 요구 사항에 따라 다릅니다. 예를 들어, 물리적으로 시뮬레이션된 체크는 공이 특정 속도로 손을 떠나야 하거나, 공이 날아가는 것을 피하거나, 방향을 변경하는 등의 요구 사항에
참조로 사용하는 샘플 레이저 태그 경험 은 3D 공간의 히트 감지 스크립트를 포함하여 다음과 같은 내용을 가르쳐줍니다.
- 현재 카메라 값과 플레이어의 블래스터 입력폭발 방향을 가져옵니다.
- 폭발하는 동안 레이를 직선적으로 쏘아 버리십시오.
- 폭발을 검증하여 블래스터 데이터의 악용을 방지합니다.
- 각 유형의 블래스터의 폭발 공격 및 플레이어에 얼마나 많은 레이가 적중하는지에 따라 플레이어 건강 감소.
이 섹션을 완료한 후 오디오, 조명 및 특수 효과와 같은 게임 플레이를 향상시키기 위한 추가 개발 주제를 탐색할 수 있습니다.
폭발 방향 얻기
플레이어가 그들의 블래스터를 폭발시킨 후, ReplicatedStorage > Blaster > attemptBlastClient > 1> blastClient1> > 4> generateBlastData4> 호출 두 함수를 시작하여 히트 감지 프로세스를 시작합니다: 7>
폭발 데이터 생성
local rayDirections = getDirectionsForBlast(currentCamera.CFrame, blasterConfig)local rayResults = castLaserRay(localPlayer, currentCamera.CFrame.Position, rayDirections)
rayDirections의 입력은 간단합니다. 현재 카메라 위치 및 회전 값, 그리고 플레이어의 블래스터 유형입니다. 샘플 레이저 태그 경험이 단일 레이 빔을 생성하는 블래
그러나 샘플은 넓은 가로 확장을 가진 여러 개의 레이저 빔을 생성하는 추가 블래스터 유형을 제공하므로, getDirectionsForBlast 는 확장 내에서 각 레이저 빔의 각도를 계산해야 합니다.
getDirectionsForBlast
if numLasers == 1 then-- 싱글 레이저는 직선적으로 조준합니다table.insert(directions, originCFrame.LookVector)elseif numLasers > 1 then-- 여러 개의 레이저를 위해 수직으로 균일하게 확산-- 중심 주위의 laserSpreadDegrees 간격local leftAngleBound = laserSpreadDegrees / 2local rightAngleBound = -leftAngleBoundlocal degreeInterval = laserSpreadDegrees / (numLasers - 1)for angle = rightAngleBound, leftAngleBound, degreeInterval dolocal direction = (originCFrame * CFrame.Angles(0, math.rad(angle), 0)).LookVectortable.insert(directions, direction)endend
이 개념을 더 설명하려면, 만약 당신이 넓은 가로 스프레드를 포함하는 셋째 블래스터 유형을 포함한다면, 당신은 새로운 블래스터 특성, 예를 들어 spreadDirection 를 만들 수 있습니다. 그리고
if numLasers == 1 thentable.insert(directions, originCFrame.LookVector)elseif numLasers > 1 thenlocal leftAngleBound = laserSpreadDegrees / 2local rightAngleBound = -leftAngleBoundlocal degreeInterval = laserSpreadDegrees / (numLasers - 1)for angle = rightAngleBound, leftAngleBound, degreeInterval dolocal directionif spreadDirection == "vertical" thendirection = (originCFrame * CFrame.Angles(math.rad(angle), 0, 0)).LookVectorelsedirection = (originCFrame * CFrame.Angles(0, math.rad(angle), 0)).LookVectorendtable.insert(directions, direction)endendreturn directions
궁극적으로, rayDirections() 함수는 각 레이저 빔의 방향을 나타내는 테이블의 Vectors를 반환합니다. 도움이 되면 일부 로깅을 추가하여 이 데이터의 모양을 확인할 수 있습니다.
폭발 데이터 생성
local rayDirections = getDirectionsForBlast(currentCamera.CFrame, blasterConfig)for _, direction in rayDirections do -- 새 줄print(direction) -- 새 줄end -- 새 줄local rayResults = castLaserRay(localPlayer, currentCamera.CFrame.Position, rayDirections)
캐스트 레이
castLaserRay() , 스크립트의 두 번째 함수인 Blaster > attemptBlastClient 이 정보는 플레이어가 환경과 충돌하는 시간과 위치를 볼 수 있기 때문에 특히 유용합니다. 예를 들어, 다음 이미지에서는 두 광선이 서로 병렬로 캐스팅되는 것을 보여 줍니다. 이들 광선의 위치는 원점과 방향
castLaserRay() 매개 변수는 작업 공간의 모든 부품을 고려해야 합니다 Raycast() 호출은 캐릭터가 폭발한 부품을 제외하고 모든 부품을 고려해야 합니다 datatype.raycastResult 테이블에서 각 방향에
- Distance – 광선 원본과 교차 점 사이의 거리.
- Material – 교차 지점에 있는 Enum.Material 입니다.
이 값은 샘플 레이저 태그 경험의 게임플레이에서 가장 중요한 이 속성 중 하나이며, 레이가 다른 플레이어와 충돌할 때 통
castLaserRay() 다음으로 사용 Position 및 Normal 을 사용하여 새
레이저 광선 던지기
if result then-- 폭발이 무언가를 타격했는지 확인하십시오, 그것이 플레이어였는지.destination = CFrame.lookAt(result.Position, result.Position + result.Normal)taggedPlayer = getPlayerFromDescendant(result.Instance)else-- 폭발은 아무것도 타격하지 않았으므로 목적지는-- 최대 거리에 있는 점.local distantPosition = origin + rayDirection * MAX_DISTANCEdestination = CFrame.lookAt(distantPosition, distantPosition - rayDirection)taggedPlayer = nilend
폭발 유효성 검사
악용 방지를 위해 이전 챕터 Blaster 구현 설명하기 어떻게 blastClient 서버를 사용하는
먼저, getValidatedRayResults 는 validateRayResult 를 호출하여 클라이언트의 rayResults 테이블에 있는 각 항목이 1> Datatype.CFrame1> 및 4> Player4> (또는 없음)인지 확인합니다.
다음으로, 이 isRayAngleFromOriginValid 를 호출하여 레이저 확산의 예상 각도를 클라이언트의 각도와 비교합니다. 이 코드는 특히 ReplicatedStorage 를 사용하는 이유를 보여줍니다, 서버가 getDirectionsForBlast 를 직접 호출할
이전 챕터의 블래스터 유효성 검사와 마찬가지로, isRayAngleFromOriginValid는 각도 차이가 "과도한"차이인지 결정하기 위해 관용 값을 기반으로 합니다.
이스레이 앵글 유효local claimedDirection = (rayResult.destination.Position - originCFrame.Position).Unitlocal directionErrorDegrees = getAngleBetweenDirections(claimedDirection, expectedDirection)return directionErrorDegrees <= ToleranceValues.BLAST_ANGLE_SANITY_CHECK_TOLERANCE_DEGREESRoblox는 수학에서 가장 복잡한 부분을 가장 적은 수의 단순하고 재사용 가능한 도우미 함수로 결합하므로 결과는 다양한 경험에 적용할 수 있는 짧은 도우미 함수입니다.
사이에 각도 얻기local function getAngleBetweenDirections(directionA: Vector3, directionB: Vector3)local dotProduct = directionA:Dot(directionB)local cosAngle = math.clamp(dotProduct, -1, 1)local angle = math.acos(cosAngle)return math.deg(angle)end다음 검사는 가장 직관적입니다. 반면 getValidatedBlastData는 DISTANCE_SANITY_CHECK_TOLERANCE_STUDS를 사용하여 플레이어가 빔의 원본 지점에 가까운지 확인하지만, isPlayerNearPosition는 태그된 플레이어가 빔의 목적
이스플레이어 근처 위치local distanceFromCharacterToPosition = position - character:GetPivot().Positionif distanceFromCharacterToPosition.Magnitude > ToleranceValues.DISTANCE_SANITY_CHECK_TOLERANCE_STUDS thenreturn falseend마지막 검사 isRayPathObstructed 는 레이 캐스트 작업의 변형을 사용하여 레이의 대상이 벽 또는 다른 장애물에 뒤처진지 여부를 확인합니다. 예를 들어, 악의적인 플레이어가 환경모든 벽을 제거하여 다른 플레이어를
방해 받은 경로local scaledDirection = (rayResult.destination.Position - blastData.originCFrame.Position)scaledDirection *= (scaledDirection.Magnitude - 1) / scaledDirection.Magnitude
어떤 반 악용 전략도 포괄적이지 않지만, 악의적인 플레이어가 경험에 어떻게 접근하는지 고려하여 서버가 수상한 행동을 검색할 수 있도록 확인을 설정할 수 있습니다.
플레이어 체력 감소
플레이어가 다른 플레이어를 태그한 후 샘플 레이저 태그 경험의 메인 게임플레이 루프를 완료하는 최종 단계는 플레이어의 체력을 줄이고, 리더보드증가하고, 플레이어를 라운드에 다시 참여하도록 하는 것입니다.
시작하여 태그된 플레이어의 체력을 줄이면, 생성 및 재생 은 플레이어가 클래스 Player
경험은 각 블래스터의 damagePerHit 특성에 피해 값을 저
Health 은 부정 값을 수락하지 않으므로 onPlayerTagged 에 몇 가지 로직이 있어 플레이어 건강을 위에 또는 아래로 유지합니다. 플레이어 건강이 위에
이 문제에 접근하는 방식은 약간 복잡해 보일 수 있습니다. 예를 들어, 플레이어 건강을 음수로 설정하면 왜 단순히 플레이어 건강을 0으로 설정하지 않는가? 이유는 건강 값이 포스 필드를 회피하기 때문입니다. Humanoid:TakeDamage() 메서드를 사용하면 플레
플레이어 태그
local function onPlayerTagged(playerBlasted: Player, playerTagged: Player, damageAmount: number)
local character = playerTagged.Character
local isFriendly = playerBlasted.Team == playerTagged.Team
-- 친절한 불 허용 금지
if isFriendly then
return
end
local humanoid = character and character:FindFirstChild("Humanoid")
if humanoid and humanoid.Health > 0 then
-- 부정 건강 피하기
local damage = math.min(damageAmount, humanoid.Health)
-- ForceField가 활성화되어 있으면 피해량 감소 없이 체력이 유지됩니다.TakeDamage ensures health is not lowered if ForceField is active
humanoid:TakeDamage(damage)
if humanoid.Health <= 0 then
-- PlayerBlasted 플레이어에게 태그 표시 기록을 부여했습니다.
Scoring.incrementScore(playerBlasted, 1)
end
end
end
다음 단계는 순위 리더보드증가시키는 것입니다. 플레이어가 폭발 데이터와 함께 폭발 한 것으로 보이지 않았던 경우에도 경험은 플레이어에게 태그를 할 수 없습니다. 마찬가지로, 태그 된 플레이어는 라운드에 다시 순위 보드
이 교육 과정의 5개 챕터는 경험의 핵심 게임 플레이 루프를 다룹니다. 하지만 여전히 탐색할 수 있는 많은 영역이 있습니다. 예를 들어:
- Blaster 시각화 : 참조 ReplicatedStorage > FirstPersonBlasterVisuals 및 0> ServerScriptService0> > 3> ThirdPersonBlasterVisuals 3> .
- 오디오 : 음향 처리기 ReplicatedStorage > SoundHandler 참조.
- 사용자 지정 모드 : 시간이 다 될 때까지 가장 많은 점수를 획득하는 등의 새로운 유형의 목표를 소개하기 위해 경험을 수정하는 방법?
레이저 태그 경험에 대한 확장된 게임 로직, 재사용 가능한 고품질 환경 자산을 위해 레이저 태그 템플릿을 검토하십시오.