레이저로 타격 감지

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

이 자습서에서는 플레이어 도구 생성에서 레이저를 발사하고 플레이어를 타격하는지 여부를 감지하는 방법을 배웁니다.

충돌 찾기를 위한 레이캐스팅

레이캐스팅 은 정의된 길이로 시작 위치에서 지정된 방향으로 투명한 광선을 생성합니다.레이가 경로에 있는 개체나 지형과 충돌하면 위치와 충돌한 개체와 같은 충돌 정보가 반환됩니다.

A에서 B로 방사되어 벽과 충돌하는 레이캐스트

마우스 위치 찾기

레이저를 발사하기 전에 플레이어가 어디를 조준하고 있는지 먼저 알아야 합니다.이는 카메라로부터 바로 화면에서 플레이어의 2D 마우스 위치로 레이캐스팅하여 게임 세계로 찾을 수 있습니다.레이는 플레이어가 마우스로 조준하는 대상과 충돌합니다.

  1. 블래스터 도구에서 도구 컨트롤러 스크립트를 열어 플레이어 도구 생성합니다.아직 해당 자습서를 완료하지 않았다면 블래스터 모델을 다운로드하고 스타터 팩에 삽입할 수 있습니다.

  2. 스크립트 상단에서 MAX_MOUSE_DISTANCE라는 상수를 값 1000 으로 선언합니다.

  3. 함수 getWorldMousePosition.


    local tool = script.Parent
    local MAX_MOUSE_DISTANCE = 1000
    local function getWorldMousePosition()
    end
    local function toolEquipped()
    tool.Handle.Equip:Play()
    end
    local function toolActivated()
    tool.Handle.Activate:Play()
    end
    -- 이벤트를 적절한 함수에 연결하기
    tool.Equipped:Connect(toolEquipped)
    tool.Activated:Connect(toolActivated)
  4. UserInputService의 GetMouseLocation 함수를 사용하여 화면에서 플레이어의 2D 마우스 위치를 가져옵니다.이를 마우스 위치 라는 변수에 할당합니다.


    local UserInputService = game:GetService("UserInputService")
    local tool = script.Parent
    local MAX_MOUSE_DISTANCE = 1000
    local function getWorldMousePosition()
    local mouseLocation = UserInputService:GetMouseLocation()
    end

이제 2D 마우스 위치가 알려졌으므로, X 및 Y 속성이 3D 게임 세계로 화면에서 생성되는 함수의 매개변수로 사용될 수 있습니다.

  1. X 및 Y 속성을 사용하여 함수의 인수로 사용합니다.이를 스크린투월드레이 라는 변수에 할당합니다.


    local function getWorldMousePosition()
    local mouseLocation = UserInputService:GetMouseLocation()
    -- 2D 마우스 위치에서 광선 생성
    local screenToWorldRay = workspace.CurrentCamera:ViewportPointToRay(mouseLocation.X, mouseLocation.Y)
    end

레이가 개체에 닿는지 확인하기 위해 Raycast 함수를 사용할 시간입니다.이를 위해 시작 위치 및 방향 벡터가 필요합니다: 이 예제에서는 screenToWorldRay의 원점 및 방향 속성을 사용합니다.

방향 벡터의 길이는 광선이 이동하는 거리를 결정합니다.광선은 MAX_MOUSE_DISTANCE만큼 길어야 하므로 방향 벡터를 MAX_MOUSE_DISTANCE로 곱해야 합니다.

  1. 변수 directionVector 의 이름을 선언하고 값을 곱한 값으로 할당합니다.


    local function getWorldMousePosition()
    local mouseLocation = UserInputService:GetMouseLocation()
    -- 2D 마우스 위치에서 광선 생성
    local screenToWorldRay = workspace.CurrentCamera:ViewportPointToRay(mouseLocation.X, mouseLocation.Y)
    -- 광선의 단위 방향 벡터가 최대 거리로 곱해진 값
    local directionVector = screenToWorldRay.Direction * MAX_MOUSE_DISTANCE
  2. 작업 영역의 함수를 호출하여 Origin 속성을 첫 번째 인수로 전달하고 을 두 번째 인수로 전달합니다.이를 raycastResult 라는 변수에 할당합니다.


    local function getWorldMousePosition()
    local mouseLocation = UserInputService:GetMouseLocation()
    -- 2D 마우스 위치에서 광선 생성
    local screenToWorldRay = workspace.CurrentCamera:ViewportPointToRay(mouseLocation.X, mouseLocation.Y)
    -- 광선의 단위 방향 벡터가 최대 거리로 곱해진 값
    local directionVector = screenToWorldRay.Direction * MAX_MOUSE_DISTANCE
    -- 광선의 원점에서 광선 방향으로 레이캐스트
    local raycastResult = workspace:Raycast(screenToWorldRay.Origin, directionVector)

충돌 정보

레이캐스트 작업이 레이에 의해 타격된 개체를 찾으면, 레이와 개체 간의 충돌 정보가 포함된 RaycastResult를 반환합니다.

레이캐스트 결과 속성설명
인스턴스레이가 교차한 세포의 BasePart 또는 Terrain 셀.
위치교차점이 발생한 위치; 일반적으로 부품이나 지형의 표면에 직접 있는 지점입니다.
재료충돌 지점의 재료.
일반교차된 얼굴의 일반 벡터. 이를 사용하여 얼굴이 가리키는 방향을 결정할 수 있습니다.

위치 속성은 마우스가 눌려 있는 개체의 위치가 됩니다.마우스가 거리의 내에 있는 어떤 개체 위로 호버하지 않으면 가 됩니다.

  1. if 문을 만들어 raycastResult 가 존재하는지 확인합니다.

  2. raycastResult 에 값이 있으면 해당 위치 속성을 반환합니다.

  3. if raycastResultnil 이면 레이캐스트의 끝을 찾습니다.screenToWorldRay.OrigindirectionVector을 함께 추가하여 마우스의 3D 위치를 계산합니다.


