레이저 센서 기반 타격 감지

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

이 튜토리얼에서는 레이저를 생성 플레이어 도구에서 캐스트하는 방법을 배우고 플레이어를 타격하는지 여부를 감지하는 방법을 배웁니다.

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

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

벽과 충돌하는 레이캐스트FROM A TO B

마우스 위치 찾기

레이저가 쏠 수 있기 전에, 먼저 플레이어가 조준하고 있는 곳을 알아야 합니다. 이는 플레이어의 2D 마우스 위치에서 직접 카메라로 향상되는 레이캐스트를 통해 찾을 수 있습니다. 레이는 플레이어가 조준하고 있는 것과 마우스로 조준하는 것 모두에 충돌합니다.

  1. 생성 플레이어 도구 에서 블래스터 도구 내의 도구 컨트롤러 스크립트를 엽니다. 아직 해당 튜토리얼을 완료하지 않았다면 Blaster 모델을 다운로드하고 StarterPack에 삽입할 수 있습니다.

  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. Class.UserInputService의 게ッ트 마우스 위치 함수를 사용하여 플레이어의 2D 마우스 위치를 화면에서 확인합니다. 이 변수에 대한 이름은 MouseLocation 입니다.


    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 속성은 Camera:ViewportPointToRay() 함수에 사용될 수 있습니다, 이는 화면에서 2>Datatype.Ray2>를 생성하는 3D 게임 세계로부터 5> Class.Camera:ViewportPointToRay()5> 함수를 참

  1. Class.Camera:ViewportPointToRay()|ViewportPointToRay() 에 대한 XmouseLocation 속성을 사용하십시오. 이 기능의 인수로 1>Class.Camera:ViewportPointToRay()|ViewportPointToRay()1> 함수에 할당됩니다. 이 변수에 대한 이름은 4>screenToWorldRay4>입니다.


    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라는 변수를 선언하고 screenToWorldRay.DirectionMAX_MOUSE_DISTANCE 와 곱한 값을 지정합니다.


    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. 작업 공간의 Raycast 함수를 호출하여 첫 번째 인수로 Origin 속성의 screenToWorldRay를 전달하고 두 번째 인수로 2>방향 벡터2>를 지정합니다. 이 변수에 대한 5>raycastResult5>를 할당


    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 셀.
위치교차 지점; 일반적으로 부품 또는 지형의 표면에 직접 있는 점입니다.
재료충돌 점의 재료.
일반적인 것은 일반적인 것입니다.교차된 두 얼굴의 일반적인 벡터. 이 벡터는 얼굴이 어느 방향으로 가리키는지 결정하는 데 사용될 수 있습니다.

위치 속성은 마우스가 위치한 개체의 위치입니다. 마우스가 MAX_MOUSE_DISTANCE 범위 내의 어떤 개체에도 마우스가 없는 경우, raycastResult 는 일반적으로 0이 됩니다.

  1. if 문을 생성하여 raycastResult 가 존재하는지 확인합니다.

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

  3. raycastResult 이 0인 경우 레이캐스트의 끝을 찾습니다. 3D 위치를 계산하려면 screenToWorldRay.OrigindirectionVector를 함께 추가하십시오.


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() 를 호출하고 결과를 MousePosition 변수에 할당하십시오. 이 경우 레이캐스트의 대상 위치가 됩니다.


    -- 개체가 히트되지 않으므로 광선 끝에 위치를 계산합니다.
    return screenToWorldRay.Origin + directionVector
    end
    end
    local function fireWeapon()
    local mouseLocation = getWorldMousePosition()
    end
    local function toolEquipped()
    tool.Handle.Equip:Play()
    end

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

  1. 변수 목표 방향 을 선언하고 도구 위치를 mouseLocation 에서 제거하여 방향 벡터를 계산합니다.

  2. 벡터를 정규화하려면 그 속성 단위 를 사용하십시오. 이렇게 하면 나중에 길이를 곱하기 쉽습니다.


    local function fireWeapon()
    local mouseLocation = getWorldMousePosition()
    -- 정규화된 방향 벡터를 계산하고 레이저 거리로 나눕니다.
    local targetDirection = (mouseLocation - tool.Handle.Position).Unit
    end
  3. 향상 벡터라는 이름의 변수를 선언하고 targetDirectionMAX_LASER_DISTANCE 로 나눕니다.


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

