2019년 6월 29일 토요일

GMS2 ZUI making Sprite Button like shop in Android, ZUI에 Sprite 버튼 추가해서 상점 비슷하게 만들기


앞에서 ZUI를 이용하여 Android 기본 사용을 위한 패치를 해봤습니다.

https://swlock.blogspot.com/2019/06/gms2-zui-in-android-zui.html

이번에는 간단하게 상점을 구현하기위한 버튼을 만들것입니다. 대단한것은 아니고, Sprite 버튼이 여러개 있으면 상점처럼 사용 할 수 있을것 같아서 구현 하였습니다.

objUIButton 생성하는곳에서 caption에 특수 문자인 \x01을 넣어주면 이미지가 있다는것을 알리게되고,  caption_ext 에는 SPR은 sprite를 의미하고, 두번째 인자는 어떤 sprite인지, 마지막으로 image index 숫자가 됩니다.
 with (zui_create(12, 38, objUIButton)) {
  zui_set_anchor(0, 0);
  zui_set_size(120, 32);
  caption = "1/10 \x01";
  caption_ext = "SPR,sprConti,0|SPR,sprThree,0"
  callback = test_callback_button;
 }

 with (zui_create(12, 38+32, objUIButton)) {
  zui_set_anchor(0, 0);
  zui_set_size(120, 32);
  caption = "1/10 \x01";
  caption_ext = "SPR,sprThree,0"
  callback = test_callback_button;
 }

objUIButton의 Create 이벤트에 아래 내용을 추가합니다.
caption = ""
caption_ext = 0

objUIButton의 Draw 이벤트에도 아래 내용을 추가합니다.  caption_ext에 값이 있으면 caption을 파싱해서\x01 부분을 찾아서 그림으로 대체합니다.
if( caption_ext==0 )
 draw_text(__width * 0.5, __height * 0.5, string_hash_to_newline(caption));
else{
 ui_draw_text_and_sprite(__width * 0.5, __height * 0.5,caption,caption_ext,1,1,1)
}

ui_draw_text_and_sprite 이것은 스크립트 입니다.
///@desc 텍스트와 스프라이트를 그림
///@args x x위치
///@args y y위치
///@args __str__ 출력할문자열
///@args caption_ext
///@args alpha 투명도
///@args x_scale 가로배율
///@args y_scale 세로배율



//text 그릴 x,y위치
var X = argument[0];
var Y = argument[1];
var startx=X;
var starty=Y;
//문자열
var STR = argument[2];
var EXT = argument[3];
var ALPHA = argument[4];

//말풍선의 배율
var XS = argument[5];
var YS = argument[6];

//줄마다의 공백픽셀
var line_empty = 8;
var theight = string_height(" ");
var lheight = string_height(" ");
var twidth = string_width(" ");
var len = string_byte_length(STR);
var extdata = string_split_2(EXT,"|",",")
var extindex = 0

var maxstartx = 0, maxstarty = 0;
//좌표 먼저 계산
startx=0;
starty=0;
for( var i = 1 ; i <= len ; i++ ){
 var s_char = string_char_at( STR , i );
 if(s_char=="\n"){
  starty = starty+lheight;
  lheight = string_height(" ");
  if( maxstartx < startx ) maxstartx = startx
  startx = 0;
  continue;
 }else if(s_char=="\x01"){
  if(extdata[extindex]=="SPR"){
   extindex = extindex+1;
   var spr = asset_get_index(extdata[extindex]);
   extindex = extindex+1;
   var frn = real( extdata[extindex] );
   extindex = extindex+1;
   if ( sprite_exists( spr ) )
   {
    twidth = sprite_get_width( spr ) * XS;
    theight = sprite_get_height( spr ) * YS;
    //if( lheight < theight){
    // lheight = theight;
    //}
    startx = startx + twidth;
    if( maxstartx < startx ) maxstartx = startx
   }
  }
  continue;
 }
 twidth = string_width(s_char) * XS;
 theight = string_height(s_char) * YS;
 if( lheight < theight){
  lheight = theight;
 }
 startx = startx + twidth;
 if( maxstartx < startx ) maxstartx = startx
}
maxstarty = starty + lheight


// DRAW

draw_set_halign(fa_left);
draw_set_valign(fa_top);
extindex = 0

X=X-(maxstartx)/2;
Y=Y-(maxstarty)/2;

