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

[게임메이커 강좌-네트워크][GMS2] 멀티플레이어 게임 만들기-2-서버 만들기

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

 

 

GAME MAKER 강좌

 

KAYAN

 

 

 

 

 

 

◈ 서버 만들기

 

 

네트워크에 필요한 주요 오브젝트를 먼저 만듭니다.

 

   - 서버 오브젝트 : obj_server_system (Persistent 체크)

   - 클라이언트 오브젝트 : obj_client_system (Persistent 체크)

   

   - 유저 오브젝트(서버 전용) : obj_game_user (Persistent 체크)

   

   - 플레이어 부모 오브젝트 : obj_player_parent

   - 플레이어 오브젝트(게임용, 부모 오브젝트 지정) : obj_player_1

   

   - 게임 실행용 오브젝트 : obj_game_stage

   - 플레이어 생성 위치용 오브젝트 : obj_start_point

 

(▲ 주요 오브젝트)

 

서버 오브젝트(obj_server_system)는 서버 실행룸(Room_waiting_server)에 배치하고,

 

클라이언트 오브젝트(obj_client_system)는 클라이언트 실행룸(Room_waiting_client)에 미리 배치합니다.

 

두 오브젝트는 다른 룸으로 이동해도 정보가 계속 유지해야 하기 때문에 [Persistent]를 체크합니다.

 

유저 오브젝트(obj_game_user)는 서버에서 게임 중일 때, 클라이언트를 제어할 설정을 추가할 겁니다.

보통 Ping 체크나, 플레이어 생성, 플레이어 정보저장에 관련된 기능입니다.

이 오브젝트도 다른 룸으로 이동해도 정보가 계속 유지해야 하기 때문에 [Persistent]를 체크합니다.

 

 

게임 실행용 오브젝트(obj_game_stage)는 게임룸에서 게임 제어나 플레이어 생성에 관련된 기능을 설정합니다.

이 오브젝트는 게임룸(Room_game_1)에 미리 배치합니다.

 

플레이어 생성 위치 오브젝트는 플레이어를 생성할 때 위치를 잡아줍니다.

 

 

먼저, 서버 설정부터 시작합니다.

 

[Create 이벤트]를 추가하고, 서버를 생성하도록 합니다.

 
obj_server_system - Create 이벤트
 
 
global.player_max = 5; //클라이언트 최대 접속 수( 서버 유저 제외 )
global.game_room = -1; //게임룸
 
global.user_id = 0; //현재 서버 유저 ID
 
global.socketlist = ds_list_create( ); //클라이언트 소켓 목록
global.player_map = ds_map_create( ); //클라이언트 정보
 
global.net_buffer = buffer_create( 256, buffer_grow, 1 ); //버퍼 생성
 
global.server_socket = network_create_server( network_socket_tcp, 6510 global.player_max );
 
if global.server_socket<0{
//서버 생성 실패했을 때
}
else{
//서버 생성 성공했을 때
}
 

 

다음, 서버 생성에 실패하면, 서버 오브젝트를 파기하고, "서버 생성에 실패했습니다."라고 메시지를 표시합니다.

그리고 메인화면으로 이동하도록 합니다.

 
obj_server_system - Create 이벤트
 
 
if global.server_socket<0{
//서버 생성 실패했을 때
instance_destroy( );
show_message_async( "서버 생성에 실패했습니다." )
room_goto( Room_open );
}
else{
//서버 생성 성공했을 때
global.select_server = 1;
 
var inst = instance_create_depth( 0, 0, 0, obj_game_user );
 
global.game_room = Room_game_1;
room_goto( Room_game_1 );
}
 

 

서버 생성에 성공하면 서버 유저의 유저 오브젝트(obj_game_user)를 생성하도록 합니다.

그리고 게임 룸으로 이동하는 거죠.

클라이언트 유저는 서버로 접속했을 때, 생성하도록 할 거에요.

서버는 바로 이동해서 클라이언트를 기다리도록 합니다.

 

유저 오브젝트의 [Create 이벤트]에 유저의 정보를 저장할 변수를 추가합니다.

 
obj_game_user - Create 이벤트
 
 
select = 0; //현재 유저 여부
 
room_sync = 0; //룸 동기화 체크
 
user_id = 0; //유저 ID
user_name = ""; //유저 이름
 
 
user_gameplay = noone; //플레이어 새성 인스턴스 ID
user_regen = 0; //플레이어 재생성 체크
 

 

그리고 [Alarm 1 이벤트]에는 플레이어 재생성할 때 필요한 변수를 초기화 시켜놓습니다.

 
obj_game_user - Alarm 1 이벤트
 
 
user_regen = 0;
 

 

서버 오브젝트로 돌아가서 서버 유저의 게임 유저 오브젝트를 생성할 때, 변수값을 미리 할당합니다.

 
obj_server_system - Create 이벤트
 
 
global.player_max = 5; //클라이언트 최대 접속 수( 서버 유저 제외 )
global.game_room = -1; //게임룸
 