local function getWorldMousePosition()
local mouseLocation = UserInputService:GetMouseLocation()
-- 2D 마우스 위치에서 광선 생성
local screenToWorldRay = workspace.CurrentCamera:ViewportPointToRay(mouseLocation.X, mouseLocation.Y)
-- 광선의 단위 방향 벡터가 최대 거리로 곱해진 값
local directionVector = screenToWorldRay.Direction * MAX_MOUSE_DISTANCE
-- 광선의 원점에서 광선 방향으로 레이캐스트
local raycastResult = workspace:Raycast(screenToWorldRay.Origin, directionVector)
if raycastResult then
-- 교차 지점의 3D 포인트 반환
return raycastResult.Position
else
-- 대상이 없으므로 광선 끝에서 위치를 계산하지 않습니다
return screenToWorldRay.Origin + directionVector
end
end

대상에 불 발사

이제 3D 마우스 위치가 알려졌으므로 레이저를 발사하기 위한 타겟 위치 로 사용할 수 있습니다두 번째 광선은 레이캐스트 함수를 사용하여 플레이어의 무기와 대상 위치 사이에 캐스트할 수 있습니다.

  1. 스크립트 상단에서 상수 MAX_LASER_DISTANCE 를 선언하고 500 또는 레이저 블래스터에 대한 선택한 범위에 할당합니다.


    local UserInputService = game:GetService("UserInputService")
    local tool = script.Parent
    local MAX_MOUSE_DISTANCE = 1000
    local MAX_LASER_DISTANCE = 500
  2. fireWeapon 이라는 함수를 getWorldMousePosition 함수 아래에 만듭니다.

  3. 호출 getWorldMousePosition 및 결과를 마우스 위치 라는 변수에 할당합니다. 이것은 레이캐스트의 대상 위치가 될 것입니다.


    -- 대상이 없으므로 광선 끝에서 위치를 계산하지 않습니다
    return screenToWorldRay.Origin + directionVector
    end
    end
    local function fireWeapon()
    local mouseLocation = getWorldMousePosition()
    end
    local function toolEquipped()
    tool.Handle.Equip:Play()
    end

이번에는 레이캐스트 함수의 방향 벡터가 플레이어의 도구 위치에서 대상 위치까지의 방향을 나타냅니다.

  1. 변수 targetDirection 의 이름을 선언하고 도구 위치를 뺀 후 방향 벡터를 계산합니다 mouseLocation.

  2. 유닛 속성을 사용하여 벡터를 정규화합니다. 이렇게 하면 나중에 길이로 곱하기가 쉬워지며 1의 크기가 생깁니다.


    local function fireWeapon()
    local mouseLocation = getWorldMousePosition()
    -- 정규화된 방향 벡터를 계산하고 레이저 거리로 곱하기
    local targetDirection = (mouseLocation - tool.Handle.Position).Unit
    end
  3. 변수 directionVector 를 선언하고 그에게 targetDirection를 곱한 MAX_LASER_DISTANCE로 할당합니다.


    local targetDirection = (mouseLocation - tool.Handle.Position).Unit
    -- 무기를 발사하는 방향, 최대 거리로 곱한
    local directionVector = targetDirection * MAX_LASER_DISTANCE
    end

A RaycastParams 개체는 광선 캐스트 함수에 대한 추가 매개변수를 저장하는 데 사용할 수 있습니다.레이저 블래스터에서 레이캐스트가 무기를 발사하는 플레이어와 우연히 충돌하지 않도록 사용됩니다.레이캐스트Params 개체의 FilterDescendantsInstances에 포함된 모든 부품은 레이캐스트에서 무시됩니다 .

  1. fireWeapon 함수를 계속하고 weaponRaycastParams 이라는 변수를 선언하십시오. 새 RaycastParams 개체를 할당하십시오.

  2. 플레이어의 로컬 문자 를 포함하는 테이블을 생성하고 속성 weaponRaycastParams.FilterDescendantsInstances 할당합니다.

  3. 플레이어의 도구 핸들 위치에서 방사, 방향은 directionVector 입니다.이번에는 인수로 weaponRaycastParams를 추가하는 것을 잊지 마세요.이를 weaponRaycastResult 라는 변수에 할당합니다.


local UserInputService = game:GetService("UserInputService")
local Players = game:GetService("Players")
local tool = script.Parent
local MAX_MOUSE_DISTANCE = 1000
local MAX_LASER_DISTANCE = 500
local function getWorldMousePosition()

local function fireWeapon()
local mouseLocation = getWorldMousePosition()
-- 정규화된 방향 벡터를 계산하고 레이저 거리로 곱하기
local targetDirection = (mouseLocation - tool.Handle.Position).Unit
-- 무기를 발사할 방향과 최대 거리를 곱한 값
local directionVector = targetDirection * MAX_LASER_DISTANCE
-- 플레이어의 캐릭터를 무시하여 스스로 손상되는 것을 방지합니다
local weaponRaycastParams = RaycastParams.new()
weaponRaycastParams.FilterDescendantsInstances = {Players.LocalPlayer.Character}
local weaponRaycastResult = workspace:Raycast(tool.Handle.Position, directionVector, weaponRaycastParams)
end

마지막으로, 레이캐스트 작업이 값을 반환했는지 확인해야 합니다.값이 반환되면 레이에 의해 개체가 타격되었고 무기와 타격 위치 사이에 레이저를 생성할 수 있습니다.아무것도 반환되지 않으면 레이저를 생성하기 위해 최종 위치를 계산해야 합니다.

  1. 공백 변수 hitPosition 을 선언합니다.

  2. Use an if 문을 사용하여 값이 있는지 여부를 확인합니다. 만약 개체가 타격되었다면, 에 를 할당하십시오.


    local weaponRaycastResult = workspace:Raycast(tool.Handle.Position, directionVector, weaponRaycastParams)
    -- 시작 위치와 끝 위치 사이에서 개체가 타격되었는지 확인
    local hitPosition
    if weaponRaycastResult then
    hitPosition = weaponRaycastResult.Position
    end
  3. weaponRaycastResult 에 값이 없으면 도구 핸들의 위치directionVector 를 함께 추가하여 레이캐스트의 끝 위치를 계산합니다.이를 hitPosition 에 할당합니다.


    local weaponRaycastResult = workspace:Raycast(tool.Handle.Position, directionVector, weaponRaycastParams)
    -- 시작 위치와 끝 위치 사이에서 개체가 타격되었는지 확인
    local hitPosition
    if weaponRaycastResult then
    hitPosition = weaponRaycastResult.Position
    else
    -- 최대 레이저 거리에 따라 최종 위치 계산
    hitPosition = tool.Handle.Position + directionVector
    end
    end
  4. toolActivated 함수로 이동하고 도구가 활성화될 때마다 레이저가 발사되도록 fireWeapon 함수를 호출하십시오.


    local function toolActivated()
    tool.Handle.Activate:Play()
    fireWeapon()
    end

