본문 바로가기
GameMaker강좌[GMS2]/네트워크강좌

[게임메이커 강좌-네트워킹][GMS2] 채팅 프로그램 만들기-1-채팅 기본 구성

by 타락카얀 2024. 12. 21.
728x90

 

 

GAME MAKER 강좌

 

KAYAN

 

 

 

 

 

 

◈ 채팅 프로그램 만들기

 

이번 강좌에서는 간단하게 채팅을 만들어 봅시다.

 

(▲ 채팅 프로그램)

 

먼저 메인 화면부터 구성합니다.

 

(▲ 단순한 메인 화면)

 

룸은 메인화면, 채팅룸 2가지 준비합니다.

화면 크기는 800x600 크기로 구성합니다.

 

(▲ 채팅 룸)

 

그리고 채팅글에 사용할 한글 폰트가 필요합니다.

한글 폰트 하나를 추가합니다.

강좌에서는 폰트명을 font0 으로 설정할 거에요.

 

(▲ 한글 폰트)

 

※ [참고] 한글 폰트 설정 https://kayanworld.tistory.com/194

 

 

오브젝트를 하나 만들고, [Game Start 이벤트]에 게임 시작시 필요한 변수를 만들어 줍니다.

 

(▲ 게임 시작 오브젝트)

 


obj_open 오브젝트 - Game Start 이벤트
      
      
global.chat_list = ds_list_create( ); //채팅 목록
 
global.local_server_IP = "127.0.0.1"; //서버의 로컬 IP
 
global.connect_IP = "127.0.0.1"; //서버 IP( 클라이언트에서 서버 접속시 필요한 IP )
 
global.select_server = 0; //1:서버 0:클라이언트

 

이 오브젝트는 맨 처음 실행되어야 하므로 메인화면에 배치하도록 합니다.

 

메인화면의 버튼은 간단하게 이름 입력, 서버 만들기, 클라이언트, 3종류로 준비하겠습니다.

 

(▲ 메인 화면)

 

서버와 클라이언트는 따로 작동해야 하기 때문에 버튼 역시 구분해야 합니다.

먼저 이름 입력을 해봅시다.

오브젝트를 만들고, 버튼 이미지를 지정합니다.

 

(▲ 이름 입력 오브젝트)

 

[Create 이벤트]에 이름을 미리 입력하도록 설정합니다.


obj_input_name 오브젝트 - Create 이벤트
 
 
randomize( );
global.playername = choose( "팀", "알렉스", "존", "스티븐", "찰리", "레온" )+string( irandom( 1000 ));
 
global.message_dialog = 0;
message_str = -1;

 

이름은 메시지 팝업창으로 입력하기 때문에 필요한 변수를 추가합니다.

변수는 입력창을 1번만 띄우기 위함과, 입력창의 값을 받아오기 위한 변수 2가지 입니다.

 

[Draw 이벤트]에서 이름을 표시하도록 합니다.


obj_input_name 오브젝트 - Draw 이벤트
 
 
draw_set_font( font0 );
draw_set_halign( fa_center );
draw_set_valign( fa_middle );
 
draw_self( );
 
var c, t;
c = c_white; draw_rectangle_color( -1, y-48-16, room_width+1, y-48+16, c, c, c, c, 0 );
c = c_black; draw_text_color( x, y-48, "채팅에 사용할 이름을 입력하세요", c, c, c, c, 1 );
 
c = c_black; draw_text_color( x, y, global.playername, c, c, c, c, 1 )

 

이제 버튼을 마우스 왼쪽 버튼을 눌렀다 떼었을 때, 팝업창을 띄우도록 합니다.


obj_input_name 오브젝트 - Mouse Left Realesed 이벤트


if ( global.message_dialog == 0 ){
message_str = get_string_async( "당신의 이름은 무엇인가요?", global.playername );
global.message_dialog = 1;
}

 

그리고 [비동기 Dialog 이벤트]를 추가하고, 아래와 같이 팝업창의 값을 받아오도록 합니다.


obj_input_name 오브젝트 - Async Dialog 이벤트
 
 
var i_d;
 
