이 튜토리얼에서는 레이저를 생성 플레이어 도구에서 캐스트하는 방법을 배우고 플레이어를 타격하는지 여부를 감지하는 방법을 배웁니다.
충돌 찾기를 위한 레이캐스팅
레이캐스팅 은 시작 위치에서 정의된 길이로 향상된 방향으로 투명한 레이를 생성합니다. 레이가 경로에 있는 개체 또는 지형과 충돌하면 충돌 위치와 개체가 충돌한 위치에 대한 정보를 반환합니다.
마우스 위치 찾기
레이저가 쏠 수 있기 전에, 먼저 플레이어가 조준하고 있는 곳을 알아야 합니다. 이는 플레이어의 2D 마우스 위치에서 직접 카메라로 향상되는 레이캐스트를 통해 찾을 수 있습니다. 레이는 플레이어가 조준하고 있는 것과 마우스로 조준하는 것 모두에 충돌합니다.
스크립트 상단에 있는 MAX_MOUSE_DISTANCE라는 이름의 상수를 선언하십시오, 1000 의 값.
함수 이름은 getWorldMousePosition 입니다.
local tool = script.Parentlocal MAX_MOUSE_DISTANCE = 1000local function getWorldMousePosition()endlocal function toolEquipped()tool.Handle.Equip:Play()endlocal function toolActivated()tool.Handle.Activate:Play()end-- 이벤트를 적절한 함수에 연결하십시오tool.Equipped:Connect(toolEquipped)tool.Activated:Connect(toolActivated)Class.UserInputService의 게ッ트 마우스 위치 함수를 사용하여 플레이어의 2D 마우스 위치를 화면에서 확인합니다. 이 변수에 대한 이름은 MouseLocation 입니다.
local UserInputService = game:GetService("UserInputService")local tool = script.Parentlocal MAX_MOUSE_DISTANCE = 1000local function getWorldMousePosition()local mouseLocation = UserInputService:GetMouseLocation()end
이제 2D 마우스 위치가 알려져 있으며, 그 X 및 Y 속성은 Camera:ViewportPointToRay() 함수에 사용될 수 있습니다, 이는 화면에서 2>Datatype.Ray2>를 생성하는 3D 게임 세계로부터 5> Class.Camera:ViewportPointToRay()5> 함수를 참
Class.Camera:ViewportPointToRay()|ViewportPointToRay() 에 대한 X 및 mouseLocation 속성을 사용하십시오. 이 기능의 인수로 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 만큼 곱해야 합니다.
DirectionVector라는 변수를 선언하고 screenToWorldRay.Direction 를 MAX_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작업 공간의 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이 됩니다.
if 문을 생성하여 raycastResult 가 존재하는지 확인합니다.
raycastResult의 값이 있으면 위치 속성을 반환합니다.
raycastResult 이 0인 경우 레이캐스트의 끝을 찾습니다. 3D 위치를 계산하려면 screenToWorldRay.Origin 및 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
-- 레이캐스트는 레이의 원래 방향으로 레이캐스트
local raycastResult = workspace:Raycast(screenToWorldRay.Origin, directionVector)
if raycastResult then
-- 3D 교차 점 반환
return raycastResult.Position
else
-- 개체가 히트되지 않으므로 광선 끝에 위치를 계산합니다.
return screenToWorldRay.Origin + directionVector
end
end
목표물을 향해 발사
이제 3D 마우스 위치가 알려졌으므로 레이저를 쏠 대상 위치로 사용할 수 있습니다. 레이캐스트 함수를 사용하여 플레이어의 무기와 대상 위치 사이에서 두 번째 레이를 캐스트할 수 있습니다.
스크립트 상단에 있는 상수 MAX_LASER_DISTANCE를 선언하고 레이저 블래스터에 대한 범위를 지정하십시오. 500 또는 레이저 블래스터에 대한 범위를 지정하십시오.
local UserInputService = game:GetService("UserInputService")local tool = script.Parentlocal MAX_MOUSE_DISTANCE = 1000local MAX_LASER_DISTANCE = 500fireWeapon 함수를 getWorldMousePosition 함수 아래에 만듭니다.
getWorldMousePosition() 를 호출하고 결과를 MousePosition 변수에 할당하십시오. 이 경우 레이캐스트의 대상 위치가 됩니다.
-- 개체가 히트되지 않으므로 광선 끝에 위치를 계산합니다.return screenToWorldRay.Origin + directionVectorendendlocal function fireWeapon()local mouseLocation = getWorldMousePosition()endlocal function toolEquipped()tool.Handle.Equip:Play()end
이번에는 레이캐스트 함수의 방향 벡터가 플레이어의 도구 위치에서 대상 위치로 방향을 나타냅니다.
변수 목표 방향 을 선언하고 도구 위치를 mouseLocation 에서 제거하여 방향 벡터를 계산합니다.
벡터를 정규화하려면 그 속성 단위 를 사용하십시오. 이렇게 하면 나중에 길이를 곱하기 쉽습니다.
local function fireWeapon()local mouseLocation = getWorldMousePosition()-- 정규화된 방향 벡터를 계산하고 레이저 거리로 나눕니다.local targetDirection = (mouseLocation - tool.Handle.Position).Unitend향상 벡터라는 이름의 변수를 선언하고 targetDirection 을 MAX_LASER_DISTANCE 로 나눕니다.
local targetDirection = (mouseLocation - tool.Handle.Position).Unit-- 무기를 발사할 방향, 최대 거리로 곱local directionVector = targetDirection * MAX_LASER_DISTANCEend
Datatype.RaycastParams 개체를 사용하여 레이캐스트 기능에 대한 추가 매개 변수를 저장할 수 있습니다. 레이캐스트는 플레이어가 무기를 발사하는 경우 부딪히는 위험이 있기 때문에 레이캐스
Continue the fireWeapon 함수 and declare a variable called weaponRaycastParams . Assign a new RaycastParams 개체를 할당합니다.
플레이어의 로컬 캐릭터 를 포함하는 테이블을 생성하고 weaponRaycastParams.FilterDescendantsInstances에 할당하십시오.
플레이어의 도구 핸들 위치에서 레이캐스트, 방향 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
마지막으로, 레이캐스트 작업이 값을 반환했는지 확인해야 합니다. 값이 반환되면 레이캐스트 작업이 레이를 반환했고 레이저를 무기 위치 사이에 생성할 수 있습니다. 아무것도 반환되지 않으면 레이저를 생성하기 위해 최종 위치를 계산해야 합니다.
hitPosition이라는 이름의 변수를 선언합니다.
Use an if 문을 사용하여 weaponRaycastResult 가 값이 있는지 여부를 확인합니다. 개체가 타격되면 weaponRaycastResult.Position 를 1> hitPosition1> 에 할당합니다.
local weaponRaycastResult = workspace:Raycast(tool.Handle.Position, directionVector, weaponRaycastParams)-- 시작 위치와 끝 위치 사이에 개체가 있는지 여부를 확인하십시오.local hitPositionif weaponRaycastResult thenhitPosition = weaponRaycastResult.PositionendweaponRaycastResult 에 값이 없으면 레이캐스트의 끝 위치를 계산하려면 도구 핸들의 위치를 추가하여 DirectionVector 와 함께 레이캐스트의 끝 위치를 계산하십시오. 이 를 directionVector 에 할당하십시오.
local weaponRaycastResult = workspace:Raycast(tool.Handle.Position, directionVector, weaponRaycastParams)-- 시작 위치와 끝 위치 사이에 개체가 있는지 여부를 확인하십시오.local hitPositionif weaponRaycastResult thenhitPosition = weaponRaycastResult.Positionelse-- 최대 레이저 거리에 따라 끝점 계산hitPosition = tool.Handle.Position + directionVectorendend도구 활성화 함수로 이동하고 fireWeapon 함수를 호출하여 도구가 활성화될 때마다 레이저가 발사됩니다.
local function toolActivated()tool.Handle.Activate:Play()fireWeapon()end
오브젝트 적중 확인
레이저가 플레이어의 캐릭터 중 하나인지 아니면 그냥 경치인지 찾으려면 모든 캐릭터에 하나의 Humanoid 을 찾아야 합니다.
먼저, 캐릭터 모델을 찾아야 합니다. 캐릭터의 부분이 타면 부모가 캐릭터인 것을 가정할 수 없습니다. 레이저는 신체 부분, 장신구또는 도구를 타기도 할 수 있지만, 이 모든 것은 캐릭터의 계층에 위치한 다른 부분에 있습니다.
레이저에 의해 명중된 개체의 조상을 찾으려면 FindFirstAncestorOfClass 을 사용할 수 있습니다. 모델이 있으면 레이저에 의해 조상이 발견된 모델의 조상을 찾을 수 있습니다. 모델에 인간형이 포함되어 있으면 대부분의 경우 해당 모��
아래에 표시된 코드를 weaponRaycastResult if 문에 추가하여 캐릭터가 타격되었는지 확인합니다.
-- 시작 위치와 끝 위치 사이에 개체가 있는지 여부를 확인하십시오.local hitPositionif weaponRaycastResult thenhitPosition = weaponRaycastResult.Position-- 타격당하는 인스턴스는 캐릭터 모델의 자식이 됩니다.-- 모델에서 휴머노이드가 발견된 경우 이는 플레이어의 캐릭터일 가능성이 높습니다.local characterModel = weaponRaycastResult.Instance:FindFirstAncestorOfClass("Model")if characterModel thenlocal humanoid = characterModel:FindFirstChildWhichIsA("Humanoid")if humanoid thenprint("Player hit")endendelse-- 최대 레이저 거리에 따라 끝점 계산hitPosition = tool.Handle.Position + directionVectorend
이제 레이캐스트 작업이 다른 플레이어를 때마다 Player hit 를 출력 창에 프린트해야 합니다.
여러 플레이어와 테스트
무기 레이캐스트가 다른 플레이어를 찾는지 테스트하려면 두 명의 플레이어가 필요합니다. 따라서 로컬 서버를 시작해야 합니다.
Studio의 테스트 탭을 선택합니다.
플레이어 드롭다운을 '2 플레이어'로 설정하고 시작 버튼을 클릭하여 로컬 서버에서 2 클라이언트로 시작하십시오. 세 개의 창이 나타납니다. 첫 번째 창은 로컬 서버이고, 다른 창은 플레이어 1 및 플레이어 2의 클라이언트입니다.
한 클라이언트에서 다른 플레이어를 클릭하여 무기로 쏘는 테스트를 수행합니다. 플레이어가 쏜 때마다 출력에 "Player hit"가 표시됩니다.
테스트 탭에 대해 자세히 알아보려면 여기에서 자세히 알아보세요.
레이저 위치 찾기
블래스터는 목표물에 빨간색 빔의 빛을 발사해야 합니다. 이 기능은 ModuleScript 내에 있으므로 나중에 다른 스크립트에서 사용할 수 있습니다. 먼저 스크립트는 레이저 빔이 렌더링되어야 할 위치를 찾아야 합니다.
LaserRender라는 이름의 모듈 스크립트 를 생성하고 StarterPlayer 아래에 있는 StarterPlayerScripts에 부모로 지정합니다.
스크립트를 열고 모듈 테이블을 레이저 렌더러 의 이름으로 이름을 변경합니다.
레이저가 보이는 시간(초)을 나타내는 변수 샷_지속_시간 을 0.15 로 선언합니다. 이것은 레이저가 보이는 시간(초)을 나타냅니다.
도구 처리기 createLaser 와 끝 위치 endPosition 를 가진 레이저 생성기 함수를 만듭니다.
local LaserRenderer = {}local SHOT_DURATION = 0.15 -- 레이저가 보이는 시간-- 시작 위치에서 레이저 빔 만들기function LaserRenderer.createLaser(toolHandle, endPosition)endreturn LaserRenderer변수 시작 위치 를 선언하고 위치 속성의 toolHandle을 값으로 설정합니다. 이 경우 플레이어의 레이저 블래스터의 위치가 됩니다.
레이저 거리 laserDistance 를 선언하고 시작 위치 endPosition 에서 레이저 빔의 길이를 찾기 위해 startPosition 을 뺍니다. 이 속성의 크기를 사용하여 레이저 빔의 길이를 얻습니다.
function LaserRenderer.createLaser(toolHandle, endPosition)local startPosition = toolHandle.Positionlocal laserDistance = (startPosition - endPosition).Magnitudeend레이저 빔의 위치 및 방향을 저장하기 위해 laserCFrame 변수를 선언하십시오. 위치는 시작 및 끝 사이의 레이저 빔의 중간 점이어야 합니다
function LaserRenderer.createLaser(toolHandle, endPosition)local startPosition = toolHandle.Positionlocal laserDistance = (startPosition - endPosition).Magnitudelocal laserCFrame = CFrame.lookAt(startPosition, endPosition) * CFrame.new(0, 0, -laserDistance / 2)end
레이저 부품 생성
이제 레이저 빔을 생성할 위치를 알았으니 빔 자체를 추가해야 합니다. 이 작업은 네온 부품으로 쉽게 수행할 수 있습니다.
변수 레이저Part 를 선언하고 새로운 Part 인스턴스를 할당합니다.
다음 laserPart 속성을 설정합니다.
- 크기 : Vector3.new(0.2, 0.2, laserDistance)
- CFrame : 레이저CFrame
- 고정된 상태 : true
- 충돌 가능 : false
- 색상 : Color3.fromRGB(225, 0, 0) (강한 빨간색 색상)
- 재료 : Enum.Material.Neon
부모 laserPart 에 Workspace .
Class.Debris 서비스에 부품을 추가하여 SHOT_DURATION 변수의 초당 금액 후에 제거됩니다.
function LaserRenderer.createLaser(toolHandle, endPosition)local startPosition = toolHandle.Positionlocal laserDistance = (startPosition - endPosition).Magnitudelocal 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 = laserCFramelaserPart.Anchored = truelaserPart.CanCollide = falselaserPart.Color = Color3.fromRGB(225, 0, 0)laserPart.Material = Enum.Material.NeonlaserPart.Parent = workspace-- 레이저 빔을 추가하여 잔해 서비스에서 제거되고 청소됩니다.Debris:AddItem(laserPart, SHOT_DURATION)end
이제 레이저 빔을 렌더링하는 기능이 완료되었으므로 도구 컨트롤러 라는 이름으로 호출할 수 있습니다.
도구 컨트롤러 스크립트의 상단에 있는 레이저 리플레이어라는 변수를 선언하고 플레이어 스크립트에 있는 레이저 리플레이어 모듈 스크립트를 요구합니다.
local UserInputService = game:GetService("UserInputService")local Players = game:GetService("Players")local LaserRenderer = require(Players.LocalPlayer.PlayerScripts.LaserRenderer)local tool = script.ParentfireWeapon 함수의 하단에서 도구 핸들과 createLaser 함수를 사용하여 레이저 생성기를 호출합니다.
-- 최대 레이저 거리에 따라 끝점 계산hitPosition = tool.Handle.Position + directionVectorendLaserRenderer.createLaser(tool.Handle, hitPosition)end플레이 버튼을 클릭하여 무기를 테스트하십시오. 도구가 활성화되면 레이저 빔이 무기와 마우스 사이에 표시됩니다.
무기 발사 속도 제어
플레이어가 너무 많은 피해를 입히지 못하도록 각 샷 사이에 지연이 필요합니다. 이는 플레이어가 마지막으로 발사한 시간 이후 얼마나 시간이 지났는지 확인하여 제어할 수 있습니다.
Fire_Rate라는 이름의 도구 컨트롤러 의 맨 위에 변수를 선언합니다. 이는 각 샷 사이의 최소 시간입니다. 선택한 값을 입력하십시오; 이 예에서는 0.3 초입니다.
변수 하나 더 선언하여 timeOfPreviousShot라는 이름의 변수를 값 0로 저장합니다. 이는 플레이어가 발사한 마지막 시간을 저장하고 각 샷과 함께 업데이트됩니다.
local MAX_MOUSE_DISTANCE = 1000local MAX_LASER_DISTANCE = 300local FIRE_RATE = 0.3local timeOfPreviousShot = 0매개 변수가 없는 canShootWeapon 함수를 만듭니다. 이 함수는 이전 샷이 지난 시간을 검토하고 참이거나 거짓이 아닌지 여부를 반환합니다.
local FIRE_RATE = 0.3local timeOfPreviousShot = 0-- 이전에 발사된 샷 이후 충분한 시간이 지났는지 확인하십시오local function canShootWeapon()endlocal function getWorldMousePosition()함수에서 현재 시간이라는 변수를 선언하고 tick() 함수의 결과를 할당합니다. 이는 1970년 1월 1일(임의의 날짜 사용)부터 지정된 시간(초)까지 지났는지 반환합니다.
현재 시간에서 timeOfPreviousShot를 뺄 수 없으면 결과가 currentTime보다 작으므로 반환하지 않고 작은 경우 반환하지 않고 나가게 됩니다. 그렇지 않으면 결과를 2> 작게 만들면 반환합니다. 그렇지 않으면 모두 반환합니다. Korean:현재 시간에서 time
-- 이전에 발사된 샷 이후 충분한 시간이 지났는지 확인하십시오local function canShootWeapon()local currentTime = tick()if currentTime - timeOfPreviousShot < FIRE_RATE thenreturn falseendreturn trueendfireWeapon 함수의 끝에, 매번 무기가 발사되면 timeOfPreviousShot 을 업데이트합니다.
hitPosition = tool.Handle.Position + directionVectorendtimeOfPreviousShot = tick()LaserRenderer.createLaser(tool.Handle, hitPosition)endtoolActivated 함수 내에서 if 문을 만들고 canShootWeapon 을 호출하여 무기를 발사할 수 있는지 확인합니다.
local function toolActivated()if canShootWeapon() thentool.Handle.Activate:Play()fireWeapon()endend
블래스터를 테스트할 때 가장 빠르게 클릭할 때도 항상 0.3초 정도의 지연이 발생합니다.
플레이어에게 피해를 주는
클라이언트는 다른 클라이언트에게 직접 피해를 줄 수 없습니다. 서버는 플레이어가 타격을 받을 때 피해를 발생시켜야 합니다.
클라이언트는 RemoteEvent 를 사용하여 서버에 캐릭터가 타격되었음을 알릴 수 있습니다. 이 것은 ReplicatedStorage 에 저장되어 클라이언트와 서버 모두에게 표시됩니다.
ReplicatedStorage의 이벤트라는 이름의 폴더를 생성합니다.
원격 이벤트를 이벤트 폴더에 삽입하고 이름을 지정합니다 DamageCharacter .
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.Parentlocal eventsFolder = ReplicatedStorage.Eventslocal MAX_MOUSE_DISTANCE = 1000local MAX_LASER_DISTANCE = 500DamageCharacter 원격 이벤트를 손질하기 위해 fireWeapon 프린트 문에 Lua 줄을 대체하십시오.
local characterModel = weaponRaycastResult.Instance:FindFirstAncestorOfClass("Model")if characterModel thenlocal humanoid = characterModel:FindFirstChildWhichIsA("Humanoid")if humanoid theneventsFolder.DamageCharacter:FireServer(characterModel)endendelse-- 최대 레이저 거리에 따라 끝점 계산hitPosition = tool.Handle.Position + directionVectorend
이벤트가 발생했을 때 플레이어에게 피해를 입히는 서버가 필요합니다.
ServerScriptService에 스크립트를 삽입하고 이름을 ServerLaserManager로 지정합니다.
LASER_DAMAGE라는 변수를 선언하고 값을 10 또는 선택한 값으로 설정합니다.
playerFired 및 캐릭터에 피해를 라는 이름의 함수를 두 개 만들고
함수 내에서 캐릭터의 휴머노이드를 찾아 LASER_DAMAGE 를 건강에서 뺍니다.
이벤트 폴더의 이벤트 센터에 있는 damageCharacter 함수를 DamageCharacter 리모트 이벤트에 연결하십시오.
local ReplicatedStorage = game:GetService("ReplicatedStorage")local eventsFolder = ReplicatedStorage.Eventslocal LASER_DAMAGE = 10function damageCharacter(playerFired, characterToDamage)local humanoid = characterToDamage:FindFirstChildWhichIsA("Humanoid")if humanoid then-- 캐릭터의 체력 제거humanoid.Health -= LASER_DAMAGEendend-- 이벤트를 적절한 함수에 연결하십시오eventsFolder.DamageCharacter.OnServerEvent:Connect(damageCharacter)로컬 서버를 시작하여 블래스터를 테스트하십시오. 다른 플레이어를 쏠 때 그들의 체력이 LASER_DAMAGE 으로 줄어듭니다.
다른 플레이어의 레이저 빔 렌더링
현재 레이저 빔은 무기를 발사하는 클라이언트에 의해 생성되므로 무기를 발사한 클라이언트만 레이저 빔을 볼 수 있습니다.
레이저 빔이 서버에 생성된 경우 모든 사람이 볼 수 있습니다. 그러나 클라이언트가 무기를 쏠 때 서버에서 정보를 수신하는 간에 약간의 지연 이 발생합니다. 이렇게 하면 클라이언트가 무기를 활성화하면 서버에서 느끼는 지연이 증가합니
이 문제를 해결하기 위해, 모든 클라이언트는 자신만의 레이저 빔을 생성합니다. 즉, 클라이언트가 무기를 쏠 때 레이저 빔을 즉시 볼 수 있습니다. 다른 클라이언트는 다른 플레이어가 쏠 때와 레이저 빔이 나타나는 시간 간의 작은 지연을 경험합니다. 이 경
샤이더 클라이언트
먼저, 클라이언트는 서버에게 레이저를 발사했다고 알리고 종료 위치를 제공해야 합니다.
ReplicatedStorage의 이벤트 폴더에 원격 이벤트를 삽입하고 이름을 LaserFired로 지정합니다.
도구 컨트롤러 스크립트의 fireWeapon 함수를 찾습니다. 함수의 끝에서 LaserFired 원격 이벤트를 사용하여 hitPosition 을 인수로 화면을 표시합니다.
hitPosition = tool.Handle.Position + directionVectorendtimeOfPreviousShot = tick()eventsFolder.LaserFired:FireServer(hitPosition)LaserRenderer.createLaser(tool.Handle, hitPosition)end
서버
이제 서버는 클라이언트가 발사한 이벤트를 수신하고 모든 클라이언트에게 레이저 빔의 시작 및 끝 위치를 알려야 합니다.
In the ServerLaserManager script, create a function named playerFiredLaser above damageCharacter with two parameters called 1> playerFired1> and 4> endPosition4> .
함수를 레이저 발사 원격 이벤트에 연결하십시오.
-- 레이저가 발사되었음을 모든 클라이언트에 알려주려면 레이저를 표시합니다.local function playerFiredLaser(playerFired, endPosition)end-- 이벤트를 적절한 함수에 연결하십시오eventsFolder.DamageCharacter.OnServerEvent:Connect(damageCharacter)eventsFolder.LaserFired.OnServerEvent:Connect(playerFiredLaser)
서버는 레이저의 시작 위치를 필요로 합니다. 이것은 클라이언트에서 보낼 수 있지만, 최선을 다해 클라이언트를 신뢰하는 것이 좋습니다. 캐릭터의 무기 핸들 위치가 시작 위치이므로 서버는 여기에서 찾을 수 있습니다.
함수 생성 getPlayerToolHandle 위의 playerFiredLaser 함수에 매개 변수로 player 이름을 지정합니다.
다음 코드를 사용하여 플레이어의 캐릭터를 검색하고 핸들 개체를 반환합니다.
local LASER_DAMAGE = 10-- 플레이어가 들고 있는 도구의 핸들을 찾습니다.local function getPlayerToolHandle(player)local weapon = player.Character:FindFirstChildOfClass("Tool")if weapon thenreturn weapon:FindFirstChild("Handle")endend-- 레이저가 발사되었음을 모든 클라이언트에 알려주려면 레이저를 표시합니다.local function playerFiredLaser(playerFired, endPosition)
이제 서버는 레이저 발사 원격 이벤트에서 레이저 이미지를 렌더링하기 위해 필요한 정보를 보내려면 FireAllClients 를 호출할 수 있습니다. 여기에는 레이저를 발사한 플레이어(이므로 클라이언트에 대한
In the playerFiredLaser function, call the getPlayerToolHandle function with playerFired as an argument and assign the value to a variable named 1> toolHandle1> .
도구 핸들이 있으면 모든 클라이언트에서 LaserFired 이벤트를 발생시키고, playerFired , toolHandle 및 2> endPosition2>을 인수로 사용합니다.
-- 레이저가 발사되었음을 모든 클라이언트에 알려주려면 레이저를 표시합니다.local function playerFiredLaser(playerFired, endPosition)local toolHandle = getPlayerToolHandle(playerFired)if toolHandle theneventsFolder.LaserFired:FireAllClients(playerFired, toolHandle, endPosition)endend
클라이언트에서 렌더링
이제 FireAllClients 가 호출되었으며, 각 클라이언트는 서버로부터 이벤트를 받아 레이저 빔을 렌더링합니다. 각 클라이언트는 도구의 핸들 위치 및 종료 위치 값을 사용하여 레이저 빔을 렌더링하는 도구의 모듈을 이전에
StarterPlayerScripts의 로컬 스크립트를 만들어 클라이언트 레이저 관리자라는 이름의 스타터 플레이어 스크립트에 합니다.
스크립트 내에서 레이저 렌더러 모듈을 필요로 합니다.
매개 변수 playerWhoShot , playerWhoShot 및 toolHandle 을 가진 함수 이름 1> createPlayerLaser1> 을 생성합니다.
Events 폴더에 있는 LaserFired 리모트 이벤트에 함수를 연결하십시오.
함수에서 if 문을 사용하여 playerWhoShot이 로컬 플레이어와 같지 않은지 확인합니다.
if 문 내에서 createLaser 함수를 사용하여 레이저 렌더러 모듈에서 toolHandle 및 endPosition 을 인수로 호출합니다.
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 thenLaserRenderer.createLaser(toolHandle, endPosition)endendeventsFolder.LaserFired.OnClientEvent:Connect(createPlayerLaser)로컬 서버를 시작하여 블래스터를 테스트하십시오. 각 클라이언트를 모니터의 다른 측면에 둔 다음 둘 중 하나를 잠깐 볼 수 있습니다. 한 클라이언트에서 쏠 때 다른 클라이언트에서 레이저를 볼 수 있습니다.
음향 효과
발사 음향 효과는 현재 발사 프로젝티리 하는 클라이언트에서만 재생됩니다. 다른 플레이어가 들을 수 있도록 코드를 이동해야 합니다.
도구 컨트롤러 스크립트에서 도구 활성화 함수로 이동하고 활성화 사운드를 재생하는 줄을 제거하십시오.
local function toolActivated()if canShootWeapon() thenfireWeapon()endendcreateLaser 함수의 하단에 있는 LaserRender 에서 변수명 shootingSound 를 선언하고 1> Class.Instance:FindFirstChild()|FindFirstChild()1> 메서드를 사용하여 4> 활성화4> 사운드를 검사합니다.
Use an if 문을 사용하여 shootingSound 이 있는지 확인하십시오; 그렇다면, Play 함수를 호출합니다.
laserPart.Parent = workspace-- 레이저 빔을 추가하여 잔해 서비스에서 제거되고 청소됩니다.Debris:AddItem(laserPart, SHOT_DURATION)-- 무기 샷 사운드 재생local shootingSound = toolHandle:FindFirstChild("Activate")if shootingSound thenshootingSound:Play()endend
유효성 검사를 사용하여 리모트 보안
서버가 수신된 요청에서 데이터를 검사하지 않으면 해커는 원격 함수 및 이벤트를 남용하여 서버에 가짜 값을 전송할 수 있습니다. 이를 방지하려면 서버 사이드 유효성 검사를 사용하는 것이 좋습니다.
현재 형태의 DamageCharacter 원격 이벤트는 매우 취약합니다. 해커는 이 이벤트를 사용하여 게임에서 원하는 플레이어에 피해를 줄 수 있습니다. 슛하지 않고 플레이어를 게임에 피해를 줄 수 있습니다.
유효성 검사는 서버에 전송되는 값이 현실적인지 확인하는 프로세스입니다. 이 경우 서버는 다음을 필요로 합니다.
- 레이저가 표시하는 위치와 플레이어가 표시하는 위치 사이의 거리가 특정 경계 내에 있는지 확인하십시오.
- 레이캐스트는 레이저를 발사한 무기와 히트 위치 사이에서 수행하여 샷이 가능하고 벽을 통과하지 않도록 합니다.
클라이언트
클라이언트는 레이캐스트에 의해 히트된 위치를 서버에 전송하여 거리가 현실적인지 확인해야 합니다.
In ToolController , DamageCharacter 원격 이벤트가 발생하는 라인으로 이동합니다. fireWeapon 함수.
hitPosition을 인수로 추가합니다.
if characterModel thenlocal humanoid = characterModel:FindFirstChildWhichIsA("Humanoid")if humanoid theneventsFolder.DamageCharacter:FireServer(characterModel, hitPosition)endend
서버
이제 클라이언트는 공격 캐릭터 원격 이벤트를 통해 추가 매개 변수를 보내고 있으므로 ServerLaserManager 를 조정해야 합니다.
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_DAMAGEendendgetPlayerToolHandle 함수 아래에, 세 매개 변수로 이름이 isHitValid 인 함수를 만듭니다. playerFired , 1> characterToDamage1> 및 4> hitPosition4> .
endlocal function isHitValid(playerFired, characterToDamage, hitPosition)end
첫 번째 검사는 히트 위치와 캐릭터 히트 사이의 거리입니다.
스크립트 상단에 있는 MAX_HIT_PROXIMITY 라는 변수를 선언하고 10 값을 할당합니다. 이는 히트와 캐릭터 사이의 최대 거리입니다. 캐릭터가 이벤트를 발생시킬 때 슬라이트를 조정하는 데 사용되는 최대 거리입니다. 쿠폰을 사용하면 클라이언트가
local ReplicatedStorage = game:GetService("ReplicatedStorage")local eventsFolder = ReplicatedStorage.Eventslocal LASER_DAMAGE = 10local MAX_HIT_PROXIMITY = 10In the isHitValid 함수에서 캐릭터와 히트 위치 사이의 거리를 계산합니다. 거리가 MAX_HIT_PROXIMITY보다 큰 경우 반환 하고 나머지는 1>거리1>로 나머지 부분을 계산합니다.
local function isHitValid(playerFired, characterToDamage, hitPosition)-- 캐릭터 히트와 히트 위치 사이의 거리 검사local characterHitProximity = (characterToDamage.HumanoidRootPart.Position - hitPosition).Magnitudeif characterHitProximity > MAX_HIT_PROXIMITY thenreturn falseendend
두 번째 검사는 발사된 무기와 타격 위치 사이의 레이캐스트를 포함합니다. 레이캐스트가 캐릭터가 아닌 개체를 반환하면 슛이 유효하지 않은 것으로 간주됩니다. 슛이 차단되었기 때문일 수 있습니다.
이 확인수행하려면 아래 코드를 복사하십시오. 함수 끝에 true 를 반환합니다: 함수가 종료도달하면 모든 검사가 통과합니다.
local function isHitValid(playerFired, characterToDamage, hitPosition)-- 캐릭터 히트와 히트 위치 사이의 거리 검사local characterHitProximity = (characterToDamage.HumanoidRootPart.Position - hitPosition).Magnitudeif characterHitProximity > 10 thenreturn falseend-- 벽을 통과하여 샷하는 경우 확인local toolHandle = getPlayerToolHandle(playerFired)if toolHandle thenlocal rayLength = (hitPosition - toolHandle.Position).Magnitudelocal rayDirection = (hitPosition - toolHandle.Position).Unitlocal raycastParams = RaycastParams.new()raycastParams.FilterDescendantsInstances = {playerFired.Character}local rayResult = workspace:Raycast(toolHandle.Position, rayDirection * rayLength, raycastParams)-- 캐릭터가 아닌 인스턴스가 타격되면 샷을 무시하십시오.if rayResult and not rayResult.Instance:IsDescendantOf(characterToDamage) thenreturn falseendendreturn trueend결과 없는 샷 을 호출하는 damageCharacter 함수에 변수를 선언하십시오. playerFired , isHitValid 및 1> isHitValid1> 함수에 3개의 인수로 호출을 할당하십시오. 4> playerFired4>, 7> CharacterToDamage</
아래 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_DAMAGEendend
이제 공격 캐릭터 원격 이벤트는 더 안전하며 대부분의 플레이어가 이를 남용하지 않도록 합니다. 일부 악성 플레이어는 유효성 검사 주위에 다양한 방법을 찾을 수 있지만 원격 이벤트를 보호하는 것은 지속적인 노력입니다.
레이캐스팅을 사용하여 기본 히트 감지 시스템을 구현한 레이저 블래스터가 이제 완성되었습니다. 사용자 입력 감지 튜토리얼을 시작하여 레이저 블래스터에 재장전 작업을 추가하거나 다른 플레이어와 함께 훌륭한 게임 맵을 만들어 보세요!
최종 코드
도구 컨트롤러
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)