본문 바로가기
학교수업[프로젝트]/개별 프로젝트

네트워크프로그래밍 [경매게임]

by wcwdfu 2024. 12. 31.

4학년 2학기 네트워크 프로그래밍을 수강했습니다. [ 최종 성적 : B ]

 

과목명에 맞게 랜덤하게 정해진 4인으로 네트워크 프로그래밍을 활용한 팀프로젝트 과제가 주어졌고, 우리팀은 '경매게임'을 만들기로 했습니다.

 

본론부터 말하자면 다행히도 소통과 개발 다 원활한 팀원분들을 운좋게 잘 만나서 호기롭게 잘 끝마칠 수 있었습니다.

주제선정에 있어서는 각자 의견제시를 했습니다.

저는 프로젝트 주제상 '미니게임'의 형태가 최적절 하다고 판단되었고, 언젠가 게임앱을 출시한다면 하나의 미니게임으로써 넣어보고싶었던 '경매게임'을 제안하였습니다. 이 게임이 절대 흔하지도 않고 아마 대부분의 사람들이 접해본적 없는 형태의 미니게임이라 판단하여 독창성 측면에서도 매우 우수하다고 판단, 해당 주제를 어필하였고 저희팀원분들도 어떤주제로 하던 상관없다고 하시며 제가 제안한 '경매게임' 을 주제로 프로젝트를 수행하게 되었습니다.

 

스레드와 네트워크 프로그래밍 관련해서 개인적으로는 매우매우 아주아주 유의미한 시간이였습니다.

3번의 발표가 정해져 있었기에 랜덤으로 맞아서 발표를 하기로 하였고, 저는 최종 발표를 맞게 되었습니다.

간단한 게임 소개와 주요 부분 구현 순으로 작성하겠습니다.

 

 아이디어 출처는 어릴적 재밌게 했던 스타크래프트 유즈맵 입니다. ㅎㅎ

게임설명입니다.

경매게임이니까 경매를 해야겠죠? 총 8개의 품목에 대해 4개의 굿즈와 4개의 아이템이 있습니다. 

라운드제 방식으로 라운드마다 하나의 품목에 대해 경매를 진행하게 되구요. 경매품목 선정확률은 굿즈:아이템으로 6:4 입니다.

아이템은 추후 나오게되니 그때 보시고 지금은 그냥 넘어가시면 됩니다.

 

1. 승리조건은 위에서 본 굿즈로 결정됩니다. 서로 다른 4가지 굿즈를 몹거나, 하나의 똑같은 굿즈를 3개를 보유하는 조건으로 가장 먼저 해당 조건을 달성한 1인이 우승하게 됩니다.

2. 진행방식은 앞에서도 언급했지만 라운드 제 방식으로 최종 우승자가 결정되기 전까지 라운드를 무한히 반복합니다.

3. 경매 진행 방법입니다.

- 우선 랜덤하게 선정된 경매품을 보고 10초의 카운트동안 응찰/불응찰 여부 결정

당연히 응찰해야지만 경매참여가 가능합니다

- 응찰자들끼리 호가하며 가격경쟁을 시작합니다. 호가는1/5원 단위로만 가능합니다.

- 호가에서도 5초의 카운트가 있습니다. 호가가 발생한 후, 5초동안 그 누구도 호가를 하지 않으면 마지막 호가를 부른 사람이 소지금이 차감되며 경매물품을 낙찰받게 됩니다.

4. 돈을 버는 방법입니다. 첫 소지금은 100원이며 수입원에는 크게 두가지가 있습니다.

- 한 라운드의 경매에 불참하는것. 경매참여를 못하게되지만 5원을 받을 수 있게됩니다.

- 여기서 4가지 아이템중 첫번째 아이템 '건구스의 지원금'이 등장합니다. 경매품목으로 나타나는 해당 아이템을 낙찰받아 소지하게 되면 경매의 응찰 여부와 상관없이 무조건 라운드마다 5원을 받을 수 있습니다. 예를들어 2개를 소지하면 10원을 받고 1개를 소지하고 한 라운드에 불응찰 해도 10원을 받습니다.

 

 참고로 한 라운드의 응찰자가 한명인경우 한명이 공짜로 아이템을 낙찰받게 되며 응찰자가 한명도없을경우 해당 라운드가 바로 종료되고 다음라운드로 진행되게 됩니다.

 

서버 클라이언트 구조를 채택하여 진행했습니다. 대략적인 패키지 내용은 우측의 이미지와 같습니다.

유일하게 사용한 라이브러리는 1개입니다. ui를 위해 javaFX를 사용하였는데, 학교커리큘럼상 swing을 사용해보게 되어 swing도 언급되었지만 처음 설계 과정에서 swing보다 javafx가 더 최신이며 css를 활용한 세련된 디자인상의 이점이 있다고 하여 채택을 하게 되었습니다.

 