global.user_id = 0; //현재 서버 유저 ID
 
global.socketlist = ds_list_create( );
global.player_map = ds_map_create( );
 
global.net_buffer = buffer_create( 256, buffer_grow, 1 );
 
global.server_socket = network_create_server( network_socket_tcp, 6510, global.player_max );
 
 
if global.server_socket&lt; 0{
//서버 생성 실패했을 때
instance_destroy( );
show_message_async( "서버 생성에 실패했습니다." )
room_goto( Room_open );
}
else{
//서버 생성 성공했을 때
global.select_server = 1;
 
//---------- ▼ 게임 유저 초기 설정
 
var inst = instance_create_depth( 0, 0, 0, obj_game_user );
 
inst.user_name = global.playername; //유저 이름
inst.user_id = 0; //서버의 유저 ID는 0, 클라이언트는 1~
inst.select = 1; //서버 유저 선택
 
inst.room_sync = 1; //룸 동기화
 
//---------- ▲ 게임 유저 초기 설정
 
global.game_room = Room_game_1;
room_goto( Room_game_1 );
}
 

 

룸 동기화 체크(room_sync)는 클라이언트가 지정한 룸으로 정확히 이동했는지 체크하는 부분입니다.

서버는 룸을 바로 이동할 수 있지만, 클라이언트는 서버에 어느 룸으로 이동할지 요청하고, 서버에서 지정하면

룸을 이동합니다.

게임 룸의 맵을 업데이트해야 할 때, 서버와의 통신에 지연시간이 발생하면 엉뚱한 룸에서 맵을 업데이트 해버릴 수 있습니다.

이것을 방지하기 위해, 지정한 룸에 완전히 이동한 다음, 서버에 동기화 요청을 하고 룸의 맵을 업데이트하도록 합니다.

 

 

[Destroy 이벤트]를 추가하고, 메모리에서 제거해야하는 기능은 파기하도록 합니다.

 
obj_server_system - Destroy 이벤트
 
 
if !( global.server_socket<0 ){ network_destroy( global.server_socket ); }
buffer_delete( global.net_buffer );
 
ds_list_destroy( global.socketlist );
ds_map_destroy( global.player_map );
 
with( obj_game_user ){ instance_destroy( ); }
 

 

서버 오브젝트를 파기할 때, 게임 유저 오브젝트도 같이 삭제하도록 합니다.

 

그리고 [Game End 이벤트]를 추가하고, 같은 내용을 추가합니다.

 
obj_server_system - Game End 이벤트
 
 
if !( global.server_socket<0 ){ network_destroy( global.server_socket ); }
buffer_delete( global.net_buffer );
 
ds_list_destroy( global.socketlist );
ds_map_destroy( global.player_map );
 

 

 

게임 화면을 간편하게 설정해봅시다.

아래 스크립트는 어떤 룸으로 이동하든 룸의 카메라의 크기를 지정한 설정으로 자동으로 처리해줍니다.

※ 다만, 처음 실행되는 룸의 크기가 게임화면의 기준이 됩니다.

 
스크립트
 
 
//카메라 자동 설정
function set_carmera_auto( ){
var vw, vh;
vw = 800; //게임 화면 너비
vh = 600; //게임 화면 높이
 
view_enabled = 1;
view_set_visible( 0, 1 );
camera_set_view_size( view_camera[0], vw, vh );
view_xport[0] = 0;
view_yport[0] = 0;
view_wport[0] = vw;
view_hport[0] = vh;
 
display_set_gui_size( vw, vh );
if window_get_fullscreen( ) == 0{ window_set_size( vw, vh ); }
 
camera_set_view_border( view_camera[0], vw, vh );
camera_set_view_speed( view_camera[0], -1, -1 );
}
 
 
//카메라 오브젝트 자동 설정
function set_carmera_target( ){
with( obj_player_parent ){ if select == 1{ camera_set_view_target( view_camera[0], id ); }}
}
 

 

[Room Start 이벤트]를 추가하고, 룸으로 이동할 때마다 카메라를 자동으로 설정하도록 합니다.

 
obj_server_system - Room Start 이벤트
 
 
set_carmera_auto( ); //카메라 자동 설정
 
 
if ( room == Room_open ){ //메인 화면으로 돌아갔을 때는 서버 오브젝트 파기
global.game_room = -1;
instance_destroy( ); }
 

 

[Room End 이벤트]에는 유저 오브젝트의 플레이어 재생성에 관련된 변수를 초기화 시킵니다.

 
obj_server_system - Room End 이벤트
 
 
with( obj_game_user ){
user_gameplay = noone;
user_regen = 0;
 
if user_id > 0{ room_sync = 0; }//클라이언트는 동기화 요청 대기
}
 

 

여기까지 서버 생성을 마쳤습니다.

다음 강좌에서는 본격적으로 게임 캐릭터의 이동에 대해 만들어 봅시다.

 

 

 

 

 

 

 

 

300x250

댓글