개체 타격 확인

레이저에 의해 타격된 개체가 플레이어의 캐릭터인지 아니면 풍경의 일부인지 찾으려면 Humanoid를 찾아야 하며, 모든 캐릭터에 하나씩 있기 때문입니다.

먼저, 문자 모델 을 찾아야 합니다.문자의 일부가 타격을 받으면 타격된 개체의 부모가 문자가 될 것이라고 가정할 수 없습니다.레이저는 신체 부위, 장신구또는 도구를 칠 수 있었으며, 이들은 모두 캐릭터의 계층에서 다른 부분에 위치했습니다.

레이저에 의해 타격된 개체의 캐릭터 모델 조상을 찾으려면 FindFirstAncestorOfClass를 사용할 수 있습니다. 하나 존재하는 경우.모델을 찾아 인간형이 포함되어 있으면, 대부분의 경우 그것이 캐릭터라고 가정할 수 있습니다.

  1. 강조 표시된 코드를 아래의 weaponRaycastResult if 문에 추가하여 문자가 타격되었는지 확인합니다.


    -- 시작 위치와 끝 위치 사이에서 개체가 타격되었는지 확인
    local hitPosition
    if weaponRaycastResult then
    hitPosition = weaponRaycastResult.Position
    -- 인스턴스 타격은 캐릭터 모델의 자식이 될 것입니다
    -- 모델에 휴머노이드가 발견되면 플레이어의 캐릭터일 가능성이 높습니다
    local characterModel = weaponRaycastResult.Instance:FindFirstAncestorOfClass("Model")
    if characterModel then
    local humanoid = characterModel:FindFirstChildWhichIsA("Humanoid")
    if humanoid then
    print("Player hit")
    end
    end
    else
    -- 최대 레이저 거리에 따라 최종 위치 계산
    hitPosition = tool.Handle.Position + directionVector
    end

이제 레이저 블래스터는 레이캐스트 작업이 다른 플레이어에 도달할 때마다 출력 창에 Player hit를 인쇄해야 합니다.

여러 플레이어로 테스트

무기 레이캐스트가 다른 플레이어를 찾고 있는지 테스트하려면 두 명의 플레이어가 필요하므로 로컬 서버를 시작해야 합니다.

  1. Studio에서 테스트 탭을 선택합니다.

  2. 플레이어 드롭다운이 '2명'으로 설정되어 있고 시작 버튼을 클릭하여 로컬 서버를 2개의 클라이언트로 시작 합니다.세 개의 창이 나타납니다.첫 번째 창은 로컬 서버가 될 것이고, 다른 창은 Player1과 Player2의 클라이언트가 됩니다.

  3. 한 클라이언트에서 무기를 클릭하여 다른 플레이어를 테스트 촬영합니다.플레이어가 쏘일 때마다 출력에 "플레이어 타격"이 표시되어야 합니다.

여기에서 테스트 탭에 대해 자세히 알아볼 수 있습니다. 여기.

레이저 위치 찾기

레이저는 대상에 빨간색 광선을 발사해야 합니다.이를 위한 함수는 내부에 있는 ModuleScript 이므로 나중에 다른 스크립트에서 재사용할 수 있습니다.먼저 스크립트는 레이저 빔이 렌더링되어야 하는 위치를 찾아야 합니다.

  1. Create a 모듈 스크립트 named 레이저 렌더러 , parented to StarterPlayerScripts under StarterPlayer.

  2. 스크립트를 열고 모듈 테이블의 이름을 스크립트의 이름으로 바꿉니다 LaserRenderer .

  3. 변수 SHOT_DURATION 의 값으로 값을 0.15 로 지정하여 변수를 선언합니다.레이저가 표시되는 시간(초)입니다.

  4. LaserRenderer라는 함수를 생성하여 createLaser 라는 이름으로 두 매개변수인 toolHandleendPosition 을 사용하여 생성합니다.


    local LaserRenderer = {}
    local SHOT_DURATION = 0.15 -- 레이저가 표시되는 시간
    -- 시작 위치에서 끝 위치까지 레이저 빔 생성
    function LaserRenderer.createLaser(toolHandle, endPosition)
    end
    return LaserRenderer
  5. 변수 startPosition 의 이름을 선언하고 Position 속성을 toolHandle의 값으로 설정합니다.이것은 플레이어의 레이저 블래스터 위치가 될 것입니다.

  6. 변수 laserDistance 를 선언하고 차감 endPosition에서 startPosition에서 두 벡터 간의 차이를 찾으십시오.이 요소의 크기 속성을 사용하여 레이저 빔의 길이를 얻습니다.


    function LaserRenderer.createLaser(toolHandle, endPosition)
    local startPosition = toolHandle.Position
    local laserDistance = (startPosition - endPosition).Magnitude
    end
  7. 레이저 빔의 위치와 방향을 저장하기 위해 lasercFrame 변수를 선언합니다.위치는 빔의 시작과 끝의 중간점이어야 합니다. CFrame.lookAt 를 사용하여 새로운 CFrame를 생성하고 위치는 startPosition이고 향하는 방향은 endPosition입니다.이를 음의 절반인 Z축 값을 가진 새 CFrame로 곱하여 중간점을 얻습니다.


    function LaserRenderer.createLaser(toolHandle, endPosition)
    local startPosition = toolHandle.Position
    local laserDistance = (startPosition - endPosition).Magnitude
    local laserCFrame = CFrame.lookAt(startPosition, endPosition) * CFrame.new(0, 0, -laserDistance / 2)
    end

레이저 부품 생성