i_d = ds_map_find_value( async_load, "id" );
if i_d == message_str{
if ds_map_find_value( async_load, "status" ){
if !( ds_map_find_value( async_load, "result" ) = "" ){
//------------- 처리 내용 -------------
global.playername = ds_map_find_value( async_load, "result" );
global.playername = string_copy( global.playername, 1, 10 );
//------------- 처리 내용 -------------
}
}
global.message_dialog = 0;
}

 

여기까지 작동 되는지 테스트 해봅시다.

 

 

다음은 서버와 클라이언트를 만들 수 있는 이벤트를 만들어야겠죠.

대충 계획은 이렇습니다.

서버 버튼을 누르면, 다음 채팅 룸으로 이동 시키고, 서버를 활성화할 겁니다.

서버는 프로그램을 실행하는 장치가 됩니다.

클라이언트는 서버로 접속하는 입장이라 서버 IP, 포트(Port)를 제공하는 것이 필수가 됩니다.

클라이언트는 로컬로 접속하는 형태(테스트 할 경우)라도, 서버가 먼저 만들어져야 합니다.

그래서 포트는 미리 설정할 수 있지만, 서버 IP는 고정 IP가 아닌 경우, 따로 지정해야 합니다.

 

먼저 오브젝트을 만들고, 서버로 이동할 버튼을 만듭니다.

 

(▲ 서버 메뉴 버튼)

 

마우스 왼쪽 버튼을 눌렀다 떼었을 때 다음 룸(채팅룸)으로 이동합니다.


obj_menu_server 오브젝트 - Mouse Left Realesed 이벤트★
      
      
      if ( global.message_dialog == 0 ){
      global.select_server = 1;
      room_goto_next( );
      }

 

다음은 클라이언트 입니다.

이름 입력창처럼 서버 IP를 입력하도록 설계할 것입니다.

 

(▲ 클라이언트 버튼)

 

오브젝트를 만들고, [Create 이벤트]에 필요한 변수를 추가합니다.


obj_menu_client 오브젝트 - Create 이벤트
      
      
message_str = -1;

 

마우스 왼쪽 버튼을 눌렀다 떼었을 때 입력창을 활성화 합니다.


obj_menu_client 오브젝트 - Mouse Left Realesed 이벤트
 
 
if ( global.message_dialog == 0 ){
message_str = get_string_async( "접속할 서버 IP를 입력하세요.", global.connect_IP );
global.message_dialog = 1; }

 

그리고 [비동기 Dialog 이벤트]를 추가하고, 아래와 같이 팝업창의 값을 받아오도록 합니다.


obj_menu_client 오브젝트 - Async Dialog 이벤트

 

var _id;
_id = ds_map_find_value( async_load, "id" );
if _id == message_str{
if ds_map_find_value( async_load, "status" ){ //메시지창의 [확인]을 누르면 true
if !( ds_map_find_value( async_load, "result" ) = "" ){
//------------- 처리 내용 -------------
global.connect_IP = ds_map_find_value( async_load, "result" );
 
//값이 올바른지 조건문을 추가해 체크함
if !( string_count( ".", global.connect_IP ) == 3 ) || !( string_letters( global.connect_IP ) == "" )
     || ( string_length( string_digits( global.connect_IP ) )<4 ){
global.connect_IP = "127.0.0.1";
show_message_async( "올바른 IP 주소를 입력하세요." );
}
//값이 원하는 형태면 다음 룸으로 이동함
else{
global.select_server = 0;
room_goto_next( );
}
//------------- 처리 내용 -------------
}
}
global.message_dialog = 0;
}

 

올바른 값을 받아오면, 채팅룸으로 이동하도록 합니다.

버튼이 완성되었으면 메인화면 룸에 각각 배치합니다.

 

채팅룸은 일단 배경을 대충 만들어 줍니다.

강좌에서는 단순하게 틀을 이미지로 만들어 배경으로 배치했습니다.

(▲ 채팅 배경)

 

(▲ 채팅룸)

 

잘 작동하는지 테스트해봅시다.

 

 

 

 

 

