C#으로 퐁(Pong) 만들어보기

공작소 2008/07/16 16:13

이 카티코리는 내가 플레이 해왔던 게임에 대한 리뷰와
리뷰한 게임들을 '재미'로 만들어 보기위한 카티코리이다.
(물론 간단한 게임에서 벗어난 경우 리뷰만 존재한다;; )

퐁에 대한 리뷰( http://www.xevious7.com/382 )를 했기 때문에 퐁을 만들어 본다.

워낙 간단한 게임이지만 아무리 간단한 게임이라도 상황에 따라서
만드는 작업은 시간이 천차만별이다.
( 퐁을 최초로 만든시기에는 퐁은 하나의 도전이자 사업이자 유희였지 않았을까?)

예를들어

MSX에서 베이직으로 스프라이트기능을 이용해 만드는 경우
DOS에서 비디오카드를 직접제어하는 , 자체라이브러리로 만드는 경우
DOS에서 BGI를 이용해 만드는 경우
원도우즈 에서 GDI라이브러리로 만드는 경우
원도우즈에서  DirectX로 만드는 경우
원도우즈에서 oengl를 이용해서 만드는 경우
리눅스에서 curses를 이용해서 텍스트 화면으로 만드는 경우
리눅스에서 xlib를 이용해서 만드는 경우
리눅스에서 opengl를 이용해서 만드는 경우

머신과 플랫폼과 라이브러리에 따라서 그리고 작성자의 능력에 따라서
천자 만별이 된다.



이번에는 C#의 폼과 GDI+ 를 이용해 만들기로 했다. 현재 나의 환경에서
가장 최단시간의 노력으로 구현이 가능하기 때문이다.

준비할것은 컴파일러, VS2008 Express 와
퐁이란 게임의 라직이다.

대략적으로 생각하면 , 게임에 필요한 리소스는
게임스코아 , 공 , 그리고 공을 칠 막대기이다.
게임스코아는 텍스트로 뿌리면 될것이고 공과 막대기는
GDI+ 의 기본함수인 FillRectangle 과 FillEllipse 로 가능하기 때문에
따로 이미지파일을 만들 필요가 없는 형태로 가기로 했다.
(좀더 세련되게 하려면 이미지를 만들어야 겠지만)

퐁게임의 라직은

먼저 공에 대한 라직과 , 컴퓨터 플레이어의 AI 두가지이다.
공의 대한 라직은 막힌 벽과 , 바에 맞으면 단순 튕김으로
add_x 값과 add_y 값의 방향만 바꾸는 형태이다.

if (벽과 충돌)  add_x = -add_x
if (바와 충돌)  add_y = -add_y

컴퓨터 플레이어의 바의 움직임은 추후 플레이후 수정을 감안하고
정하진속도에서 최대한 공을 따라가는 형태로 정했다.
(너무 정확하게 따라가는 것을 방지하기 위해서 75%의 히트율만 하도록했다.)
if( rnd.Next(4) != 0) ....       ( 랜덤값이 0 이 아닌경우 공을 따라간다. 따라서 75%히트)

이렇게 간단하게 생각을 정리한후 폼을 만들어 코딩시작 ,소스를 보면 알겠지만
소스는 다른것(재활용,가독성,속도,문서화 등등)은 절대 고려하지 않고
단순 라직 구현만 목적으로 했다. (재미를 목적으로 혼자만의 유희이기 때문에
가능하다.) 5분정도의 타이핑과 몇가지 파라미터 조정 20여분의 시간으로 완성 V.

전체구조는 초간단하게 기본폼에 panel 하나를 만들어 붙이고
On Paint 이벤트에서 화면을 갱신한다.

timer 하나를 붙여 timer에서는 볼의 유효여부를 파악 볼을 생성하거나
볼의 이동시키는 작업과 , 충돌체크 , 컴퓨터의 움직임을 처리했다.

플레이어의 움직임은 Keyboard Event 처리를 붙여
KeyEventArgs e 로 넘어온 e 값과 이동으로 쓸 방향키와 단순비교
처리하였고 , 방향키이외에 a (<-) , s (->) 키도 좌우로 움직이도록
키를 추가하였다.

PS. 러프한 충돌체크 좌표때문에 공의 충돌처리가 매끄럽지 못하는
경우가 있다.

소스코드

namespace Pong
{
  public partial class Form1 : Form
  {
       public int bar1_x = 110;         // user bar start variable.
       public int bar2_x = 110;
       public bool ball_live = false; // ball live flag
       public int ball_x, ball_y, add_x, add_y;
       public Random rnd= new Random();

       public Form1()
       {
           InitializeComponent();
       }

       private void panel1_Paint(object sender, PaintEventArgs e)
       {
           System.Drawing.SolidBrush myBrush = new System.Drawing.SolidBrush(System.Drawing.Color.LightGreen);
           System.Drawing.SolidBrush myBrushGreen = new System.Drawing.SolidBrush(System.Drawing.Color.Green);
           System.Drawing.Graphics panelGraphics;

           panelGraphics = this.panel1.CreateGraphics();
           //panelGraphics.FillRectangle(myBrush, new Rectangle(150, 0, panel1.Width, panel1.Height));
           panelGraphics.FillRectangle(myBrushGreen, new Rectangle(bar2_x,30, 50, 8));
           panelGraphics.FillRectangle(myBrushGreen, new Rectangle(bar1_x,panel1.Height-20,50,8));

           if(ball_live)
           panelGraphics.FillEllipse(myBrushGreen, new Rectangle(ball_x, ball_y, 10, 10));
          
           myBrushGreen.Dispose();
           myBrush.Dispose();
           panelGraphics.Dispose();
          
       }

       private void Form1_KeyDown(object sender, KeyEventArgs e)
       {
           if (e.KeyCode == Keys.Left || e.KeyCode == Keys.A ) bar1_x -= 5;
           if (e.KeyCode == Keys.Right|| e.KeyCode == Keys.S ) bar1_x += 5;
           panel1.Invalidate();
       }

       private void timer1_Tick(object sender, EventArgs e)
       {
           if (ball_live) // ball moving
           {
               ball_x += add_x;
               ball_y += add_y;
               // collision check.
               if (add_y > 0)
               {
                   if (ball_y > (panel1.Height - 30) && ball_y < (panel1.Height - 20))
                   {
                       if (ball_x > bar1_x && ball_x < (bar1_x + 50)) add_y = -add_y;
                   }
               }
               else
               {
                   if (ball_y < 40 && ball_y > 30)
                   {
                       if (ball_x > bar2_x && ball_x < (bar2_x + 50)) add_y = -add_y;
                   }
               }
               // computer move
               if (rnd.Next(4) != 0) // 25% dump
               {
                   if ((ball_x - 25) > bar2_x) bar2_x += 5;
                   else if ((ball_x - 25) < bar2_x) bar2_x -= 5;
               }
               // ball die check
               if (ball_y > panel1.Height || ball_y < 10 ) ball_live = false;
               // wall collision check
               if (ball_x > panel1.Width || ball_x < 0 ) add_x = -add_x;
               panel1.Invalidate();
           }
           else // ball create
           {
              
               ball_x = rnd.Next(200);
               ball_y = 50;
               add_x = 4+ rnd.Next(4);
               add_y = 5;
               ball_live = true;
               Console.Beep();
           }
       }        
  }
}

실행화면.

top

Trackback Address :: http://www.xevious7.com/trackback/384

Write a comment