본문 바로가기

프로그래밍/마인크래프트 - CommandHellper 플러그인

마인크래프트 CommandHelper 커헬 강좌 5강 - 반복문 , 월드에디터 만들기



안녕하세요 벌써 5강이네요


오늘은 반복문을 설명하면서 간단하게 WorldEdit ( 월드에디터 ) 에 있는 //set 기능을 만들어보도록 하겠습니다


우선 for문을 간단하게 설명드리자면 자신이 원하는만큼 코드를 반복시킬수 있습니다



기본적인 형태는


for(초기화, 조건, 업데이트) {

실행내용

}


입니다

초기화,조건 업데이트가 뭐냐고요?

우선 초기화라는게 뭐냐면 변수를 만드는겁니다


@i = 0;


이런식으로 변수를 선언하는게 초기화입니다

조건은 저번에 if문에서도 본것처럼


if(@i > 10)


이런식으로 조건을 넣을수 있습니다

@i가 10보다 클때 실행되는거죠


마지막으로 업데이트는 @i += 1 이런식으로 변수를 바꿔주는겁니다

한번 명령어로 만들어서 테스트해보죠


*:/test = >>>

for(@i = 0, @i < 10, @i+=1) {

msg(@i)

}

<<<


@i라는 변수를 만들고 @i가 10보다 작은지 체크합니다.

10보다 작을경우 코드를 실행하고 @i에 1을 더합니다

그리고 조건이 만족하지 않을때까지 반복합니다


한번 직접 출력해볼까요?




0부터 9까지 반복하면서 @i를 계속해서 출력해줬습니다.

그리고 10을 넘어가는순간 조건을 만족하지 못해서 for문이 중지됐죠


그리고 for문에서 중간에 탈출하는방법도 있습니다

바로 중간에 break()를 넣어주면 되는겁니다.


*:/test = >>>

for(@i = 0, @i < 10, @i++) {

if(@i == 6) {

break();

}

msg(@i)

}

<<<

@i가 6일때 break()가 실행되도록 해봅시다




@i가 6이되는순간 for문이 중지된걸 볼수있습니다


그렇다면 for문은 중지시키고싶지는 않은데 아래 코드들을 실행하기 싫다면 어떻게해야될까요

continue(); 를 사용하면됩니다

컨티뉴는 바로 실행중인 코드를 끝내고 바로 업데이트단계로 스킵합니다.

직접 코드를 짜서 보여드리겠습니다


*:/test = >>>

for(@i = 0, @i < 10, @i++) {

if(@i % 2 == 0) {

continue();

}

msg(@i)

}

<<<

%는 나머지를 구하는 연산자입니다
5%2를 할경우 5에서 2를 나누고 1이 남으니 1이됩니다.

@i가 짝수일경우 무조건 2로 나눴을때 0이 남게되니
@i % 2가 0일때 컨티뉴를 해줘서 짝수는 모두 스킵해보겠습니다


짝수는 모두 스킵되고 홀수만 출력된걸 볼수 있습니다

일단 for문에 대해 배워봤으니 그림으로 정리해봅시다
for문의 실행단계를 그림으로 표현해보면 이렇게됩니다



조건이 맞지 않거나 break가 올때까지 계속해서 반복하는걸 볼수 있습니다


그리고 다른 반복문으로 while문이 있습니다


while은 if문을 반복한다고 생각하시면 편합니다

for은 반복시킬때 많이쓰지만 while은 좀더 조건적인부분에서 쓰입니다.


while(조건) {

실행내용

}


이렇게 쓰이고 조건이 만족하지 않을때까지 반복합니다

정말 간단하죠? 이게 다입니다.


do while이란것도 있는데 이건 실행내용을 한번 실행한다음 원래 while로 돌아옵니다


그림으로 설명하면 이렇습니다





그럼 이걸 이용해서 월드에디터의 //set 기능을 만들어볼수도 있습니다

블럭의 좌표 0~100까지 반복하면서 블럭타입을 바꿔주는겁니다



우선 좌표를 설정해주기 위해서 main.ms에 EventAPI를 추가해줍시다



bind(player_interact, null, null, @event,

if(pinfo( player() , 6) == '271:0') {

if(@event[action] == 'left_click_block') {

store_value(player() . 'set1', @event[location])

msg('1번 좌표설정')

cancel()

}

if(@event[action] == 'right_click_block') {

store_value(player() . 'set2', @event[location])

msg('2번 좌표설정')

cancel()

}

}

)




새로 보이는 함수가 나와버렸네요
우선 손에 든 아이템인지 무엇인지 체크해야되기때문에
pinfo( player() , 6) 
를 넣었습니다

pinfo( 플레이어명, 매개변수) 이 함수는 해당플레이어의 정보를 얻어올수 있습니다
매개변수는 1~20의 숫자를 넣을수있고
넣은 숫자에 따라 받아올수 있는 정보가 다른데 6번을 넣을경우 플레이어가 들고있는 아이템코드를 가져옵니다


271번인 나무도끼를 들고있을경우 실행되며
저번에도 말씀드렸듯이 EventAPI에는 @event로 이벤트 데이터들을 받아올수 있습니다

player_interact는 플레이어가 클릭을 했을경우에 실행되는 이벤트입니다
그중 @event[action]는 어떤 방법으로 클릭했는지 알려줍니다

left_click_block - 블럭에 좌클릭
right_click_block - 블럭에 우클릭
left_click_air - 허공에 좌클릭
right_click_air - 허공에 우클릭