이제 레이저 빔을 생성할 위치를 알았으므로 빔 자체를 추가해야 합니다. 네온 부품으로 쉽게 수행할 수 있습니다.

  1. 변수 레이저 파트 를 선언하고 새로운 Part를 할당합니다.

  2. 다음 속성을 laserPart에 설정하십시오:

    1. 크기 : Vector3.new(0.2, 0.2, 레이저거리)
    2. CFrame : 레이저CFrame
    3. 고정되었습니다 : true
    4. CanCollide : 거부
    5. 색상 : Color3.fromRGB(225, 0, 0) (강한 빨간색)
    6. 재료 : Enum.Material.Neon
  3. 부모 laserPart 에서 작업 공간 으로.

  4. 부품을 Debris 서비스에 추가하여 변수 SHOT_DURATION의 초 수 후에 제거되도록 함


    function LaserRenderer.createLaser(toolHandle, endPosition)
    local startPosition = toolHandle.Position
    local laserDistance = (startPosition - endPosition).Magnitude
    local laserCFrame = CFrame.lookAt(startPosition, endPosition) * CFrame.new(0, 0, -laserDistance / 2)
    local laserPart = Instance.new("Part")
    laserPart.Size = Vector3.new(0.2, 0.2, laserDistance)
    laserPart.CFrame = laserCFrame
    laserPart.Anchored = true
    laserPart.CanCollide = false
    laserPart.Color = Color3.fromRGB(225, 0, 0)
    laserPart.Material = Enum.Material.Neon
    laserPart.Parent = workspace
    -- 제거되고 정리될 폐기물 서비스에 레이저 빔 추가
    Debris:AddItem(laserPart, SHOT_DURATION)
    end

이제 레이저 빔을 렌더링하는 함수가 완료되었으므로 ToolController 에서 호출할 수 있습니다.

  1. 도구 컨트롤러 스크립트의 상단에서 변수 LaserRenderer 의 이름을 선언하고 PlayerScripts에 있는 LaserRenderer 모듈 스크립트를 요구합니다.


    local UserInputService = game:GetService("UserInputService")
    local Players = game:GetService("Players")
    local LaserRenderer = require(Players.LocalPlayer.PlayerScripts.LaserRenderer)
    local tool = script.Parent
  2. fireWeapon 함수의 바닥에서 도구 핸들과 createLaserhitPosition을 인수로 사용하여 LaserRenderer 함수를 호출하십시오.


    -- 최대 레이저 거리에 따라 최종 위치 계산
    hitPosition = tool.Handle.Position + directionVector
    end
    LaserRenderer.createLaser(tool.Handle, hitPosition)
    end
  3. 플레이 버튼을 클릭하여 무기를 테스트하십시오. 도구가 활성화되면 무기와 마우스 사이에 레이저 빔이 표시되어야 합니다.

무기 발사 속도 평가

무기는 각 발사 사이에 지연이 필요하며, 플레이어가 짧은 시간에 너무 많은 피해를 입히지 않도록 합니다.플레이어가 마지막으로 발사한 시간이 충분히 지났는지 확인하여 이를 제어할 수 있습니다.

  1. 변수를 선언하여 도구 컨트롤러 의 맨 위에서 화재 속도 라고 불리는 변수를 호출합니다.이것은 각 샷 사이의 최소 시간이 될 것입니다.선택한 값을 부여하십시오; 이 예에서는 0.3 초가 사용됩니다.

  2. 다른 변수를 아래에 선언하여 timeOfPreviousShot 의 값으로 0 을 사용합니다.이는 플레이어가 발사한 마지막 시간을 저장하고 각 샷마다 업데이트됩니다.


    local MAX_MOUSE_DISTANCE = 1000
    local MAX_LASER_DISTANCE = 300
    local FIRE_RATE = 0.3
    local timeOfPreviousShot = 0
  3. 매개 변수가 없는 canShootWeapon 이라는 함수를 만듭니다.이 함수는 이전 샷이 발사된 이후 지난 시간을 살펴보고 진실 또는 거짓을 반환합니다.


    local FIRE_RATE = 0.3
    local timeOfPreviousShot = 0
    -- 이전 발사 후 충분한 시간이 지났는지 확인
    local function canShootWeapon()
    end
    local function getWorldMousePosition()
  4. 함수 내에서 변수 currentTime 을 선언하고; tick() 함수를 호출하는 결과를 할당합니다.이는 1970년 1월 1일(시간을 계산하는 데 널리 사용되는 임의의 날짜) 이후, 초 단위로 경과한 시간을 반환합니다.

  5. 결과가 보다 작으면 에서 뺀 후 반환하고, 그렇지 않으면 true 를 반환합니다.


    -- 이전 발사 후 충분한 시간이 지났는지 확인
    local function canShootWeapon()
    local currentTime = tick()
    if currentTime - timeOfPreviousShot < FIRE_RATE then
    return false
    end
    return true
    end
  6. 함수가 끝날 때, 무기가 를 사용하여 발사될 때마다 업데이트합니다.


    hitPosition = tool.Handle.Position + directionVector
    end
    timeOfPreviousShot = tick()
    LaserRenderer.createLaser(tool.Handle, hitPosition)
    end
  7. toolActivated 함수 내에서 if 문을 생성하고 canShootWeapon 호출하여 무기를 발사할 수 있는지 확인합니다.


    local function toolActivated()
    if canShootWeapon() then
    tool.Handle.Activate:Play()
    fireWeapon()
    end
    end

블래스터를 테스트할 때 클릭 속도가 얼마나 빠르든 상관없이 항상 각 발사 사이에 짧은 0.3초 지연이 발생할 것임을 알아야 합니다.

플레이어 손상

클라이언트는 다른 클라이언트를 직접 손상시킬 수 없으며; 플레이어가 타격될 때 서버가 손상을 발행해야 합니다.

클라이언트는 RemoteEvent를 사용하여 서버에 캐릭터가 타격당했음을 알릴 수 있습니다.이는 클라이언트와 서버 모두에게 표시되는 ReplicatedStorage 에 저장되어야 합니다.

  1. ReplicatedStorage의 폴더이벤트 라는 이름으로 생성합니다.

  2. 원격 이벤트를 이벤트 폴더에 삽입하고 이름을 손상 캐릭터 로 지정합니다.

  3. In 도구 컨트롤러 , ReplicatedStorage 및 이벤트 폴더의 스크립트 시작 시 변수를 만듭니다.


    local UserInputService = game:GetService("UserInputService")
    local Players = game:GetService("Players")
    local ReplicatedStorage = game:GetService("ReplicatedStorage")
    local LaserRenderer = require(Players.LocalPlayer.PlayerScripts.LaserRenderer)
    local tool = script.Parent
    local eventsFolder = ReplicatedStorage.Events
    local MAX_MOUSE_DISTANCE = 1000
    local MAX_LASER_DISTANCE = 500
  4. "Player hit" 프린트 문을 fireWeapon 에 Luau 라인으로 교체하여 피해 캐릭터 원격 이벤트를 발생시키고 변수 characterModel 을 인수로 사용합니다.


    local characterModel = weaponRaycastResult.Instance:FindFirstAncestorOfClass("Model")
    if characterModel then
    local humanoid = characterModel:FindFirstChildWhichIsA("Humanoid")
    if humanoid then
    eventsFolder.DamageCharacter:FireServer(characterModel)
    end
    end
    else
    -- 최대 레이저 거리에 따라 최종 위치 계산
    hitPosition = tool.Handle.Position + directionVector
    end