또, 설계단계에서 타이머기능이 있기때문에 Quartz scheduler, 서버 클라이언트간 통신을 위해 Gson 두가지 라이브러리의 사용을 고려했으나, 서버-클라이언트간 통신은 굳이 json으로 주고받을 필요가 없다고 판단, string으로 주고받되 맨앞에 특정키워드(ex: 호가, 낙찰 등등..)을 넣어주어 키워드에 맞는 기능을 시현하게끔 구현하였고, 타이머기능또한 타이머 기능을 담당하게될 별도의 스레드를 생성하여 사용함에 따라 제외되었습니다.

 

 깃 레포 주소는 맨 아래에 있습니다.

 

우리게임은 총 3가지 화면이 있습니다.

시작화면 , 대기화면, 메인게임화면 입니다.

1. 시작화면에서는 같은와이파이환경내에 연결된 상태에서 서버프로젝트를 실행한 컴퓨터의 ip주소와, 사용할 닉네임을 입력해서 들어가주게 됩니다.

2. 저희게임은 유일하게 하나의 대기방만 존재합니다. 해당 대기방에 진입하여 대기하게되고, 4명이 모두 차게되면 5초의 카운트 후 메인게임화면으로 넘어가 게임이 진행되게 됩니다.

 

 

 위에서 설명드렸듯 우리게임은 하나의 대기방이 존재하기 때문에 해당 부분을 싱글톤 패턴으로 구현되었습니다. 따라서 유일한 매칭큐가 존재하게 됩니다. 저희 게임은 다양한 스레드들이 사용되었기 때문에 뒤의 설명에서도 스레드관점에서 설명을 드리도록 하겠습니다. MatchingThread에서 유저들을 매칭큐에 넣어주는 작업을 해주게 되고 WaitingThread에서는 매칭큐에 4명이 차는지를 보고있다가 4명이 차게되면 5초의 카운트 후에 메인게임뷰로 전환하며 본격적인 게임이 시작되게 됩니다.

 사진상으로는 안나와있지만 메인게임은 gameThread에서 진행하게 되는데, WaitingThread에서 대기열 유저들을 인게임 유저로 바꿔주는 작업에서 쓰레드로서 작동하는 ClientHandler를 유저수만큼 생성하여 유저의 인게임 세션관리를 담당하게 되며  최종적으로 gameThread를 실행하는 식으로 작동하게 됩니다.

 

 

 첫번째 사진을통해 설명드리고 싶은건 우리게임이 머리를 써야하는 이유인데요. 좌측상단의 큰 텍스트화면을 보면 한 라운드마다 어떤 경매품목이 선정되었고, 누가 응찰에 참여하였으며 최종적으로 경매품이 낙찰되었는지 유찰되었는지의 정보만 알려줄뿐 누가 낙찰받았는지와 더불어 누가 얼마를 가지고 있는지, 누가 어떤 아이템을 가지고 있는지는 전혀 알수가 없습니다. 따라서 게임이 진행되는 양상과 더불어 남아있는 기록들을 통해 누가 어떤전략으로 승리를 노리고있는지, 자금 상태는 어떠할지등을 유추하여 상대방의 승리를 방해하거나 궁극적으로는 나의 승리를 쟁취할 수 있는 방향으로 전략을 짜야합니다.

 두번째 사진에서는 4개의 아이템중 두번째 아이템인 황소의 분노가 등장하게 됩니다. 한마디로 정의하자면 황소의 분노 아이템은 해당라운드 강제유찰권 입니다. 아이템 사용은 사각형 아이템 아이콘창을 클릭함으로써 사용할 수 있게 되며 입찰이 마감되고 경매품 응찰여부를 발표하는 순간, 해당아이템이 누군가 사용한 상태라면 사진과 같이 강제유찰메세지를 띄우며 경매가 종료되게 됩니다. 예를들어 누군가 거금을 들여 해당 라운드가 종료됬는데 황소의 분노를 누군가 사용했다면, 돈은 돈대로 날리고 아이템도 받지 못하는 대참사가 일어날 수 있게됩니다.

 

 

 이어서 세번째 아이템인 일감호의 기적입니다. 일감호의 기적은 강제낙찰권 입니다. 경매가 진행되는동안 사용할 수 있으며 해당 아이템을 사용하면 그 즉시 입찰이 마감되며 해당 라운드의 경매품을 소지금 차감 없이 즉시 낙찰받게됩니다. 단, 황소의 분노 아이템은 사용의 우위를 갖기 떄문에 만약 일감호의 기적을 쓴 라운드에서 누군가 앞서 본 황소의 분노를 이미 사용한 경우라면 아이템은 아이템대로 날리고 경매품또한 받지못하는 사태가 발생할 수 있습니다.

 마지막 아이템인 스턴건은 한 라운드 내에 응찰상태의 유저를 강제로 불응찰상태로 변경시키는 아이템 입니다. 가운데 사진과 같이 스턴건 아이템을 클릭하게되면 라운드에 응찰한 상태의 유저가 진한 파란색으로 표시되게 되고 그 부분을 다시 클릭하게되면 안내메시지와 함께 해당 유저의 응찰여부가 강제로 불응찰 상태로 변경되게 됩니다. 팀원중 한명이 실제로 이 스턴건 아이템을 모아서 라운드에 응찰한 모든 팀원을 불응찰 상태로 바꿔 아이템을 독식하려는 뛰어난 전략을 보여주셨습니다 ㅎㅎ

 

 

 앞서 설명드렸듯 저희는 string 타입으로 클라이언트 서버간 메세지를 주고받되 앞에 특정키워드를 넣어서 그 키워드에 따라 적재적소 기능이 작동되도록 구현하였습니다. 클라이언트의 경우, javaFX에 있어서 하나의 뷰마다 그 기능을 담당할 controller 클래스를 필요로 하였는데 여기서는 메인게임이 진행되는 뷰를 담당하는 컨트롤러 클래스에서 메세지 처리를 하도록 구현하였습니다. 

 서버에서는 ClientHandler에서 클라이언트로 부터 전달된 메시지를 처리하도록 구현하였습니다.

 

 

 다음은 메인게임이 진행되는 gameThread를 간략히 설명드리겠습니다. endGame이라는 boolean값을 통해서 루프를 계속 돌게되는데 startNewAuctionRound에서 경매품목을 랜덤으로 선정하고 checkParticipation에서 응찰자들을 받게됩니다. 이후 braodcast를 통해 게임이 시작되었음을 유저들에게 알리고 stageIsOngoing 과 같은 boolean값을 통해서 클라이언트 뷰에서 각각의 버튼이 필요한 순간에만 작동할 수 있게끔 구현을 하였습니다. timerManager.bidding에서 호가에 필요한 5초 카운트 기능을 호출하여 사용하게 되는데 타이머는 바로 다음 화면에서 다시 설명드리도록 하겠습니다. endGame = endAuctionRound를 통해 우승조건을 만족한 유저가 있는지 검사를 하는것과 더불어 유저들에게 돈을 지급하고, 서버 클라이언트간 아이템 싱크를 맞춰주는 작업까지 진행해주게 됩니다. 최종적으로 한 라운드 내에 아이템 사용여부를 추적하는 값들을 초기화 시켜주고 난 뒤 전체적인 하나의 라운드가 종료되게 됩니다.

 

 

 타이머 역할을 담당하는 클래스는 위와같이 두가지로 이뤄집니다. Timer클래스에서 타이머는 1초마다 슬립, 다시 남은시간을 braodcast 하는식으로 남은시간이 있고 일감호의 기적(강제낙찰권)이 발동되지 않은 상태인경우에 한해서 while문을 계속해서 돌게됩니다.

 TimerManager에서는 응찰불응찰 여부를 결정할때에는 10초, 최종호가자를 결정할때에는 5초와 같이 필요한 순간의 시간을 p_time등과같은 값을 통해 넣어준 후 스레드를 필요할때마다 생성해주는 식으로 작동하도록 구현하였습니다.

 

 엄밀히 말하면 이번 프로젝트의 게임은 대기방이 하나고, 하나의 게임만 진행이 되기 때문에 유의미한 차이는 없겠으나, 코드적인 관점에 있어서 구현당시에는 필요할때마다 timer 스레드를 매번 생성해서 사용하는 식으로 구현하였는데, 스레드 풀을 통해서 기존의 스레드를 재활용하는 식으로 구현하였으면 조금 더 괜찮은 코드가 되지 않았을까 싶은 아쉬움이 남았습니다.

 

 

 드디어 마지막 화면입니다. 저희팀은 누가 진짜 경매게임의 고수인지 알아보기위해 끝까지 시연게임을 진행하였고, 마지막 라운드의 경매를 끝으로 팀원한분이 조건을 만족하여 게임이 종료되게 되었습니다. 사진과 같이 우승한 사람에게는 승리! 메세지가, 패배한 사람에게는 패배 메세지가 화면 중앙에 애니매이션 효과를 동반한채 표시되면서 게임이 끝나게 됩니다!

 

 

깃 레포 

클라이언트 : https://github.com/Wcwdfu/auctionGameClient

서버 : https://github.com/Wcwdfu/auctionGameServer

 

프로젝트 진행 당시 코인의 미니 불장이 있었습니다. 코인수익금 중 일부인 2만원을 우승상금으로 걸고 동기들중 게임참여자들을 모집에서 1차 경보배 경매게임 대회를 진행해보았습니다. ㅎㅎ

 다들 생각보다 재밌었다고 매우 호평을 주었고 나름 뿌듯한 시간이였던 것 같습니다. ㅎㅎ

 

게임방법 :

모두 같은 와이파이에 연결해서 한사람이 서버 프로젝트를 받고 실행시킵니다.

나머지 유저들은 서버를 실행시킨 사람의 ip주소를 입력해서 들어가고 게임을 하면 됩니다!

 

주의사항:

javaFX관련 버그가 사용중인 자바버전에 따라 잦게 발생하고 있습니다. 참고하여 주시기 바랍니다.

 

--글을 끝마치며

사진을 넣는 과정에서 갑자기 지혼자 멈춰버리는 대참사가 발생했다. 그래서 쓰던걸 한번 더썻다.