본문 바로가기
Develop Story/Game Designer

Lua - 노트패드 설정과 가위바위보 예제

by 늘상의 하루 2021. 1. 25.

몇년 전에 한번 루아를 공부한 적이 있지만 시간이 많이 흘러서 잊어버린것도 꽤 많았습니다. 배워두면 좋고 쓰는 회사도 많기 때문에 이번에 계기가 생겨서 주말간 루아를 다시 공부해 보았습니다.

 

제 경우에는 연산자부터 함수까지 차근차근 단계를 밟는 것 보다는 바로바로 예제를 따라 진행하면서 규칙과 기능을 익히는 것이 더 편하기 때문에 바로 인터넷을 뒤져 예제를 따라 만들고 이해했습니다.

 

제가 루아의 전문가가 아니기 때문에 구조적으로 루아가 어떤 점이 다른지는 말씀드릴 수 없지만

 

1. 굉장히 가벼운 언어.

2. 로직과 데이터의 분리로 수정된 내용을 빠르게 확인 가능.

3. 작성 구조가 단순하고 쉬움.

 

다른 분들께서 공통적으로 루아를 표현하는 말들이었습니다.

 

언제 한번 마음먹고 모드를 만들어보자 생각하고 있는 '프로젝트 좀보이드' 게임 또한 루아로 만들어졌기 때문에 알아두면 매우 유용한 언어가 될 것임은 분명했습니다.

 

아래의 내용대로 설명을 드리고자 합니다.

 

1. 노트패드 설정

3. 예제 1번 (가위바위보)

 

다음 장에서는 직업을 고르고 슬라임과 싸우는 간단한 '전투 시스템' 예제를 진행하고자 합니다.

 

준비물은 '루아 프로그램'과 가볍게 작성할 '노트패드'입니다. 아래의 링크에서 받으면 됩니다.

 

code.google.com/archive/p/luaforwindows/downloads

 

Google Code Archive - Long-term storage for Google Code Project Hosting.

 

code.google.com

notepad-plus.softonic.kr/

 

Notepad++

완전한 소스 코드 편집기와 메모장 대체

notepad-plus.softonic.kr

 

1. 노트패드 설정


작업하기 전에 앞서 노트패드에서 루아의 결과를 즉각 확인하고 보다 편하게 작성하기 위해 몇 가지 설정을 해 주려고 합니다.

 

'비주얼 스튜디오'에서는 코드를 작성할 때 입력한 철자와 연결되는 함수 리스트를 띄워주는 인텔리센스 기능이 있습니다. 전문적으로 프로그래밍을 하시는 분들에게는 불편할 수도 있지만 제게는 편하고 유용한 기능 중 하나입니다.

 

 

[언어 설정 - L - Lua]를 선택해 주시면 됩니다.

 

이렇게 선택하면 이후 자동완성 기능이 작동하여 루아 함수를 입력할 때 리스트를 출력하여 빠르게 입력 가능하게 만들어 주고 작성한 스크립트를 보기 좋게 컬러로 구분해 줍니다.

 

다음으로 환경 설정에 들어가서 자동 완성 - 함수 및 단어 완성을 체크해 주도록 합시다.

여기까지가 기본적인 작성 준비었고 노트패드로 결과를 바로 확인하기 하기 위해서는 다음 준비가 필요합니다.

 

 

NppExec, NppExport가 필요합니다.

[플러그인-플러그인 관리] 에서 찾아서 설치해 주면 됩니다.

 

설치가 끝난 다음 실행하는 방법으로는 [플러그인-NppExec-Execute...] 혹은 F6을 누르시면 됩니다.

 

 

그러면 이렇게 창 하나가 뜨는데 커맨드 안에 자신의 루아의 실행경로를 적고 뒤에 $(FULL_CURRENT_PATH) 를 작성해 주시면 됩니다. 임의의 이름으로 Save를 하면 목록에서 바꿔가면서 쉽게 실행이 가능합니다.

 

그 다음 작성된 코드를 실행 OK 버튼을 눌러주시면

 

 

하단 콘솔창이 출력되며 프로그램의 결과 화면을 바로 볼 수 있습니다.


가위바위보의 룰은 심플하면서 직관적입니다.

 

상대방이 무엇을 낼지 알 수 없다는 긴장감과 먹고 먹히는 구조관계는 게임에서 가장 근본적인 전투 시스템이라 생각하며 실제로 '대항해시대 시리즈'나 '마비노기'에서 사용하는 전투 시스템이기도 합니다.

 

아주 간단하게 텍스트로만 진행되는 게임을 만들기 때문에 그래픽은 따로 필요 없습니다.

장인정신을 가지신 분이라면 '아스키 아트' 방식으로 그래픽 리소스 없이 표현 가능하기도 합니다.

 

우선 텍스트파일을 하나 만들고 확장자를 .lua로 바꿔 줍시다.

 