서버는 이벤트가 발생했을 때 타격을 받은 플레이어에게 피해를 입혀야 합니다.

  1. 서버스크립트서비스에 스크립트 를 삽입하고 이름을 서버레이저관리자 로 지정합니다.

  2. 변수 LASER_DAMAGE 를 선언하고 10 또는 선택한 값으로 설정하십시오.

  3. 함수 damageCharacter 를 생성하여 두 개의 매개변수인 playerFiredcharacterToDamage 를 사용합니다.

  4. 함수 내에서 캐릭터의 휴머노이드를 찾아 체력에서 LASER_DAMAGE를 뺍니다.

  5. damageCharacter 함수를 이벤트 폴더의 DamageCharacter 원격 이벤트에 연결하십시오.


    local ReplicatedStorage = game:GetService("ReplicatedStorage")
    local eventsFolder = ReplicatedStorage.Events
    local LASER_DAMAGE = 10
    function damageCharacter(playerFired, characterToDamage)
    local humanoid = characterToDamage:FindFirstChildWhichIsA("Humanoid")
    if humanoid then
    -- 캐릭터에서 건강 제거
    humanoid.Health -= LASER_DAMAGE
    end
    end
    -- 이벤트를 적절한 함수에 연결하기
    eventsFolder.DamageCharacter.OnServerEvent:Connect(damageCharacter)
  6. 로컬 서버를 시작하여 2명의 플레이어로 블래스터를 테스트하십시오.다른 플레이어를 쏘면 그들의 체력이 LASER_DAMAGE에 할당된 숫자만큼 감소합니다.

다른 플레이어의 레이저 빔 렌더링

현재 레이저 빔은 무기를 발사하는 클라이언트가 생성하므로 오직 그들만 레이저 빔을 볼 수 있습니다.

서버에 레이저 빔이 생성되면 모든 사람이 볼 수 있습니다.그러나 클라이언트가 무기를 발사하고 서버가 샷에 대한 정보를 받는 사이에 약간의 지연이 있을 것입니다.이는 클라이언트가 무기를 발사하면 무기를 활성화하고 레이저 빔을 보는 시간 사이에 지연이 발생한다는 것을 의미하며, 결과적으로 무기가 느린 느낌을 받을 것입니다.

이 문제를 해결하기 위해 각 클라이언트는 자체 레이저 빔을 생성합니다.즉, 무기를 발사하는 클라이언트가 즉시 레이저 빔을 볼 것입니다.다른 클라이언트는 다른 플레이어가 발사하고 빔이 나타나는 시간 사이에 약간의 지연을 경험합니다.이는 최상의 시나리오입니다: 다른 클라이언트에 레이저를 더 빠르게 전달할 수 있는 방법은 없습니다.

사격수의 클라이언트

먼저 클라이언트는 서버에 레이저를 발사했으며 종점 위치를 제공했다고 알려야 합니다.

  1. ReplicatedStorage의 이벤트 폴더에 원격 이벤트 를 삽입하고 이름을 레이저 발사 로 지정합니다.

  2. 도구 컨트롤러 스크립트에서 함수를 찾으십시오.함수가 끝나면 LaserFired 원격 이벤트를 인수로 사용하여 hitPosition 을 사용하여 원격 이벤트를 발사합니다.


    hitPosition = tool.Handle.Position + directionVector
    end
    timeOfPreviousShot = tick()
    eventsFolder.LaserFired:FireServer(hitPosition)
    LaserRenderer.createLaser(tool.Handle, hitPosition)
    end

서버

이제 서버는 클라이언트가 발사한 이벤트를 수신하고 모든 클라이언트에게 레이저 빔의 시작 및 끝 위치를 알려 그들도 렌더링할 수 있어야 합니다.

  1. 서버 레이저 관리자 스크립트에서 playerFiredLaser 라는 함수를 생성하여 두 개의 매개변수인 **** 및 damageCharacter 를 사용하여 위의 playerFiredendPosition 와 함께 작동합니다.

  2. 함수를 LaserFired 원격 이벤트에 연결합니다.


    -- 레이저가 발사되었음을 모든 클라이언트에 알려 레이저를 표시할 수 있도록 함
    local function playerFiredLaser(playerFired, endPosition)
    end

    -- 이벤트를 적절한 함수에 연결하기
    eventsFolder.DamageCharacter.OnServerEvent:Connect(damageCharacter)
    eventsFolder.LaserFired.OnServerEvent:Connect(playerFiredLaser)

서버는 레이저의 시작 위치가 필요합니다.클라이언트에서 보낼 수도 있지만, 가능하면 클라이언트를 신뢰하지 않는 것이 좋습니다.캐릭터의 무기 핸들 위치가 시작 위치이므로 서버에서 거기에서 찾을 수 있습니다.

  1. 함수 getPlayerToolHandle 위에 매개변수 playerFiredLaser 라고 불리는 함수를 만들어 player 함수 위에 있습니다.

  2. 다음 코드를 사용하여 플레이어의 캐릭터를 검색하여 무기를 반환하고 핸들 개체를 반환합니다.


    local LASER_DAMAGE = 10
    -- 플레이어가 보유하고 있는 도구의 핸들 찾기
    local function getPlayerToolHandle(player)
    local weapon = player.Character:FindFirstChildOfClass("Tool")
    if weapon then
    return weapon:FindFirstChild("Handle")
    end
    end
    -- 레이저가 발사되었음을 모든 클라이언트에 알려 레이저를 표시할 수 있도록 함
    local function playerFiredLaser(playerFired, endPosition)

