[함께해요, 로블록스 코딩]
*해당 게시글 내용은 오규환 교수님께서 실제 게임 개발자들이 하는 방식으로 짠 코드입니다. 천천히 따라해보세요. 만약 아래 내용이 어렵다면, 기사를 다운받아 교수님의 코드를 좀 더 쉽게 요약한 내용을 확인해보세요.
[함께해요, 로블록스 코딩] 숨바꼭질 게임 (2) : 게임 맵 구성, 게임 로직
# (이번호 주제) 게임 맵 구성, 게임 로직
이번호에서는 숨바꼭질 게임 진행 맵 구성, 인터페이스에 값 표시 스크립트, 전체 게임 로직을 알아보도록 하겠습니다.
# 숨바꼭질 게임 맵 구성 : 로비맵, 게임맵
숨바꼭질 게임은 ‘로비맵’와 ‘게임맵‘의 2개 영역으로 구성됩니다. ’로비맵‘에는 스폰로케이션이 있어 게임에 접속하면 이 장소에 모이게 됩니다. ’로비맵‘에 있는 플레이어 중 1명이 술래가 되면 술래와 다른 플레이어들은 각각 ’게임맵‘의 ’SeekerSpawnLocation‘ 과 HiderSpawnLocation 위로 이동됩니다.
[게임맵 구성]
[게임맵 구성 (워크스패이스)]
# 숨바꼭질 게임 인터페이스에 남은 시간, 플레이어 수 표시10
숨바꼭질 게임은 여러 플레이어가 온라인으로 진행되으로 게임 진행시간 과 플레이어 수는 서버로부터 데이터를 전송받아 화면에 표시합니다. 서버로부터 관련 데이터를 받기 위해 ‘탐색기→ReplicatedStorage→ ’를 눌러 ‘StringValue‘를 2개 추가 후, 각각 ’Timer‘, ’PlayerLeft’로 변경합니다. ‘탐색기→StarterGui→HUD→
’를 눌러 ‘LocalScript‘를 추가하고 ReplicatedStorage 아래의 Timer와 PlayerLeft 값이 변경될때마다 HUD 아래의 ‘Timer, PlayerLeft 값을 변경하여 화면에 보이도록 합니다.
[ReplicatedStorage 와 StarterGui 구성]
탐색기→StarterGui→HUD→LocalScript 코드는 다음과 같습니다.
local ReplicatedStorage = game:GetService("ReplicatedStorage") local timer = ReplicatedStorage.Timer local playersLeft = ReplicatedStorage.PlayersLeft local HUD = script.Parent local timerFrame = HUD:WaitForChild("Timer") local playersLeftFrame = HUD:WaitForChild("PlayersLeft") |
ReplicatedStorage에서 timer, playersLeft를 가져오고 HUD에서 timerFrame, playersLeftFrame를 가져온다. |
timer:GetPropertyChangedSignal("Value"):Connect(function() timerFrame.Timer.Text = timer.Value end) playersLeft:GetPropertyChangedSignal("Value"):Connect(function() playersLeftFrame.PlayersLeft.Text = playersLeft.Value end) |
timer, playersLeft 값이 변경될떄마다 HUD의 인터페이스에 해당 값을 표시한다. |
# 숨바꼭질 게임 로직
’탐색기→ServerScriptService→ ’에 Script를 추가하여 게임 로직이 서버에서 동작하도록 합니다. 게임 로직은 다음 단계로 나눠집니다.
[’탐색기→ServerScriptService→ ’로 Script 추가 후 GameLoop로 이름 변경]
단계1. 2인 이상이 접속할때까지 대기
단계2. 무작위로 술래 정하기, 술래가 빠르게 걷도록 속고 변경
단계3. 나머지 플레이어를 PlayMap의 HiderSpawnLocation 위치로 이동
단계4, 다른 플레이어가 술래와 부딪히면 죽도록 이벤트 세팅
단계4, 다른 플레이어가 술래와 부딪히면 죽도록 이벤트 세팅
단계5, 플레이어들이 도망가도록 3초 동안 대기
단계6. 술레를 PlayMap의 SeekerSpawnLocation 위치로 이동
단계7. 60초 동안 술래잡기 놀이 시작
단계7. 타이머가 0이 되거나 모든 플레이어가 잡히면 종료 후 승패 판정하기
단계8. 타이머 종료 후 게임 상태 복원
GameLoop 스크립트의 주요 코드 내용은 다음과 같습니다.
함수 선언 |
플레이어 이동 |
local function teleportPlayers(players, spawn) end |
술래에게 잡힌 플레이 처리 |
local function removePlaye(player) end |
|
술래의 충돌 처리 이벤트 |
local function setHitBoxTouchEvent(hitbox) end |
|
무한루프 |
단계1 (대기) |
while #game.Players:GetPlayers() < 2 do wait(1) end |
단계2. (술레 결정, 세팅) |
gamePlayers = game.Players:GetPlayers() local seeker =gamePlayers[math.random(1, #gamePlayers)] removePlaye(seeker) wait(1) seeker.Character.Humanoid.WalkSpeed = 32 wait(3) |
|
단계3, (플레이어이동) |
teleportPlayers(gamePlayers, gamePlayMap.HiderSpawnLocation) wait(5) |
|
단계4. (술레와 부딪히는 이벤트 설정) |
setHitBoxTouchEvent(seeker.Character.HumanoidRootPart) |
|
단계5. (3초 대기) |
for i = 3, 0, -1 do timer.Value = ("%02i:%02i"):format(i/60%60, i%60) playersLeft.Value = #gamePlayers wait(1) end |
|
단계6. (술레 이동) |
teleportPlayers({seeker}, gamePlayMap.SeekerSpawnLocation) wait(3) |
|
단계7. (60초 동안 술레잡기 진행) |
local winner = "Hider" for i = 60, 0, -1 do timer.Value =("%02i:%02i"):format(i/60%60, i%60) playersLeft.Value = #gamePlayers if #gamePlayers == 0 then winner = "Seeker" break end wait(1) end |
|
단계8. (게임상태정리) |
if seekerHitboxConnection then seekerHitboxConnection:Disconnect() end seeker.Character.Humanoid.WalkSpeed = 16 wait(10) |
[GameLoop 주요 코드 내용]
(Game Loop전체 코드)
local ReplicatedStorage = game:GetService("ReplicatedStorage") local message = ReplicatedStorage.Message local timer = ReplicatedStorage.Timer local playersLeft = ReplicatedStorage.PlayersLeft
local gamePlayMap = game.Workspace.PlayMap local gamePlayers = {} local seekerHitboxConnection
local function teleportPlayers(players, spawn) for _, player in pairs(players) do if player.Character then player.Character:MoveTo(spawn.Position + Vector3.new(0, 5, 0)) end end end
local function removePlaye(player) for i, plr in pairs(gamePlayers) do if plr == player then table.remove(gamePlayers, i) end end end
local function setHitBoxTouchEvent(hitbox) seekerHitboxConnection = hitbox.Touched:Connect(function(hit) local player = game.Players:GetPlayerFromCharacter(hit.Parent) if player then removePlaye(player) if player.Character then player.Character.Humanoid.Health = 0 end end end) end
while wait(1) do while #game.Players:GetPlayers() < 2 do wait(1) end
gamePlayers = game.Players:GetPlayers() local seeker =gamePlayers[math.random(1, #gamePlayers)] removePlaye(seeker) wait(1) seeker.Character.Humanoid.WalkSpeed = 32 wait(3)
teleportPlayers(gamePlayers, gamePlayMap.HiderSpawnLocation) wait(5)
setHitBoxTouchEvent(seeker.Character.HumanoidRootPart)
for i = 3, 0, -1 do timer.Value = ("%02i:%02i"):format(i/60%60, i%60) playersLeft.Value = #gamePlayers wait(1) end
teleportPlayers({seeker}, gamePlayMap.SeekerSpawnLocation) wait(3)
local winner = "Hider" for i = 60, 0, -1 do timer.Value =("%02i:%02i"):format(i/60%60, i%60) playersLeft.Value = #gamePlayers if #gamePlayers == 0 then winner = "Seeker" break end wait(1) end
if seekerHitboxConnection then seekerHitboxConnection:Disconnect() end seeker.Character.Humanoid.WalkSpeed = 16 wait(10) end |
timer, playersLeft 값이 변경될떄마다 HUD의 인터페이스에 해당 값을 표시한다. |