작성자 : CHAN
최종 업데이트 : 2021.04.26
기타 : 애니메이션 적용 과정을 순서대로 업로드할 예정
이 예제에서는 내가 로블록스에 저장시킨 애니메이션들을 불러와 마우스로 공격 했을 때, 해당 애니메이션들을 실행시킬 수 있다. 마우스 한번클릭, 2번클릭에 따라 다른 애니메이션을 적용 시킨다.
그후 HitBox를 생성하여 해당 부위에 붙혀준다.
주석에 서술한 내용이 많으므로 주석을 잘 읽어볼 것
사전준비
- 로블록스에 저장된 애니메이션들 ( 주먹공격 애니메이션, 발차기 애니메이션 등등 2개 이상 )
- roblox-blog.tistory.com/28 글의 3-6 (로블록스에 애니메이션 저장하기)까지 진행하고 이어서 하면 됨
- 이 글에서 사용한 애니메이션 (태권소년)
www.roblox.com/library/6729954651/Taekwon2
www.roblox.com/library/6730003404/Taekwon3
www.roblox.com/library/6729998143/Taekwon4
1. 스크립트 생성하기
- StarterPlayer - StarterCharacterScripts 안에서 진행( 왜 이 폴더 안에서 코딩해야할까? )
1. LocalScript 생성( Combat2 으로 이름 변경)
2. Combat2 안에 Script 생성 ( CombatSystem2 으로 이름 변경 )
3. CombatSystem2 안에 Folder 생성 ( Animations 으로 이름 변경 )
4. Animations 안에 내가 만든 애니메이션 추가하기
1) Animations 옆 "+" 버튼클릭 -> animation을 검색해서 추가한다.
2) properties 에서 AnimationsId 에 내가 로블록스에 올린 애니메이션 링크를 넣는다 ( 자동으로 rbxasset...으로 변경된다)
3) 애니메이션 이름을 변경한다.
- ReplicatedStorage 안
1. Remote Event를 생성한다. ( HitEvent 로 이름 변경)
- Combat2 : 전투 관련 클라이언트 코드
- CombatSystem2 : 전투 관련 서버 코드
- HitEvent : 전투시 클라 , 서버를 연결할때 발생시키는 이벤트 ( Remote event 공부 )
2. 클라이언트 부분 ( Combat2 )
StarterPlayer / StarterCharacterScripts / combat2(LocalScript)
공부해야할 사항: TweenService, RemoteEvent, CFrame, UserInputService
-1. 인스턴스 생성 및 변수 선언
local Player = game.Players.LocalPlayer --goyou_chan
local Character = Player.Character --goyou_chan
local Humanoid = Character:FindFirstChild("Humanoid") --Humanoid
local UserInputService = game:GetService("UserInputService") --inputObject
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local HitEvent = ReplicatedStorage:WaitForChild("HitEvent")
--local TweenService = game:GetService("TweenService")
local combo = 1 -- 진행시킬 콤보
local current = 0 -- 현재 마우스 클릭 시간
local prev = 0 -- 이전 마우스를 클릭 시간
local debounce = false -- 애니메이션이 실행중인지 판별하는 변수 (애니메이션 중복 플레이 못하도록 하는데 사용)
서비스 연결 및 전투관련 스크립트에 필요한 인스턴스들을 생성해준다.
tween은 추후에 추가될 예정
-2. 마우스 클릭 시 서버로 이벤트 전송
--유저의 입력을 받았을 때 일어나는 함수
UserInputService.InputBegan:Connect(function(input)
--유저가 어떤 키를 누르는지 다 알 수 있게 해준다.
--print(input.UserInputType)
--사용자가 마우스 왼쪽클릭 한 경우
if input.UserInputType == Enum.UserInputType.MouseButton1 then
--애니메이션 실행중이 아닌 경우
if not debounce then
debounce = true
prev = current -- 이전 클릭 시간
current = tick() -- 현재 클릭 시각
local gap = current - prev
warn("Gap : "..gap) --마우스 클릭 간격 차이
-- 콤보 계산 로직
-- 콤보 수마다 코드가 달라져야 하므로 나중에 변경되야함 지금은 2콤보 기준으로 작성
-- 클라에서 서버로 combo라는 변수값을 보내서 1이면 콤보1 실행, 2면 콤보 2 실행
if gap > 0.8 then -- 이전 클릭과의 시간 gap이 0.8초 초과면 콤보 해제
combo = 1
HitEvent:FireServer(combo)
combo = combo + 1
elseif combo == 1 and gap <= 0.8 then
HitEvent:FireServer(combo)
combo = combo + 1
elseif combo == 2 then
HitEvent:FireServer(combo)
combo = 1
end
--애니메이션 끝난 후 애니메이션 진행중이 아니라고 상태 저장
debounce = false
end
end
end)
현재는 2콤보 기준으로 작성되었다
print(input.UserInputType) 으로 유저가 어떤 키(키보드,마우스 등등)를 입력하는지 다 알 수 있다.
1. 마우스 클릭 간격차이로 combo 값을 서버로 보낸다.
2. 서버에서 받은 combo값에 따라 실행시키는 애니메이션이 달라진다.
마우스 왼쪽 클릭 시
Enum.UserInputType.MouseButton1,
우클릭시
Enum.UserInputType.MouseButton2 등등, 키보드도 알 수있다.
tick() 은 1970.1.1 부터 기록되는 시간값이다. 시간계산할때 용이하게 쓰인다.
Enum은 뭔지 잘 모르겠다.
3. 서버 부분 ( CombatSystem2 )
StarterPlayer / StarterCharacterScripts / combatSystem2(Script)
공부해야할 사항: TweenService, RemoteEvent, CFrame, Debris, WeldConstraint, Animator
-1. 클라에서 보낸 이벤트에 응답해 애니메이션 실행시키기
--전투 관련 서버 코드
local Player = game:GetService("Players").LocalPlayer
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local HitEvent = ReplicatedStorage:WaitForChild("HitEvent")
local Animations = script:WaitForChild("Animations")
local Debris = game:GetService("Debris") -- Hitbox에서 사용( 공부하기 )
------------------------------------------------------
--[[애니메이션 모음 테이블 ]]--
local anims = { -- 유저 공격 순서(콤보)
--Animations:WaitForChild("Taekwon2"),
Animations:WaitForChild("Taekwon3"),
Animations:WaitForChild("Taekwon4")
}
--마우스 클릭 했을때 HitEvent받는 부분 / 자동으로 Player 가 첫번째 파라미터에 추가됨
HitEvent.OnServerEvent:Connect(function(Player, combo)
print("마우스 왼쪽클릭시 서버에서 받음")
local Character = Player.Character
local Humanoid = Character:FindFirstChild("Humanoid")
local Humrp = Character:WaitForChild("HumanoidRootPart")
local Animator = Humanoid:FindFirstChildOfClass("Animator")
--받은 콤보변수값에 따라 다른 애니메이션을 실행시킨다.
local attack = Animator:LoadAnimation(anims[combo])
attack:Play()
end)
1. 전투 시 필요한 인스턴스들을 변수로 받아온다.
2. HitEvent.OnServerEvent:Connect 부분은 Combat2 (클라이언트) 에서 FireServer() 으로 발생시킨 이벤트를 받는 부분이다.
로컬에서 서버로 이벤트를 발생시킬때는 항상 player가 첫번째 파라미터로 들어온다. 서버측에서 누가 보낸건지 알아야 하기 때문이다.
HumanoidRootPart는 왜 쓰일까?
꼭 애니메이션을 폴더 안에 저장해놓고 써야하나? 필요할 때 인스턴스를 생성해서 사용하면 편하지 않을까?
이제 플레이를 해보자. 내 캐릭터에 내가 만든 애니메이션이 적용 된 것을 확인할 수 있다.
만약 애니메이션이 실행이 안된다면, AnimationID, AnimationName을 잘 확인해 볼 것
-2. HitBox 생성하기
HitBox도 결국에는 하나의 Part이다.
추후에는 투명도를 0으로 하여 범위를 조절하면 될 것같다.
1) 먼저, Part를 만든 뒤, ReplicatedStorage에 추가한다. (이름을 Hitbox로 변경한다 )
--[[애니메이션 모음 테이블 ]]--
local anims = { -- 유저 공격 순서(콤보)
--Animations:WaitForChild("Taekwon2"),
Animations:WaitForChild("Taekwon3"),
Animations:WaitForChild("Taekwon4")
}
-- 여기부터 추가하는 내용입니다!!!!!!!!!!!!
-- 해당 부분 추가하기
-- 유저가 타격할 때 사용한 부위. ( 콤보순서랑 순서가 맞아야함 + 애니메이션 만들때 어느 부위인지 기억)
-- 해당 부위에 HitBox가 생성될 예정
local limbs = {
"LeftFoot",
"RightFoot"
}
-------------[[로컬 함수]]-----------------------------
local function CreateHitbox(Player,combo)
local Character = Player.Character
local Limb = Character:WaitForChild(limbs[combo]) -- combo에 따라 어느 부위로 때렸는지 가져온다.
--플레이어 이름의 폴더를 생성한다.
local folder = Instance.new("Folder", Character)
folder.Name = Player.Name
-- 객체를 복사해준다. (복사해주는 이유는 계속 생성됐다가 사라지는걸 반복해야 하기 때문에 본 객체는 건들면 안된다.)
local Hitbox = ReplicatedStorage:WaitForChild("Hitbox"):Clone()
Hitbox.CFrame = Limb.CFrame -- Hitbox의 위치를 타격할때 사용한 부위와 일치시킨다.
Hitbox.Parent = folder -- ?? 왜 parent 지정해주는지 모르겠음
Debris:AddItem(folder, .5) -- Hitbox를 0.5초 후 사라지게 한다.
local weld = Instance.new("WeldConstraint")
weld.Part0 = Hitbox -- Part0은 용접할 첫번째 Part ( 히트박스와 플레이어가 맞닿는 부위 )
weld.Part1 = Limb -- Part1은 용접할 두번째 Part ( 플레이어의 부위 )
weld.Parent = workspace
Debris:AddItem(weld, .5) -- 마찬가지로 용접부위도 0.5초후 사라지게 함
return Hitbox
end
--마우스 클릭 했을때 HitEvent받는 부분 / 자동으로 Player 가 첫번째 파라미터에 추가됨
--애니메이션을 실행시키고, Hitbox를 추가하는 코드
HitEvent.OnServerEvent:Connect(function(Player, combo)
print("마우스 왼쪽클릭시 서버에서 받음")
local Character = Player.Character
local Humanoid = Character:FindFirstChild("Humanoid")
local Humrp = Character:WaitForChild("HumanoidRootPart")
local Animator = Humanoid:FindFirstChildOfClass("Animator")
--받은 콤보변수값에 따라 다른 애니메이션을 실행시킨다.
local attack = Animator:LoadAnimation(anims[combo])
attack:Play()
-- Hitbox 생성 ( 이 부분 추가 )
local Hitbox = CreateHitbox(Player, combo)
end)
<추가되는 코드 설명 >
1. limbs 라는 테이블을 생성하고, 내가 Hitbox를 붙힐 파트의 위치들을 저장한다.
이때, anims 테이블의 애니메이션순서와 limbs 테이블의 타격 위치가 일치해야 한다.
(내가 만드는 애니메이션의 동작과 갯수에 따라 달라질 수 있다. )
2. CtreateHitbox() - 히트박스를 만들어주는 함수를 추가한다. (파라미터로 플레이어와 콤보가 들어간다)
(WeldConstraint, CFrame 모른다면 공부하기)
3. HitEvent.OnServerEvent:Connect 부분에 애니메이션 플레이 후 HibBox를 생성하는 함수를 사용한다.
이제 플레이를 해보면 내가 만든 애니메이션에 Hitbox가 추가된 모습을 확인 할 수 있다.
다음편에서는 Hitbox에 데미지를 넣을 것이다.
'Learn' 카테고리의 다른 글
전투 애니메이션 로직 - (3) 방어하기 (0) | 2021.04.28 |
---|---|
전투 애니메이션 로직 - (2) Hitbox에 터치이벤트 넣기 (0) | 2021.04.26 |
Customizing the Camera (카메라 커스터마이징) (0) | 2021.04.25 |
Camera Manipulation (0) | 2021.04.24 |
Particle Emitters (0) | 2021.04.22 |
댓글