간단한 적의 AI를 만들어 봤다.

적 AI

너무 단순해서 순서도를 그릴 가치도 없음. ㅋ

 

공격은 애니메이션을 찾기 귀찮기 때문에 크기를 키웠다가 줄이는 것으로 표현했다.

일단 동작은 잘 되는데 로블록스는 멀티가 기본인 거 같아서 로컬에서 반복을 돌리는거보다 서버의 틱에 맞춰서 돌아가도록 해봤다.

 

이제 적과 플레이어의 상호작용을 만들면 얼추 플레이는 가능할 것 같다.

local enemy = script.Parent
local speed = 10
local attackRange = 10 -- 공격 범위
local attackTime = 0.25 -- 공격 애니메이션 시간
local attackCooldown = 1 -- 공격 쿨다운 시간
local isAttacking = false -- 공격 중 여부
local lastAttackTime = 0 

local RunService = game:GetService("RunService")

local bodyVelocity = Instance.new("BodyVelocity", enemy)
bodyVelocity.MaxForce = Vector3.new(4000, 4000, 4000)
bodyVelocity.Parent = enemy

local function GetClosestPlayer()
	local closestPlayer = nil
	local shortestDistance = math.huge

	for _, player in ipairs(game.Players:GetPlayers()) do
		local character = player.Character
		if character and character:FindFirstChild("HumanoidRootPart") then
			local distance = (enemy.Position - character.HumanoidRootPart.Position).Magnitude
			if distance < shortestDistance then
				closestPlayer = player
				shortestDistance = distance
			end
		end
	end
	return closestPlayer, shortestDistance
end

-- 공격 동작 수행
local function PerformAttack()
	if isAttacking then return end -- 이미 공격 중이면 무시
	if os.clock() - lastAttackTime < attackCooldown then return end -- 쿨다운 중이면 무시

	isAttacking = true
	lastAttackTime = os.clock() -- 현재 시간을 기록

	-- 공격애니메이션(크기 잠깐 키우기)
	local originalSize = enemy.Size
	enemy.Size = originalSize * 1.2 

	
	task.delay(attackTime, function()
		enemy.Size = originalSize -- 크기 복구
		isAttacking = false -- 공격 종료
	end)
end

-- 가장 가까운 플레이어를 향해 이동
local function moveTowardsClosestPlayer(deltaTime)
	if isAttacking then
		bodyVelocity.Velocity = Vector3.zero
		return
	end

	local targetPlayer, distance = GetClosestPlayer()
	if not targetPlayer then
		bodyVelocity.Velocity = Vector3.zero
		return
	end

	local playerPosition = targetPlayer.Character.HumanoidRootPart.Position
	local enemyPosition = enemy.Position

	if distance <= attackRange then
		PerformAttack()
	else
		enemy.CFrame = CFrame.new(enemyPosition, playerPosition)
		local direction = enemy.CFrame.LookVector
		bodyVelocity.Velocity = direction * speed
	end
end


local lastUpdate = 0
RunService.Stepped:Connect(function(deltaTime)
	lastUpdate += deltaTime
	if lastUpdate < 0.1 then return end -- 0.1초 간격으로 업데이트
	lastUpdate = 0

	moveTowardsClosestPlayer(deltaTime)
end)

 

테스트영상

로블록스 에디터 화면

기획과 같이 큐브를 배치하고 SpawnZone으로 이름을 바꿔주었다.

그리고 콜리전을 꺼서 충돌은 제거하고 시각적으로 확인하기 위해서 컬러는 레드로 바꿔주었다.

 

이제 저 SpawnZone의 범위안에서 적을 생성하는 로직을 작성하면 된다.

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local enemyPrefab = ReplicatedStorage:WaitForChild("Enemy")
local spawnInterval = 1
local spawnZones ={workspace.SpawnZoneU,workspace.SpawnZoneD,workspace.SpawnZoneL,workspace.SpawnZoneR}


local function spawnObject()
	local randomZone = spawnZones[math.random(1, #spawnZones)]
	local size = randomZone.Size;
	local position = randomZone.Position;
	
	local randomX = math.random(-size.X/2,size.X/2)
	local randomY = math.random(-size.Y/2, size.Y/2)
	local randomZ = math.random(-size.Z/2, size.Z/2)
	
	local spawnPosition = Vector3.new(position.X+randomX,position.Y+randomY,position.Z+randomZ)
	
	local newObj = enemyPrefab:Clone()
	newObj.Position = spawnPosition
	newObj.Parent = workspace
	print("Object spawned at: " .. tostring(randomZone.Name))
end

while true do
	spawnObject()
	print()
	wait(spawnInterval)
end

 

로블록스는 lua 언어를 사용하는데 lua를 써본적이 없어서 기본적인 언어의 구조와, 로블록스 내부함수들을 같이 이용하는 쪽으로 코드를 작성해보았다.(배열, 반복 사용 등..)

그리고 ReplicatedStorage에 넣은 객체들은 게임상에서는 등장하지 않고 유니티의 프리팹처럼 사용할 수 있는것 같다. 그래서 Prefab으로 사용해보았다.

 

결과

적생성 동작화면

 

생성은 일단 완료했고 다음은 간단한 적의 AI를 만들어야지

로블록스 스터디 목적으로 간단한 게임을 기획해봤다.

 

- 중앙에서 시작하고 적들이 사방에서 몰려온다.

- 플레이어는 적을 총으로 쏴서 파괴할 수 있고 파괴하면 점수를 얻는다.

- 일정시간 버티면 스테이지를 클리어한다.

- 클리어 후 점수를 이용해서 특수능력을 얻을 수 있다.

- 체력이 0이되면 사망한다.

 

이제 만들기 시작.

최근에 로블록스를 활용한 외주 작업을 진행할 가능성이 생겨서, 로블록스 관련 정보를 조금 조사해보았다.

그동안은 로블록스에 대해 별다른 관심이 없어서 “에디터가 있구나” 정도로만 알고 있었는데, 막상 살펴보니 거의 게임 엔진 수준의 강력한 에디터를 지원하고 있어 자유도가 굉장히 높다는 점이 인상적이었다.

그리고 그 말은 학습해야할 것들이 많다는 것을 의미한다.

따라서 로블록스 스튜디오 학습을 겸해 간단한 토이 프로젝트를 진행해보려고 한다. 앞으로 진행 과정과 배운 것들을 블로그에 기록할 예정인데, 이 카테고리를 통해 차근차근 정리해볼 생각이다.

부디 잘 마무리할 수 있길 바라며, 화이팅!

+ Recent posts