그리고 파일을 우클릭하여 노트패드로 열면 준비는 끝.

 

구현해야 할 목록은 이렇습니다.

 

1. 게임을 몇 판 플레이 할 것인지 입력하는 기능.

2. 플레이어가 어떤 것을 낼 것인지 입력하는 기능.

3. 인공지능이 어떤 것을 낼 것인지 결정하는 기능.

4. 두 가지를 비교하고 누가 이겼는지 판단하는 기능.

5. 승리 횟수를 기억하고 게임이 끝났을 때 누가 이겼는지 판단하는 기능.

6. 그리고 더 할건지 그만할건지 결정하는 기능.

 

자신이 만든 루아 프로그램을 실행하는 방법은 간단합니다.

 

작성한 스크립트 파일을 더블 클릭하여 실행하면 끝!

 

바로 작성합시다.

 

 

2. 가위바위보 만들기


먼저 루아는 위에서 아래로 실행됩니다.

행을 넘어갈 때는 세미콜론을 사용할 필요가 없으며 주석은 [[ ]] 를 사용합니다.

그렇기 때문에 함수 혹은 메소드를 호출하기 위해서는 아래와 같은 구조가 필요합니다.

 

function StartGame()

    print("print 함수는 텍스트를 출력할 수 있습니다.")

end [[ {}를 사용하지 않기 때문에 end는 함수를 끝낼 때 사용합니다. ]]

StartGame() [[위에 함수가 정의되었기 때문에 호출이 가능합니다. ]]

 

F6을 눌러 실행하면 콘솔창에 결과값이 출력됩니다.

하지만 루아 프로그램 파일을 눌러 실행하면... 엥? 아무 반응도 뜨지 않습니다.

 

그 이유로는 루아 프로그램이 엄청난 속도로 print를 출력하고 종료하기 때문인데 이를 막기 위해서는 임시로 마지막 줄에 아래의 코드를 넣어 주시면 됩니다.

 

os.execute("pause")

 

이제 가장 먼저 게임을 몇 판 플레이할 것인지 입력하는 함수를 만들어 봅시다.

 

function SetRound()
	print("")
	print("라운드를 설정합니다. 숫자를 입력하세요.")
	round = io.read("*n")
    
	while (round % 2) ~= 1 do
		print("무승부가 나지 않는 번호를 입력하세요.")
		round = io.read("*n")
	end
    
	print("라운드가 설정되었습니다. ")
	print("")
end

SetRound()

os.execute("pause")

 

먼저 우리는 사용자가 무엇을 해야 하는지 알려줘야 합니다. 참고로 빈칸을 출력하는 print는 한칸 띄우기 위해서입니다.

 

io.read("")는 사용자가 입력한 키 값을 받을 수 있습니다. 여기서 괄호 안에 *n을 넣으면 숫자 입력만 받을 수 있습니다.

입력된 값을 round 변수에 넣어 주는 것으로 값을 저장합니다.

 

하지만 여기서 라운드가 2, 4, 6 등의 짝수로 설정되었을 때 게임은 승패를 가리지 않고 무승부로 끝날 수가 있습니다. 

while ~ do 는 조건이 참일때 루프를 돌리는 함수입니다.

 

이걸 사용해서 게임이 무승부로 끝나지 않도록 짝수를 받을 수 없게 만들어 줍니다.

%값을 나눈 나머지를 반환합니다. ~= 값이 같지 않을때 참이 됩니다.

 

round가 5일때 나누기 2를 하면 1이 반환됩니다. 값이 같기 때문에 거짓이 되고 while은 실행되지 않습니다.

round가 4일때 나누기 2를 하면 0이 반환됩니다. 값이 같지 않기 때문에 참이 되고 while 루프가 실행됩니다.

 

루프가 실행되면 무승부가 나지 않도록 번호를 입력하라는 멘트를 출력하고 다시 round에 값을 입력할 수 있도록 해 줍니다.

 

이제 실행해 보고 잘 작동하면 본격적으로 가위바위보를 진행해 봅시다.

 