◈ 채팅구성

 

오브젝트를 만들고, [Create 이벤트]에 채팅에 필요한 구성을 설정합니다.

 

(▲ 채팅 표시 오브젝트)

 

채팅글은 관리가 편한 리스트 데이터 구조체를 사용해 글들을 순차적으로 저장할 것입니다.


obj_chat 오브젝트 - Create 이벤트
 
 
keyboard_string = "";

 

키보드 값을 바로 받아올 것이라 keyboard_string 값을 비웁다.

데이터 구조체는 필요 없을 때는 파기하는 것이 좋기 때문에 [Game End 이벤트]를 추가하고,

게임이 종료 되었을 때, 리스트 데이터 구조체를 파기하여 메모리에서 제거하도록 합니다.


obj_chat 오브젝트 - Game End 이벤트
 
 
ds_list_destroy( global.chat_list );

 

채팅글은 아래에서 위로 올라가도록 표시할 거에요.

먼저 문자열을 처리할 아래 스크립트가 필요합니다.


스크립트


//문자열을 지정한 너비로 자동 개행처리함( 채팅글 표시 ).
function get_string_limit( str, width ) {
///get_string_limit( str, width )
///@param string
///@param width
var n, i, _return, t;
 
 _return = "";
n = string_length( str );
for( i = 1; i< = n; i+ = 1; ){
t = string_char_at( str, i );
if string_width( _return+t )<width{ _return+ = t; }
else{ _return+ = "\n"+t; }
}
 
return _return;
}
 
 
//문자열 끝을 기준으로 지정한 너비 만큼 잘라줌( 입력창 ).
function get_string_tail( str, width ) {
///get_string_tail( str, width )
///@param string
///@param width
var n, i, _return, t, tt, count;
 
_return = "";
if string_width( str )<width{ _return = str; }
else{
tt = "";
count = 0;
n = string_length( str );
for( i = n; i> = 1; i- = 1; ){
t = string_char_at( str, i );
if string_width( tt+t )<width{ tt+ = t; count+ = 1; }else{ break; }
}

if count>0{ _return = string_copy( str, n-count+1, count ); }
}
 
return _return;
}

 

이제 [Draw 이벤트]를 추가하고, 채팅글을 표시하도록 합니다.

 

(▲ 채팅글-아래에서 위로)

 

글은 아래에서 위로 표시할 것이므로 좌표 시작을 채팅창 끝부터 설정합니다.


obj_chat 오브젝트 - Draw 이벤트
 
 
draw_set_font( font0 );
draw_set_halign( fa_left );
draw_set_valign( fa_top );
 
// == == == == == == == == == 채팅 시작
//채팅창
var sz = ds_list_size( global.chat_list );
var line_max, width, th, h, i, t;
var _x, _y, c;
 
_x = 80;
_y = 520;
line_max = 25;
width = 480;
 
h = string_height( "A" );
draw_set_halign( fa_left ); draw_set_valign( fa_bottom );
i = sz;
repeat( min( sz, line_max ) ){
i- = 1;
 
t = get_string_limit( global.chat_list[| i], 480 );
 
th = max( h, string_height( t ) );
 
draw_set_alpha( 0.1 );
c = c_green; draw_roundrect_color( _x-14, _y-th-3, _x+width, _y+3, c, c, 0 );
draw_set_alpha( 1 );

c = c_black; draw_text_color( _x, _y, t, c, c, c, c, 1 );

_y- = th+10;
}
// == == == == == == == == == 채팅 끝

 

다음은 키보드값을 받아 입력창에 글을 표시하도록 합니다.

 

(▲ 글자 입력)

 

위와 같이 글자를 입력합니다.

글자가 입력칸을 넘어가면 입력한 끝을 기준으로 문자열을 잘라 표시합니다.

[Draw 이벤트]에 아래와 같이 추가합니다.


obj_chat 오브젝트 - Draw 이벤트
 

draw_set_halign( fa_left ); draw_set_valign( fa_top );
 