startx=X;
starty=Y;
lheight = string_height(" ");
for( var i = 1 ; i <= len ; i++ ){
 var s_char = string_char_at( STR , i );
 if(s_char=="\n"){
  starty = starty+lheight;
  lheight = string_height(" ");
  startx = X;
  continue;
 }else if(s_char=="\x01"){
  if(extdata[extindex]=="SPR"){
   extindex = extindex+1;
   var spr = asset_get_index(extdata[extindex]);
   extindex = extindex+1;
   var frn = real( extdata[extindex] );
   extindex = extindex+1;
   if ( sprite_exists( spr ) )
   {
    twidth = sprite_get_width( spr ) * XS;
    theight = sprite_get_height( spr ) * YS;
    //if( lheight < theight){
    // lheight = theight;
    //}
    //스프라이트 그리기
    draw_sprite_ext( spr , frn , startx , starty , XS , YS , 0 , c_white , ALPHA); 
    startx = startx + twidth;
   }
  }
  continue;
 }

 twidth = string_width(s_char) * XS;
 theight = string_height(s_char) * YS;
 if( lheight < theight){
  lheight = theight;
 }

 /* 문자 그리기 */
 draw_text_transformed( startx , starty , s_char , XS , YS, 0);
 startx = startx + twidth;
}

그리고 아래는 해당 스크립트에서 문자열을 분리하기 위한 string_split, string_split_2 가 있습니다.
string_split_2
입력 : "SPR,sprConti,0|SPR,sprThree,0" , "|", ","
출력 : 
result[0]="SPR"
result[1]="sprConti"
result[2]="0"
result[3]="SPR"
result[4]="sprThree"
result[5]="0"
///@desc string_split_2(string,seperator1,seperator2)
///@args string
///@args seperator1
///@args seperator2
var str = argument0 
var seperator1 = argument1
var seperator2 = argument2
var sep1 = string_split(str,seperator1)
var sep2;
var ret=array_create(0);
var size = array_length_1d(sep1);

for(var i = 0 ; i < size ; i++ ){
 sep2 = string_split(sep1[i],seperator2)
 array_copy(ret,array_length_1d(ret),sep2,0,array_length_1d(sep2))
}

return ret;

string_split
입력 : "abc:def:ghijk",":" 입력시 
출력 : 
result[0]="abc"
result[1]="def"
result[2]="ghijk" 
///@desc string_split(string,seperator)
///@args string
///@args seperator

var count = 0;
var result;

result[0] = argument0;

while (true) {
 var position = string_pos(argument1, result[count]);
 
 if (position <= 0)
  break;
 
 result[count + 1] = string_copy(result[count], position + 1, string_length(result[count]) - position);
 result[count] = string_copy(result[count], 1, position - 1);
 
 count++;
}

return result;


굉장히 복잡하긴 하지만 먼저 line수와 글자를 계산해서 중심점을 찾아내게 됩니다. 그리고 실제 text 그릴때 중심점을 기준으로 text를 draw하게 됩니다. 여기서 주의할점은 image의 위치의 상대 주소는 left top 기준으로 하여야하며 이미지 가로는 고려하여 중심점을 잡지만, 이미지가 아무리 크더라도 세로는 중점을 계산하지 않았습니다. 이 부분은 몇가지 예제를 살펴보면 쉽게 이해가 될것 같습니다.
코드는 위 내용이 전부입니다.

위 예제에서 아래와같\x01이 하나 임에도 대응되는 SPR데이터를 2개 넣어둔것은 잉여 데이터가 있더라도 오류가 발생하지 않음을 보여준 예제 입니다.
  caption = "1/10 \x01";
  caption_ext = "SPR,sprConti,0|SPR,sprThree,0"

16*16 이미지를 빨강색, 파란색 사각형으로 구현한 실행화면은 아래와 같습니다.

빨강색 사각형을 32*32로 표기하면 다음과 같이 됩니다.세로는 중점이 안맞는 현상이 나타납니다. 이것은 큰 그림에 많은 설명을 붙여서 기록하는 방식을 사용하기 위한 의도된 동작입니다. 윈도우가 벗어나는것처럼 표시된것은 버튼 생성시 윈도우 크기를 좀 더 키우면 됩니다.


지금까지 작업한 소스 입니다.
https://drive.google.com/open?id=1lCBh0uOy2iZ_YwwTWieOA7E20gKoBs-w


댓글 없음:

댓글 쓰기