서버는 이제 FireAllClients 를 레이저 발사 원격 이벤트에 호출하여 레이저를 클라이언트에 렌더링하는 데 필요한 정보를 보낼 수 있습니다.여기에는 레이저를 발사한 플레이어 (그래서 해당 플레이어의 클라이언트는 레이저를 두 번 렌더링하지 않음), 레이저의 핸들 (레이저의 시작 위치로 작용) 및 레이저의 끝 위치가 포함됩니다.

  1. 함수에서 함수를 인수로 호출하고 을 변수 이름으로 지정된 값으로 할당하여 도구 핸들이라는 변수에 값을 할당합니다.

  2. toolHandle 가 존재하면 playerFired , toolHandleendPosition 을 인수로 사용하는 모든 클라이언트에 대해 LaserFired 이벤트를 발사합니다.


    -- 레이저가 발사되었음을 모든 클라이언트에 알려 레이저를 표시할 수 있도록 함
    local function playerFiredLaser(playerFired, endPosition)
    local toolHandle = getPlayerToolHandle(playerFired)
    if toolHandle then
    eventsFolder.LaserFired:FireAllClients(playerFired, toolHandle, endPosition)
    end
    end

클라이언트에서 렌더링

이제 FireAllClients 가 호출되었으므로 각 클라이언트는 서버에서 이벤트를 받아 레이저 빔을 렌더링합니다.각 클라이언트는 도구의 핸들 위치와 끝 위치 값을 통해 서버에서 전송된 레이저 빔을 렌더링하기 위해 이전에 사용된 LaserRenderer 모듈을 재사용할 수 있습니다.레이저 빔을 처음 발사한 플레이어는 이 이벤트를 무시해야 하고 그렇지 않으면 2개의 레이저를 볼 것입니다.

  1. 스타터플레이어스크립트에 LocalScript 를 생성하여 ClientLaserManager 라고 불러오세요.

  2. 스크립트 내에서 LaserRenderer 모듈을 요구합니다.

  3. 매개 변수 createPlayerLaser , playerWhoShotendPosition 을 사용하여 toolHandle라는 함수를 만듭니다.

  4. 함수를 이벤트 폴더의 LaserFired 원격 이벤트에 연결합니다.

  5. 함수에서는 if 문을 사용하여 로컬플레이어가 같지 않은지 확인합니다.

  6. if 문 내에서 createLaser 함수를 사용하여 toolHandleendPosition 을 인수로 사용하여 LaserRenderer 모듈에서 호출하십시오.


    local Players = game:GetService("Players")
    local ReplicatedStorage = game:GetService("ReplicatedStorage")
    local LaserRenderer = require(script.Parent:WaitForChild("LaserRenderer"))
    local eventsFolder = ReplicatedStorage.Events
    -- 다른 플레이어의 레이저 표시
    local function createPlayerLaser(playerWhoShot, toolHandle, endPosition)
    if playerWhoShot ~= Players.LocalPlayer then
    LaserRenderer.createLaser(toolHandle, endPosition)
    end
    end
    eventsFolder.LaserFired.OnClientEvent:Connect(createPlayerLaser)
  7. 로컬 서버를 시작하여 2명의 플레이어로 블래스터를 테스트하십시오.모니터의 다른 쪽에 각 클라이언트를 배치하여 한 번에 두 창을 모두 볼 수 있습니다.한 클라이언트에서 촬영할 때 다른 클라이언트에서 레이저를 볼 수 있어야 합니다.

음향 효과

현재 발사 사운드 효과는 발사체를 발사하는 클라이언트에서만 재생됩니다.다른 플레이어도 소리를 들을 수 있도록 코드를 이동해야 합니다.

  1. 도구 컨트롤러 스크립트에서 도구 활성화 함수로 이동하고 활성화 소리를 재생하는 줄을 제거합니다.


    local function toolActivated()
    if canShootWeapon() then
    fireWeapon()
    end
    end
  2. 레이저 렌더러의 함수 하단에서 shootingSound라는 변수를 선언하고 활성화 소리를 확인하기 위해 방사 소리의 메서드를 사용합니다.

  3. if 문을 사용하여 문이 존재하는지 확인하고, 존재하면 플레이 함수를 호출합니다.


    laserPart.Parent = workspace
    -- 제거되고 정리될 폐기물 서비스에 레이저 빔 추가
    Debris:AddItem(laserPart, SHOT_DURATION)
    -- 무기의 발사 소리 재생
    local shootingSound = toolHandle:FindFirstChild("Activate")
    if shootingSound then
    shootingSound:Play()
    end
    end

유효성 검사를 사용하여 원격 보안

서버가 들어오는 요청에서 데이터를 확인하지 않는 경우 해커는 원격 함수와 이벤트를 남용하고 서버에 가짜 값을 전송할 수 있습니다.이를 방지하기 위해 서버 측 유효성 검사 를 사용하는 것이 중요합니다.

현재 형태에서 피해 캐릭터 원격 이벤트는 공격에 매우 취약합니다.해커는 이 이벤트를 사용하여 플레이어를 쏘지 않고도 게임에서 원하는 플레이어에게 피해를 줄 수 있습니다.

유효성 검사는 서버에 전송되는 값이 현실적인지 확인하는 프로세스입니다. 이 경우 서버는 다음이 필요합니다:

  • 플레이어와 레이저가 타격한 위치 사이의 거리가 특정 경계 내에 있는지 확인합니다.
  • 레이저를 발사한 무기와 타격 위치 사이에서 레이캐스트하여 발사가 가능했고 벽을 통과하지 않았는지 확인합니다.

클라이ент

클라이언트는 레이캐스트에 의해 타격된 서버 위치를 보내야 하므로 거리가 현실적인지 확인할 수 있습니다.

  1. 에서 도구 컨트롤러 , 피해 캐릭터 원격 이벤트가 fireWeapon 함수에서 발생하는 줄로 이동합니다.

  2. hitPosition를 인수로 추가합니다.


    if characterModel then
    local humanoid = characterModel:FindFirstChildWhichIsA("Humanoid")
    if humanoid then
    eventsFolder.DamageCharacter:FireServer(characterModel, hitPosition)
    end
    end

서버