그리고 @event[location] 는 클릭한 블럭의 좌표를 알려줍니다

고로 블럭에 좌클릭했을때 '플레이어이름.set1' 이라는 변수에 블럭좌표를 저장해주고
우클릭했을때 '플레이어이름.set2' 이라는 변수에 블럭좌표를 저장해줍니다.
그리고 cancel()로 이벤트를 취소해줘서 행동이 실행되는걸 막아줍니다.

이제 이걸 아까 배운 for문으로 블럭을 바꿔주기만 하면 됩니다

블럭으로 바꿔주는 명령어를 짜봅시다

*:/set $code = >>>
@loc1 = get_value(player() . 'set1')
@loc2 = get_value(player() . 'set2')
if(!(@loc1 == null || @loc2 == null)) {
}
<<<

우선 명령어를 만들고 $code변수를 입력받습니다. 그리고set1과 set2좌표를 가져와줍시다.

그다음 그게 비어있는값인지 아닌지 체크해봅니다

근데 if문에 || 라는 못보던게 보이죠?

이김에 잠시 논리연산자를 설명해드리겠습니다

if문은 항상 조건이 참일때만 실행이되는데


A && B 를 할경우 A와 B가 모두 참일경우에 참이됩니다  ( AND )

' A 그리고 B ' 라고 보시면 됩니다


A || B 는 둘중 하나만 참이여도 참이됩니다  ( OR )

이건' A 또는 B'로 보면 됩니다


!A 는 A가 참일경우 거짓이되고 거짓일경우 참이됩니다. 거꾸로 바꿔주는거죠 ( NOT )

A를 부정할경우 그 반대가되기때문에 NOT입니다

쉽게말하면   '난 A다.'    ->    난 'A가 아니다.'    이게 되는거죠.


참 거짓 하니까 어려워보일수도 있겠지만 간단하게 설명하면 이런겁니다



if(A && B)를 할경우 A와 B의 조건이 둘다 만족되야 실행되고

if(A || B)는 둘중 하나마 만족되도 실행됩니다

if(!A)는 A가 만족할경우 실행되지 않고 만족하지 않을경우 실행됩니다


if(!(@loc1 == null || @loc2 == null)) { 는 둘다 비어있는값이 아닐때만 실행됩니다

||를 사용해서 둘중 하나라도 널값이 들어있으면 참이되버리고 그것을 !로 부정해줍니다.

그래서 둘중 하나라도 널값이 들어있으면 실행이 안됩니다


이제 여기에 for문으로 블럭을 채워봅시다


*:/set $code = >>>

@loc1 = get_value(player() . 'set1')

@loc2 = get_value(player() . 'set2')

if(!(@loc1 == null || @loc2 == null)) {

@tmp = 0;

if(@loc2[x] < @loc1[x]) {

@tmp = @loc1[x]

@loc1[x] = @loc2[x]

@loc2[x] = @tmp

}

if(@loc2[y] < @loc1[y]) {

@tmp = @loc1[y]

@loc1[y] = @loc2[y]

@loc2[y] = @tmp

}

if(@loc2[z] < @loc1[z]) {

@tmp = @loc1[z]

@loc1[z] = @loc2[z]

@loc2[z] = @tmp

}

for(@i = @loc1[x], @i <= @loc2[x], @i++) {

for(@j = @loc1[y], @j <= @loc2[y], @j++) {

for(@u = @loc1[z], @u <= @loc2[z], @u++) {

@loc = array(0:@i,1:@j,2:@u,3:@loc1[world],world:@loc1[world],x:@i,y:@j,z:@u)

set_block_at(@loc, $code)

}

}

}

}

<<<



코드가 너무 길어져버렸네요 


우선 for문에서 좌표값이 작은것부터 큰것으로 진행하게 만들기 위해서

@loc1이 @loc2보다 클경우 두 값을 바꿔줘서

무조건 @loc1이 작은값이 되도록 만들어줬습니다


근데 왜 @tmp를 넣어서 바꿔주었냐?


왜냐하면

@loc1 = @loc2

@loc2 = @loc1

이런식으로 바꿔줄경우에는 @loc2에 @loc1을 넣을때 @loc1은 이미 @loc2의 값이 들어있기때문에 바뀌지 않게됩니다.

그래서 @tmp에 임시로 값을 저장해놓고 옮겨주는겁니다.


그렇게 x, y ,z값을 모두 @loc1이 작게 만들어준후

for문으로 들어갑니다

for문은 저렇게 한번에 여러개를 중첩시켜서 사용할수도 있습니다

반복문을 반복하는거죠

for문을 for문으로 여러번 실행시켜서 x,y,z를 모두 한번씩 돌수있게됩니다


set_block_at(@loc, $code)


이 함수는 좌표와 블럭코드를 넘겨주면 그 좌표에 해당 블럭을 설치해주는 함수입니다.


한번 잘 작동되는지 볼까요?



나무도끼를 들고 좌클릭으로 1번좌표를 설정해주고



우클릭으로 2번좌표를 설정해줍니다



그리고 '/set 아이템코드'를 치면..?




짠 아이템코드 1번인 돌이 생성되었습니다.


오늘은 반복문을 배우고 월드에디터의 //set 기능을 만들어보았습니다


모르는점 있으면 댓글로 질문해주세요

그리고 혹시 만들고싶은 기능이 있다면 강좌로 올려드리겠습니다