Datatype.RaycastParams 개체를 사용하여 레이캐스트 기능에 대한 추가 매개 변수를 저장할 수 있습니다. 레이캐스트는 플레이어가 무기를 발사하는 경우 부딪히는 위험이 있기 때문에 레이캐스

  1. Continue the fireWeapon 함수 and declare a variable called weaponRaycastParams . Assign a new RaycastParams 개체를 할당합니다.

  2. 플레이어의 로컬 캐릭터 를 포함하는 테이블을 생성하고 weaponRaycastParams.FilterDescendantsInstances에 할당하십시오.

  3. 플레이어의 도구 핸들 위치에서 레이캐스트, 방향 number1 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 문을 사용하여 weaponRaycastResult 가 값이 있는지 여부를 확인합니다. 개체가 타격되면 weaponRaycastResult.Position 를 1> hitPosition1> 에 할당합니다.


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


    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. 도구 활성화 함수로 이동하고 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 클라이언트로 시작하십시오. 세 개의 창이 나타납니다. 첫 번째 창은 로컬 서버이고, 다른 창은 플레이어 1 및 플레이어 2의 클라이언트입니다.

  3. 한 클라이언트에서 다른 플레이어를 클릭하여 무기로 쏘는 테스트를 수행합니다. 플레이어가 쏜 때마다 출력에 "Player hit"가 표시됩니다.

테스트 탭에 대해 자세히 알아보려면 여기에서 자세히 알아보세요.

레이저 위치 찾기

블래스터는 목표물에 빨간색 빔의 빛을 발사해야 합니다. 이 기능은 ModuleScript 내에 있으므로 나중에 다른 스크립트에서 사용할 수 있습니다. 먼저 스크립트는 레이저 빔이 렌더링되어야 할 위치를 찾아야 합니다.

  1. LaserRender라는 이름의 모듈 스크립트 를 생성하고 StarterPlayer 아래에 있는 StarterPlayerScripts에 부모로 지정합니다.

  2. 스크립트를 열고 모듈 테이블을 레이저 렌더러 의 이름으로 이름을 변경합니다.

  3. 레이저가 보이는 시간(초)을 나타내는 변수 샷_지속_시간 을 0.15 로 선언합니다. 이것은 레이저가 보이는 시간(초)을 나타냅니다.

  4. 도구 처리기 createLaser 와 끝 위치 endPosition 를 가진 레이저 생성기 함수를 만듭니다.


    local LaserRenderer = {}
    local SHOT_DURATION = 0.15 -- 레이저가 보이는 시간
    -- 시작 위치에서 레이저 빔 만들기
    function LaserRenderer.createLaser(toolHandle, endPosition)
    end
    return LaserRenderer
  5. 변수 시작 위치 를 선언하고 위치 속성의 toolHandle을 값으로 설정합니다. 이 경우 플레이어의 레이저 블래스터의 위치가 됩니다.

  6. 레이저 거리 laserDistance 를 선언하고 시작 위치 endPosition 에서 레이저 빔의 길이를 찾기 위해 startPosition 을 뺍니다. 이 속성의 크기를 사용하여 레이저 빔의 길이를 얻습니다.


    function LaserRenderer.createLaser(toolHandle, endPosition)
    local startPosition = toolHandle.Position
    local laserDistance = (startPosition - endPosition).Magnitude
    end
  7. 레이저 빔의 위치 및 방향을 저장하기 위해 laserCFrame 변수를 선언하십시오. 위치는 시작 및 끝 사이의 레이저 빔의 중간 점이어야 합니다


    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 를 선언하고 새로운 Part 인스턴스를 할당합니다.

  2. 다음 laserPart 속성을 설정합니다.

    1. 크기 : Vector3.new(0.2, 0.2, laserDistance)
    2. CFrame : 레이저CFrame
    3. 고정된 상태 : true
    4. 충돌 가능 : false
    5. 색상 : Color3.fromRGB(225, 0, 0) (강한 빨간색 색상)
    6. 재료 : Enum.Material.Neon
  3. 부모 laserPartWorkspace .

  4. Class.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

이제 레이저 빔을 렌더링하는 기능이 완료되었으므로 도구 컨트롤러 라는 이름으로 호출할 수 있습니다.

  1. 도구 컨트롤러 스크립트의 상단에 있는 레이저 리플레이어라는 변수를 선언하고 플레이어 스크립트에 있는 레이저 리플레이어 모듈 스크립트를 요구합니다.


    local UserInputService = game:GetService("UserInputService")
    local Players = game:GetService("Players")
    local LaserRenderer = require(Players.LocalPlayer.PlayerScripts.LaserRenderer)
    local tool = script.Parent
  2. fireWeapon 함수의 하단에서 도구 핸들과 createLaser 함수를 사용하여 레이저 생성기를 호출합니다.


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

무기 발사 속도 제어