클라이언트가 이제 DamageCharacter 원격 이벤트를 통해 추가 매개변수를 보내고 있으므로 ServerLaserManager 가 수락하도록 조정해야 합니다.

  1. ServerLaserManager 스크립트에서 hitPosition 매개 변수를 damageCharacter 함수에 추가하십시오.


    function damageCharacter(playerFired, characterToDamage, hitPosition)
    local humanoid = characterToDamage:FindFirstChildWhichIsA("Humanoid")
    if humanoid then
    -- 캐릭터에서 건강 제거
    humanoid.Health -= LASER_DAMAGE
    end
    end
  2. 아래의 getPlayerToolHandle 함수에서 3개의 매개변수를 가진 함수 이름 isHitValid 을 만듭니다: playerFired, characterToDamagehitPosition.


    end
    local function isHitValid(playerFired, characterToDamage, hitPosition)
    end

첫 번째 확인은 타격 위치와 캐릭터 타격 사이의 거리가 될 것입니다.

  1. 스크립트 상단에 MAX_HIT_PROXIMITY 라는 변수를 선언하고 값 10 을 할당합니다.히트와 캐릭터 사이의 허용되는 최대 거리가 됩니다.클라이언트가 이벤트를 발생시킨 이후 캐릭터가 약간 이동했을 수 있기 때문에 허용이 필요합니다.


    local ReplicatedStorage = game:GetService("ReplicatedStorage")
    local eventsFolder = ReplicatedStorage.Events
    local LASER_DAMAGE = 10
    local MAX_HIT_PROXIMITY = 10
  2. isHitValid 함수에서 문자와 타격 위치 사이의 거리를 계산합니다.거리가 MAX_HIT_PROXIMITY 보다 크면 반환 false 합니다.


    local function isHitValid(playerFired, characterToDamage, hitPosition)
    -- 문자 타격과 타격 위치 사이의 거리 유효성 검사
    local characterHitProximity = (characterToDamage.HumanoidRootPart.Position - hitPosition).Magnitude
    if characterHitProximity > MAX_HIT_PROXIMITY then
    return false
    end
    end

두 번째 검사는 발사된 무기와 타격 위치 사이의 레이캐스트를 포함합니다.레이캐스트가 캐릭터가 아닌 개체를 반환하면 샷이 차단되었기 때문에 샷이 유효하지 않았다고 가정할 수 있습니다.

  1. 이 확인수행하기 위해 아래 코드를 복사하십시오. 함수 끝에 true 를 반환합니다: 종료도달하면 모든 검사가 통과됩니다.


    local function isHitValid(playerFired, characterToDamage, hitPosition)
    -- 문자 타격과 타격 위치 사이의 거리 유효성 검사
    local characterHitProximity = (characterToDamage.HumanoidRootPart.Position - hitPosition).Magnitude
    if characterHitProximity > 10 then
    return false
    end
    -- 벽을 통과하여 촬영하는지 확인
    local toolHandle = getPlayerToolHandle(playerFired)
    if toolHandle then
    local rayLength = (hitPosition - toolHandle.Position).Magnitude
    local rayDirection = (hitPosition - toolHandle.Position).Unit
    local raycastParams = RaycastParams.new()
    raycastParams.FilterDescendantsInstances = {playerFired.Character}
    local rayResult = workspace:Raycast(toolHandle.Position, rayDirection * rayLength, raycastParams)
    -- 캐릭터가 아닌 인스턴스를 타격했다면 샷을 무시합니다
    if rayResult and not rayResult.Instance:IsDescendantOf(characterToDamage) then
    return false
    end
    end
    return true
    end
  2. 유효한 샷이라고 불리는 damageCharacter 함수에서 변수를 선언하십시오 validShot .세 가지 인수로 isHitValid 함수에 대한 호출 결과를 할당하십시오: playerFired , characterToDamagehitPosition .

  3. 아래 if 문에서 연산자를 추가하여 validShottrue 인지 확인합니다.


    function damageCharacter(playerFired, characterToDamage, hitPosition)
    local humanoid = characterToDamage:FindFirstChildWhichIsA("Humanoid")
    local validShot = isHitValid(playerFired, characterToDamage, hitPosition)
    if humanoid and validShot then
    -- 캐릭터에서 건강 제거
    humanoid.Health -= LASER_DAMAGE
    end
    end

이제 손상 캐릭터 원격 이벤트가 더 안전하며 대부분의 플레이어가 남용하는 것을 방지합니다.일부 악성 플레이어는 종종 유효성 검사를 우회하는 방법을 찾을 수 있습니다; 원격 이벤트를 안전하게 유지하는 것은 지속적인 노력입니다.

레이저 블래스터가 완성되었으며, 레이캐스팅을 사용하는 기본 히트 감지 시스템이 있습니다.레이저 블래스터에 재장전 작업을 추가하거나 재미있는 게임 맵을 만들고 다른 플레이어와 함께 레이저 블래스터를 시도해 볼 수 있도록 사용자 입력 감지 튜토리얼을 시도하십시오!

최종 코드

도구 컨트롤러