var text, _x, _y, c;
text = string_replace_all( keyboard_string, "\n", "" ); //개행 문자는 제거
keyboard_string = string_copy( text, 1, 100 ); //100자 제한
text = keyboard_string;

// == == == == == == == == == 입력창
_x = 80;
_y = 520+32;
draw_set_alpha( 1 );
//c = c_white; draw_roundrect_color( _x-14, _y, _x+width, _y+32, c, c, 0 ); //입력창 배경
c = c_black; draw_text_color( _x, _y+8, get_string_tail( text, 480 )+"|", c, c, c, c, 1 ); //문자열 끝에 커서 표시
// == == == == == == == == == 입력창
 
draw_sprite_ext( spr_chat_top, 0, 0, 0, 1, 1, 0, c_white, 1 ); //채팅창 상단 배경

 

 

[End Step 이벤트]를 추가하고, 저장할 수 있는 채팅글을 제한 하도록 합니다.


obj_chat 오브젝트 - End Step 이벤트
 
 
var sz = ds_list_size( global.chat_list );
var _max = 50;
if sz>_max{
repeat( sz-_max ){
ds_list_delete( global.chat_list, 0 );
}
}

 

채팅 20라인 모두 표시할 수 없을 것 같은데, 강좌에서는 넉넉하게 50 라인만 저장하도록 할 것입니다.

 

 

 

 

 

 

◈ 채팅 테스트

 

일단, 여기까지 마쳤다면 테스트할 수 있게 [Step 이벤트]를 추가하고, 채팅글을 추가하도록 해봅시다.


obj_chat 오브젝트 - Step 이벤트( 임시 테스트용 )

 
if keyboard_check_pressed( vk_enter ){
//문자 필터링
keyboard_string = string_replace_all( keyboard_string, "\n", "" ); //개행 문자열은 제거
if string_length( keyboard_string )>100{ keyboard_string = string_copy( keyboard_string, 1, 100 ); }//최대 100자
 
ds_list_add( global.chat_list, keyboard_string ); //채팅글 추가
 
keyboard_string = "";
}

 

물론 이 설정은 그냥 테스트용입니다.

 

채팅룸에 채팅 오브젝트(obj_chat)을 배치하고, 올바르게 작동하는지 확인해보세요.

(▲ 채팅룸)

 

커서가 깜빡이지 않기 때문에 뭔가 허전해보인다면, 커서를 깜빡이도록 합시다.

 

(▲ 커서 깜빡임)

 

커서 깜빡임을 위해 채팅 오브젝트의 [Create 이벤트]에 변수를 추가합니다.


       obj_chat 오브젝트 - Create 이벤트

   
      cursor = 0;
      alarm[0] = 30; //cursor


 

[Alarm 0 이벤트]를 추가하고, 커서 변수를 변경합니다.


obj_chat 오브젝트 - Alarm0 이벤트


cursor = !( cursor );
alarm[0] = 30; //cursor

 

커서 변수 값이 1일 때 표시하고, 0일 때는 보이지 않게 합니다.

 

[Draw 이벤트]에서 커서 표시 부분을 변경합니다.


obj_chat 오브젝트 - Draw 이벤트


draw_set_halign( fa_left ); draw_set_valign( fa_top );
 
var text, _x, _y, c;
text = string_replace_all( keyboard_string, "\n", "" );
keyboard_string = string_copy( text, 1, 100 );
text = keyboard_string;
 
// == == == == == == == == == 입력창
_x = 80;
_y = 520+32;
draw_set_alpha( 1 );
//c = c_white; draw_roundrect_color( _x-14, _y, _x+width, _y+32, c, c, 0 ); //입력창 배경
 
//---------- ▼
 
c = c_black; draw_text_color( _x, _y+8, get_string_tail( text, 480 )+( ( cursor == 1 ) ? "|" : "" ), c, c, c, c, 1 );
 
//---------- ▲
// == == == == == == == == == 입력창
 
draw_sprite_ext( spr_chat_top, 0, 0, 0, 1, 1, 0, c_white, 1 );

 

잘 되는지 다시 테스트 해봅시다.

 

 

 

 

 

 

 

 

300x250

댓글