플레이어가 너무 많은 피해를 입히지 못하도록 각 샷 사이에 지연이 필요합니다. 이는 플레이어가 마지막으로 발사한 시간 이후 얼마나 시간이 지났는지 확인하여 제어할 수 있습니다.

  1. Fire_Rate라는 이름의 도구 컨트롤러 의 맨 위에 변수를 선언합니다. 이는 각 샷 사이의 최소 시간입니다. 선택한 값을 입력하십시오; 이 예에서는 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. 함수에서 현재 시간이라는 변수를 선언하고 tick() 함수의 결과를 할당합니다. 이는 1970년 1월 1일(임의의 날짜 사용)부터 지정된 시간(초)까지 지났는지 반환합니다.

  5. 현재 시간에서 timeOfPreviousShot를 뺄 수 없으면 결과가 currentTime보다 작으므로 반환하지 않고 작은 경우 반환하지 않고 나가게 됩니다. 그렇지 않으면 결과를 2> 작게 만들면 반환합니다. 그렇지 않으면 모두 반환합니다. Korean:현재 시간에서 time


    -- 이전에 발사된 샷 이후 충분한 시간이 지났는지 확인하십시오
    local function canShootWeapon()
    local currentTime = tick()
    if currentTime - timeOfPreviousShot < FIRE_RATE then
    return false
    end
    return true
    end
  6. fireWeapon 함수의 끝에, 매번 무기가 발사되면 timeOfPreviousShot 을 업데이트합니다.


    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. 원격 이벤트를 이벤트 폴더에 삽입하고 이름을 지정합니다 DamageCharacter .

  3. In ToolController , 스크립트 시작 부분에서 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. DamageCharacter 원격 이벤트를 손질하기 위해 fireWeapon 프린트 문에 Lua 줄을 대체하십시오.


    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. ServerScriptService에 스크립트를 삽입하고 이름을 ServerLaserManager로 지정합니다.

  2. LASER_DAMAGE라는 변수를 선언하고 값을 10 또는 선택한 값으로 설정합니다.

  3. playerFired 및 캐릭터에 피해를 라는 이름의 함수를 두 개 만들고

  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. 로컬 서버를 시작하여 블래스터를 테스트하십시오. 다른 플레이어를 쏠 때 그들의 체력이 LASER_DAMAGE 으로 줄어듭니다.

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

현재 레이저 빔은 무기를 발사하는 클라이언트에 의해 생성되므로 무기를 발사한 클라이언트만 레이저 빔을 볼 수 있습니다.

레이저 빔이 서버에 생성된 경우 모든 사람이 볼 수 있습니다. 그러나 클라이언트가 무기를 쏠 때 서버에서 정보를 수신하는 간에 약간의 지연 이 발생합니다. 이렇게 하면 클라이언트가 무기를 활성화하면 서버에서 느끼는 지연이 증가합니

이 문제를 해결하기 위해, 모든 클라이언트는 자신만의 레이저 빔을 생성합니다. 즉, 클라이언트가 무기를 쏠 때 레이저 빔을 즉시 볼 수 있습니다. 다른 클라이언트는 다른 플레이어가 쏠 때와 레이저 빔이 나타나는 시간 간의 작은 지연을 경험합니다. 이 경

샤이더 클라이언트

먼저, 클라이언트는 서버에게 레이저를 발사했다고 알리고 종료 위치를 제공해야 합니다.

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

  2. 도구 컨트롤러 스크립트의 fireWeapon 함수를 찾습니다. 함수의 끝에서 LaserFired 원격 이벤트를 사용하여 hitPosition 을 인수로 화면을 표시합니다.


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

서버

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

  1. In the ServerLaserManager script, create a function named playerFiredLaser above damageCharacter with two parameters called 1> playerFired1> and 4> endPosition4> .

  2. 함수를 레이저 발사 원격 이벤트에 연결하십시오.


    -- 레이저가 발사되었음을 모든 클라이언트에 알려주려면 레이저를 표시합니다.
    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. In the playerFiredLaser function, call the getPlayerToolHandle function with playerFired as an argument and assign the value to a variable named 1> toolHandle1> .

  2. 도구 핸들이 있으면 모든 클라이언트에서 LaserFired 이벤트를 발생시키고, playerFired , toolHandle 및 2> endPosition2>을 인수로 사용합니다.


    -- 레이저가 발사되었음을 모든 클라이언트에 알려주려면 레이저를 표시합니다.
    local function playerFiredLaser(playerFired, endPosition)
    local toolHandle = getPlayerToolHandle(playerFired)
    if toolHandle then
    eventsFolder.LaserFired:FireAllClients(playerFired, toolHandle, endPosition)
    end
    end

클라이언트에서 렌더링