function StartGame()

	local PlayerScore = 0
	local AIScore= 0
    
    	local PlayerDo = 0
    	local AIDO = 0
    
	while PlayerScore <=(round /2) and AIScore <=(round /2) do
    
		print("주먹 = 1, 가위 = 2, 보자기 =3, 잘 이겨보세용")
		PlayerDo = io.read("*n")
        
		math.randomseed(os.time())        
		AIDO = math.floor(math.random(1,3))
        
		if PlayerDo > 3 or PlayerDo < 1 then
			print("가위바위보 중 하나를 선택하세요.")
		elseif PlayerDo == AIDO then
			print ("무승부~")
            
		elseif PlayerDo == 1 and AIDO == 2 then
			print ("주먹 vs 가위")
			print ("플레이어 승리")
			PlayerScore = PlayerScore +1
		elseif PlayerDo == 1 and AIDO == 3 then
			print ("주먹 vs 보자기")
			print ("컴퓨터 승리")
			AIScore = AIScore +1
            
		elseif PlayerDo == 2 and AIDO == 1 then
			print ("가위 vs 주먹")
			print ("컴퓨터 승리")
			AIScore = AIScore +1
		elseif PlayerDo == 2 and AIDO == 3 then
			print ("가위 vs 보자기")
			print ("플레이어 승리")
			PlayerScore = PlayerScore +1
            
		elseif PlayerDo == 3 and AIDO == 1 then
			print ("보자기 vs 주먹")
			print ("플레이어 승리")
			PlayerScore = PlayerScore +1	
		elseif PlayerDo == 3 and AIDO == 2 then
			print ("보자기 vs 가위")
			print ("컴퓨터 승리")
			AIScore = AIScore +1		
		end
        
		print("플레이어 :"..PlayerScore.." / 컴퓨터 :"..AIScore.."")
	end
    
	if PlayerScore > AIScore then
		print("플레이어가 이겼다. ")
	elseif AIScore > PlayerScore then
		print("컴퓨터가 이겼다.")
	end		
    
end

 

StartGame()이라는 새로운 함수를 만들어 줍시다.

여기서 몇점을 따냈는지 저장할 두 변수가 필요합니다.

 

local을 통해 지역변수로 만들어 주면 StartGame 함수 안에서만 사용할 수 있게 됩니다.

local을 붙이지 않으면 전역변수로 자동 설정되며 아무때나 가져다 쓸 수 있습니다.

 

while을 통해 가위바위보 중 어떤 것을 낼지 결정하고, AI가 셋 중에 어떤 것을 낼지 랜덤하게 뽑을 계획입니다.

그리고 라운드를 반으로 나눈 값보다 플레이어의 점수가 더 크거나 AI 점수가 더 크면 while은 종료됩니다.

 

플레이어의 입력값은 io.read를 통해 받고 AI의 입력값은 math.random()을 사용하겠습니다. 설정값 안에서 난수를 만드는 함수입니다. 랜덤 앞줄에는 항상 시드를 초기화 해 주는 math.randomseed(os.time()) 을 사용합니다.

-시드를 초기화하지 않으면 랜덤표가 변하지 않고 같은 값을 출력하게 됩니다.-

 

랜덤 함수를 그대로 사용하면 소수점 난수까지 출력하기 때문에 결과값이 변하지 않는 것처럼 보이는 현상이 발생합니다. 그래서 math.floor를 사용해서 소수를 버리고 정수만 출력하게 만듭니다. 

 

다음으로는 노가다에 가까운 if 활용입니다.

플레이어의 값과 AI의 값을 비교해서 결과값을 출력하는 모든 경우의 수를 반복...합니다.

모든 판정이 끝나면 플레이어의 점수와 AI의 점수를 보여줍니다.

 

그리고 while문이 종료될 때 까지 점수가 변동되면 이제 누가 이겼는지 판정을 해 줍니다.

이제 게임이 끝났습니다.

 

function FinishGame()

	print("계속하실? (그만하고 싶으면 10을 누르세요.)")
	StopNum = io.read("*n")
    
	if StopNum == 10 then
		Gamestop = 1
	end
end

print("가위 바위 보")

Gamestop = 0


while Gamestop do

	SetRound()
	StartGame()
	FinishGame()
	
	if Gamestop == 1 then
		break
	end
end

 

게임이 끝났을 때는 곧 StartGame 함수가 종료됨을 말합니다.

그 다음으로 출력될 FinishGame 함수를 만들고 게임을 더 플레이할건지 그만 플레이할건지 판단해 줍시다.

 

여기서는 10을 입력하면 게임을 그만하도록 했습니다. 10을 누르면 Gamestop 변수에 1값이 입력되고 아래 while 문에서 break를 사용해 프로그램을 종료합니다.

 

function 함수 안에 있는 내용은 호출되지 않으면 작동하지 않습니다. lua는 위에서 아래로 프로그램을 시작함과 동시에 순차적으로 실행되며 함수를 제외한 코드가 모두 실행되면 프로그램을 종료합니다.

 

때문에 아래 while 문은 실질적으로 게임을 구동하는 함수입니다. 유니티 C#에서 Update와 같은 역할을 합니다.

lua에서는 while문 안에 들어간 변수가 참일 경우 무한 반복합니다. 그리고 조건문 비교가 없으면 항상 참으로 출력합니다.

 

이 안에서 SetRound, StartGame, FinishGame을 순차적으로 반복 실행할 수 있도록 호출해 줍시다. 그리고 FinishGame이 끝났을 때 게임을 계속 진행할 것인지 아닌지를 판단하는 조건문을 넣고 break를 사용해 while을 빠져나가는 것으로 게임을 종료합니다.

 

다음장에서는 가위바위보를 응용한 간단한 전투 시스템을 구현해 보겠습니다.

 

RSP_Study01.lua
0.00MB