local UserInputService = game:GetService("UserInputService")
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local LaserRenderer = require(Players.LocalPlayer.PlayerScripts.LaserRenderer)
local tool = script.Parent
local eventsFolder = ReplicatedStorage.Events
local MAX_MOUSE_DISTANCE = 1000
local MAX_LASER_DISTANCE = 500
local FIRE_RATE = 0.3
local timeOfPreviousShot = 0
-- 이전 발사 후 충분한 시간이 지났는지 확인
local function canShootWeapon()
local currentTime = tick()
if currentTime - timeOfPreviousShot < FIRE_RATE then
return false
end
return true
end
local function getWorldMousePosition()
local mouseLocation = UserInputService:GetMouseLocation()
-- 2D 마우스 위치에서 광선 생성
local screenToWorldRay = workspace.CurrentCamera:ViewportPointToRay(mouseLocation.X, mouseLocation.Y)
-- 광선의 단위 방향 벡터가 최대 거리로 곱해진 값
local directionVector = screenToWorldRay.Direction * MAX_MOUSE_DISTANCE
-- 로이의 원점에서 해당 방향으로 레이캐스트
local raycastResult = workspace:Raycast(screenToWorldRay.Origin, directionVector)
if raycastResult then
-- 교차 지점의 3D 포인트 반환
return raycastResult.Position
else
-- 대상이 없으므로 광선 끝에서 위치를 계산하지 않습니다
return screenToWorldRay.Origin + directionVector
end
end
local function fireWeapon()
local mouseLocation = getWorldMousePosition()
-- 정규화된 방향 벡터를 계산하고 레이저 거리로 곱하기
local targetDirection = (mouseLocation - tool.Handle.Position).Unit
-- 무기를 발사하는 방향, 최대 거리로 곱한
local directionVector = targetDirection * MAX_LASER_DISTANCE
-- 플레이어의 캐릭터를 무시하여 스스로 손상되는 것을 방지합니다
local weaponRaycastParams = RaycastParams.new()
weaponRaycastParams.FilterDescendantsInstances = {Players.LocalPlayer.Character}
local weaponRaycastResult = workspace:Raycast(tool.Handle.Position, directionVector, weaponRaycastParams)
-- 시작 위치와 끝 위치 사이에서 개체가 타격되었는지 확인
local hitPosition
if weaponRaycastResult then
hitPosition = weaponRaycastResult.Position
-- 인스턴스 타격은 캐릭터 모델의 자식이 될 것입니다
-- 모델에 휴머노이드가 발견되면 플레이어의 캐릭터일 가능성이 높습니다
local characterModel = weaponRaycastResult.Instance:FindFirstAncestorOfClass("Model")
if characterModel then
local humanoid = characterModel:FindFirstChildWhichIsA("Humanoid")
if humanoid then
eventsFolder.DamageCharacter:FireServer(characterModel, hitPosition)
end
end
else
-- 최대 레이저 거리에 따라 최종 위치 계산
hitPosition = tool.Handle.Position + directionVector
end
timeOfPreviousShot = tick()
eventsFolder.LaserFired:FireServer(hitPosition)
LaserRenderer.createLaser(tool.Handle, hitPosition)
end
local function toolEquipped()
tool.Handle.Equip:Play()
end
local function toolActivated()
if canShootWeapon() then
fireWeapon()
end
end
tool.Equipped:Connect(toolEquipped)
tool.Activated:Connect(toolActivated)

레이저 렌더러


local LaserRenderer = {}
local Debris = game:GetService("Debris")
local SHOT_DURATION = 0.15 -- 레이저가 표시되는 시간
-- 시작 위치에서 끝 위치까지 레이저 빔 생성
function LaserRenderer.createLaser(toolHandle, endPosition)
local startPosition = toolHandle.Position
local laserDistance = (startPosition - endPosition).Magnitude
local laserCFrame = CFrame.lookAt(startPosition, endPosition) * CFrame.new(0, 0, -laserDistance / 2)
local laserPart = Instance.new("Part")
laserPart.Size = Vector3.new(0.2, 0.2, laserDistance)
laserPart.CFrame = laserCFrame
laserPart.Anchored = true
laserPart.CanCollide = false
laserPart.Color = Color3.fromRGB(255, 0, 0)
laserPart.Material = Enum.Material.Neon
laserPart.Parent = workspace
-- 제거되고 정리될 폐기물 서비스에 레이저 빔 추가
Debris:AddItem(laserPart, SHOT_DURATION)
-- 무기의 발사 소리 재생
local shootingSound = toolHandle:FindFirstChild("Activate")
if shootingSound then
shootingSound:Play()
end
end
return LaserRenderer

서버레이저 관리자


local ReplicatedStorage = game:GetService("ReplicatedStorage")
local eventsFolder = ReplicatedStorage.Events
local LASER_DAMAGE = 10
local MAX_HIT_PROXIMITY = 10
-- 플레이어가 보유하고 있는 도구의 핸들 찾기
local function getPlayerToolHandle(player)
local weapon = player.Character:FindFirstChildOfClass("Tool")
if weapon then
return weapon:FindFirstChild("Handle")
end
end
local function isHitValid(playerFired, characterToDamage, hitPosition)
-- 문자 타격과 타격 위치 사이의 거리 유효성 검사
local characterHitProximity = (characterToDamage.HumanoidRootPart.Position - hitPosition).Magnitude
if characterHitProximity > MAX_HIT_PROXIMITY then
return false
end
-- 벽을 통과하여 촬영하는지 확인
local toolHandle = getPlayerToolHandle(playerFired)
if toolHandle then
local rayLength = (hitPosition - toolHandle.Position).Magnitude
local rayDirection = (hitPosition - toolHandle.Position).Unit
local raycastParams = RaycastParams.new()
raycastParams.FilterDescendantsInstances = {playerFired.Character}
local rayResult = workspace:Raycast(toolHandle.Position, rayDirection * rayLength, raycastParams)
-- 캐릭터가 아닌 인스턴스를 타격했다면 샷을 무시합니다
if rayResult and not rayResult.Instance:IsDescendantOf(characterToDamage) then
return false
end
end
return true
end
-- 레이저가 발사되었음을 모든 클라이언트에 알려 레이저를 표시할 수 있도록 함
local function playerFiredLaser(playerFired, endPosition)
local toolHandle = getPlayerToolHandle(playerFired)
if toolHandle then
eventsFolder.LaserFired:FireAllClients(playerFired, toolHandle, endPosition)
end
end
function damageCharacter(playerFired, characterToDamage, hitPosition)
local humanoid = characterToDamage:FindFirstChildWhichIsA("Humanoid")
local validShot = isHitValid(playerFired, characterToDamage, hitPosition)
if humanoid and validShot then
-- 캐릭터에서 건강 제거
humanoid.Health -= LASER_DAMAGE
end
end
-- 이벤트를 적절한 함수에 연결하기
eventsFolder.DamageCharacter.OnServerEvent:Connect(damageCharacter)
eventsFolder.LaserFired.OnServerEvent:Connect(playerFiredLaser)

클라이언트레이저매니저


local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local LaserRenderer = require(Players.LocalPlayer.PlayerScripts:WaitForChild("LaserRenderer"))
local eventsFolder = ReplicatedStorage.Events
-- 다른 플레이어의 레이저 표시
local function createPlayerLaser(playerWhoShot, toolHandle, endPosition)
if playerWhoShot ~= Players.LocalPlayer then
LaserRenderer.createLaser(toolHandle, endPosition)
end
end
eventsFolder.LaserFired.OnClientEvent:Connect(createPlayerLaser)