이제 FireAllClients 가 호출되었으며, 각 클라이언트는 서버로부터 이벤트를 받아 레이저 빔을 렌더링합니다. 각 클라이언트는 도구의 핸들 위치 및 종료 위치 값을 사용하여 레이저 빔을 렌더링하는 도구의 모듈을 이전에

  1. StarterPlayerScripts의 로컬 스크립트를 만들어 클라이언트 레이저 관리자라는 이름의 스타터 플레이어 스크립트에 합니다.

  2. 스크립트 내에서 레이저 렌더러 모듈을 필요로 합니다.

  3. 매개 변수 playerWhoShot , playerWhoShottoolHandle 을 가진 함수 이름 1> createPlayerLaser1> 을 생성합니다.

  4. Events 폴더에 있는 LaserFired 리모트 이벤트에 함수를 연결하십시오.

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

  6. if 문 내에서 createLaser 함수를 사용하여 레이저 렌더러 모듈에서 toolHandleendPosition 을 인수로 호출합니다.


    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. 로컬 서버를 시작하여 블래스터를 테스트하십시오. 각 클라이언트를 모니터의 다른 측면에 둔 다음 둘 중 하나를 잠깐 볼 수 있습니다. 한 클라이언트에서 쏠 때 다른 클라이언트에서 레이저를 볼 수 있습니다.

음향 효과

발사 음향 효과는 현재 발사 프로젝티리 하는 클라이언트에서만 재생됩니다. 다른 플레이어가 들을 수 있도록 코드를 이동해야 합니다.

  1. 도구 컨트롤러 스크립트에서 도구 활성화 함수로 이동하고 활성화 사운드를 재생하는 줄을 제거하십시오.


    local function toolActivated()
    if canShootWeapon() then
    fireWeapon()
    end
    end
  2. createLaser 함수의 하단에 있는 LaserRender 에서 변수명 shootingSound 를 선언하고 1> Class.Instance:FindFirstChild()|FindFirstChild()1> 메서드를 사용하여 4> 활성화4> 사운드를 검사합니다.

  3. Use an if 문을 사용하여 shootingSound 이 있는지 확인하십시오; 그렇다면, Play 함수를 호출합니다.


    laserPart.Parent = workspace
    -- 레이저 빔을 추가하여 잔해 서비스에서 제거되고 청소됩니다.
    Debris:AddItem(laserPart, SHOT_DURATION)
    -- 무기 샷 사운드 재생
    local shootingSound = toolHandle:FindFirstChild("Activate")
    if shootingSound then
    shootingSound:Play()
    end
    end

유효성 검사를 사용하여 리모트 보안

서버가 수신된 요청에서 데이터를 검사하지 않으면 해커는 원격 함수 및 이벤트를 남용하여 서버에 가짜 값을 전송할 수 있습니다. 이를 방지하려면 서버 사이드 유효성 검사를 사용하는 것이 좋습니다.

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

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

  • 레이저가 표시하는 위치와 플레이어가 표시하는 위치 사이의 거리가 특정 경계 내에 있는지 확인하십시오.
  • 레이캐스트는 레이저를 발사한 무기와 히트 위치 사이에서 수행하여 샷이 가능하고 벽을 통과하지 않도록 합니다.

클라이언트

클라이언트는 레이캐스트에 의해 히트된 위치를 서버에 전송하여 거리가 현실적인지 확인해야 합니다.

  1. In ToolController , DamageCharacter 원격 이벤트가 발생하는 라인으로 이동합니다. fireWeapon 함수.

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


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

서버

이제 클라이언트는 공격 캐릭터 원격 이벤트를 통해 추가 매개 변수를 보내고 있으므로 ServerLaserManager 를 조정해야 합니다.

  1. In the ServerLaserManager script, add a hitPosition parameter to the damageCharacter function.


    function damageCharacter(playerFired, characterToDamage, hitPosition)
    local humanoid = characterToDamage:FindFirstChildWhichIsA("Humanoid")
    if humanoid then
    -- 캐릭터의 체력 제거
    humanoid.Health -= LASER_DAMAGE
    end
    end
  2. getPlayerToolHandle 함수 아래에, 세 매개 변수로 이름이 isHitValid 인 함수를 만듭니다. playerFired , 1> characterToDamage1> 및 4> hitPosition4> .


    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. In the isHitValid 함수에서 캐릭터와 히트 위치 사이의 거리를 계산합니다. 거리가 MAX_HIT_PROXIMITY보다 큰 경우 반환 하고 나머지는 1>거리1>로 나머지 부분을 계산합니다.


    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 함수에 변수를 선언하십시오. playerFired , isHitValid 및 1> isHitValid1> 함수에 3개의 인수로 호출을 할당하십시오. 4> playerFired4>, 7> CharacterToDamage</

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


    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)