반응형
처음으로 최근 TV에서 가끔 볼 수 있는 동체 시력을 체크하는 기계의 소프트웨어 버전을 만들어 보았습니다.1초 간격으로 폼내에 랜덤하게 빨간색 램프(●표시)가 표시되므로, 그 때 버튼을 눌러 1분간 몇 개의 버튼을 누를 수 있는지를 측정하는 게임입니다.폼에 배치된 35개의 Label 컨트롤 중 어느 것이든 1개에 ′●′을 표시합니다.해당 컨트롤의 선택에 난수를 사용하여 Timer 컨트롤의 Tick 이벤트 핸들러를 조합하여 1초 간격으로 다른 위치의 Label 컨트롤에 표시합니다.대상 독자 Visual C# 를 이용해 프로그램을 만들고 싶은 초보자 분들을 대상으로 하고 있습니다.필요한 환경 .NET Framework 1.1이 필요합니다.또 샘플 코드의 프로젝트를 열기 위해서는 Visual Studio .NET 2003이 필요합니다.사용자 인터페이스의 작성 사용자 인터페이스의 작성은 간단하게 했습니다.Label 컨트롤과 Button 컨트롤을 35개 정도 배치하고 Timer 컨트롤을 1개 배치하면 됩니다.Label, Button 컨트롤의 배치는 코드에서 각 클래스의 컨스트럭터를 사용해 배치해도 상관은 없습니다만, 설명이 번잡해지기 때문에 이번에는 폼 디자이너 상에서 카피 페이스트를 사용해 배치했습니다.완성은, 샘플 프로그램의 화면을 봐 주세요.각 컨트롤들의 속성 설정값은 표와 같습니다.포인트는 Label 컨트롤의 이름을 번호순으로 설정하고, TabIndex 속성을 컨트롤의 이름과 같은 숫자로 하고 있습니다.예를 들어 Label1은 TabIndex 속성값이 ′1′, Label2는 ′2′가 됩니다.이것은 TabIndex 속성 값을 사용해 빨간색 동그라미를 칠 때의 Label 컨트롤 식별에 사용하기 때문입니다.Timer 컨트롤에 대해서 이 컨트롤은 사용자의 작업을 접수하는 것이 아니고 설정한 시간 간격으로 Tick이라고 하는 이벤트를 발생합니다.이 Tick 이벤트 핸들러에 처리를 기술해 놓으면, 그 처리를 일정 간격으로 계속 반복하게 되는 것입니다.애니메이션 처리나 시간 표시 등에 자주 사용되는 컨트롤로 Enabled 속성에서 Timer 컨트롤의 온/오프를 바꿉니다(Timer 컨트롤을 폼에 배치한 시점에서는 Enabled 속성은 기본적으로 ′False′로 되어 있습니다).프로그램 시작 시부터 Timer 컨트롤을 동작시키고 싶으면 속성 창에서 이 Enabled 속성을 ′True′로 합니다.프로그램 실행 후에 Timer를 켜고 싶다면 Button 컨트롤이나 메뉴의 이벤트 핸들러에서 이 Enabled 속성을 ′True′로 하겠습니다.Tick 이벤트를 발생시키는 시간 간격은 Interval 속성을 사용합니다.설정치는 밀리초입니다.프로그램의 동작 내용 이 프로그램은, 다음과 같이 동작하도록 했습니다.시작버튼을 누르면 Timer 컨트롤이 작동합니다.
Timer 컨트롤의 Tick 이벤트 핸들러에서는 우선 모든 Label 컨트롤의 표시를 「○」으로 셋팅합니다.
그런 다음 빨간색 동그라미를 표시하는 Label 컨트롤을 지정하기 위해서 1부터 35까지의 난수를 발생시킵니다.
발생한 난수를 사용하고, 그 번호의 Label 컨트롤로 「●」을 표시합니다.
난수는 Timer 컨트롤의 Interval 속성에 설정한 1초마다 작성되므로 그 시간 간격으로 빨간색 동그라미에 대한 점멸이 시작됩니다.
그와 동시에, 폼에 표시하고 있는 초수의 카운트 다운을 개시합니다.
사용자가 빨간색 동그라미 아래의 버튼을 누르면 Label 컨트롤에 빨간색 동그라미가 표시되어 있을 때만 히트 카운트를 하나 늘립니다.
게임 동작시간 60초가 경과하면 Timer 컨트롤을 중지하고 다음 시작에 대비합니다.프로그램 시작부터 시작할 준비입니다.게임은 [Start] 버튼을 누르면 시작하기 때문에 Click 이벤트 핸들러로 처리를 하겠습니다.블록 밖에서 변수 2개를 선언합니다.하나는 게임 시간의 카운트다운에 사용하는 i이고, 다른 하나는 히트한 수의 카운트에 사용하는 hitcount입니다.그리고 Start 버튼의 Click 이벤트 핸들러를 만들고 Timer 컨트롤의 Enabled 속성을 True로 만들어서 점수 및 남은 시간 표시를 설정합니다.또, 2개의 변수를 각각 초기화해 둡니다.변수 i에 60이 아닌 59를 대입하고 있는 것은 게임 시간은 59에서 0까지이기 때문입니다.int i ;
int hitcount ;
private void StartButton _ Click ( object sender , System . EventArgs e )
{
this . timer 1 . Enabled = true ;
this . scorelabel . Text = ′ 0 ′ ;
this . countdown . Text = ′ 60 ′ ;
i = 59 ;
hitcount = 0;
} 프로그램 실행 중 Timer 컨트롤이 동작하기 시작하므로 빨간색 동그라미 표시 처리를 합니다.첫 번째, 게임 시작 전 처리입니다.포인트는 한번 게임을 끝낸 경우, 이미 ′●′이 표시되어 있으면, ′○′으로 바꿉니다.어떤 Label 컨트롤에 「●」이 표시되어 있는지 모르기 때문에 foreach 스테이트먼트에서 모든 Label 컨트롤을 「○」로 설정했습니다.foreach 스테이트먼트는 배열이나 컬렉션 오브젝트 내의 요소 하나하나에 액세스하는 처리를 반복하는 스테이트먼트입니다.아래와 같이 대상 컬렉션에서 지정한 형태로 오브젝트에 액세스하고 거기에 대한 참조를 변수 var에 저장합니다.이를 이용해 폼 상의 Label 컨트롤들을 하나하나 액세스하고 Text 속성을 ○로 설정합니다.foreach(지정한 형 변수 var in 대상 컬렉션) 나머지는 변수 var 에서 오브젝트의 속성 및 메서드를 조작합니다.컬렉션 내 모든 객체에 액세스하면 루프 처리가 종료됩니다.여기에서는 폼의 Controls 컬렉션 내에서 Control 오브젝트 하나하나에 접속합니다.foreach(System.Windows.Forms.Control lb in this.Controls) 당연히 폼에는 Label 컨트롤 이외에 Button 컨트롤도 배치되어 있기 때문에 이 중에서 Label 컨트롤만 선별합니다.컨트롤의 Name 속성을 참조하여 컨트롤명의 선두가 label로 시작하는 문자인지 여부를 Starts With 메서드를 사용하여 판단합니다.Starts With 메서드는 String 클래스의 메서드로 인수로 지정한 문자열(String)이 조작 대상 문자열의 선두와 일치하는지 여부를 판단하는 메서드입니다.if (lb.Name.StartsWith (′label′)) 이것으로 폼상의 컨트롤군 중에서 Label 컨트롤만 찾을 수 있습니다.private void timer 1 _ Tick ( object sender , System . EventArgs e )
{
int c , rnd ;
// Tick 이벤트 1회 발생 시마다 1초 차감
c = i -- ;
// 게임이 시작되면 Start 버튼을 해제한다.
this . StartButton . Enabled = false ;
//우선 이미 있는 Label 컨트롤의 빨간 동그라미 지우기
foreach ( System . Windows . Forms . Control lb in this . Controls )
{
if ( lb . Name . StartsWith ( ′ label ′ ))
{
lb . Text = ′ ○ ′ ;
lb . ForeColor = System . Drawing . Color . Black ;
}
}}다음 게임 종료 시 처리입니다.변수 c가 0미만으로 되어 있으면 게임시간이 없어진 것이 되므로 Timer컨트롤을 정지하고 [Start]버튼을 활성화 하고 다음 게임개시에 대비합니다.덧붙여 블록내에 return 스테이트먼트를 기술하면, 이 시점에서 코드의 실행을 종료시킬 수 있습니다. // 만약 게임시간이 0이 되면
if ( c < 0 )
{
this . timer 1 . Enabled = false ;
this . countdown . Text = ′ 60 ′ ;
this . StartButton . Enabled = true ;
return ;
} 게임을 실행할 수 있는 상황이라면 난수를 발생시킵니다.이는 Random 클래스의 인스턴스를 작성하고 Next 메서드를 수행합니다.Next 메소드는 오버로드이기 때문에 여기서 난수를 발생시키는 범위를 지정할 수 있는 Next 메소드를 사용하기로 했습니다.인수는 2개로, 발생시키고 싶은 난수의 하한치와 상한치를 지정합니다. // 1부터 35까지의 난수 발생
Random rd = new Random ( ) ;
rnd = rd.Next(1,35); 난수가 생성되면 다시 foreach 스테이트먼트로 폼상의 컨트롤에 액세스하여 Label 컨트롤을 찾아 TabIndex 속성값을 조사합니다.그리고 이 값이 난수와 일치하면 그 Text 속성을 ′●′으로 설정하고 ForeColor 속성을 빨간색(System.Drawing.Color.Red)으로 하겠습니다.foreach ( System . Windows . Forms . Control lb in this . Controls )
{
// 취득한 난수로 Label 컨트롤에 빨간 동그라미를 그어
if ( lb . TabIndex == rnd )
{
lb . Text = ′ ● ′ ;
lb . ForeColor = System . Drawing . Color . Red ;
}
}}마지막으로 1초를 줄인 게임의 경과시간을 표시합니다만, C#에서는 암묵적인 데이터형 변환이라는 것이 없습니다.따라서 정수인 변수 c의 값을 ToString메소드에서 문자열로 변환하는 작업이 필요합니다. // 초수의 카운트다운 표시
this . countdown . Text = c . ToString ( ) ;
}} 히트여부에 대한 판정 ′●′이 붙어 있을 때 버튼을 누르면 히트 카운터를 1개 늘리는 처리는 각 Label 컨트롤 아래에 배치한 Button 컨트롤에서 합니다.이 처리는 35개를 배치한 Button 컨트롤 모든 Click 이벤트 핸들러에 생성을 합니다.처리는 Click 이벤트가 발생했을 때 버튼 위에 위치한 Label 컨트롤에 ′●′이 표시되어 있으면 히트카운터 1개를 더 늘리고, 그렇지 않으면 아무것도 하지 않습니다.private void button 1 _ Click ( object sender , System . EventArgs e )
{
if ( this . label 1 . Text == ′ ● ′ )
{
hitcount ++ ;
this . scorelabel . Text = hitcount . ToString ( ) ;
}
}
private void button 2 _ Click ( object sender , System . EventArgs e )
{
if ( this . label 2 . Text == ′ ● ′ )
{
hitcount ++ ;
this . scorelabel . Text = hitcount . ToString ( ) ;
}
}
private void button 3 _ Click ( object sender , System . EventArgs e )
{
if ( this . label 3 . Text == ′ ● ′ )
{
hitcount ++ ;
this . scorelabel . Text = hitcount . ToString ( ) ;
}
}
// *********** 중략 **************
private void button 35 _ Click ( object sender , System . EventArgs e )
{
if ( this . label 35 . Text == ′ ● ′ )
{
hitcount ++ ;
this . scorelabel . Text = hitcount . ToString ( ) ;
}
}}정리 이번에는, Timer 컨트롤과 난수, foreach 스테이트먼트를 사용한, 간단한 게임 프로그램을 작성했습니다.Random 클래스와 Next 메소드를 사용하면 난수를 발생할 수 있다.
foreach 스테이트먼트는 컬렉션이나 배열 내의 요소 모두에 액세스 해, 각 요소에 대한 참조를 취득할 수 있는 스테이트먼트.
수치 데이터의 문자열 변환은 변수가 가진 ToString 메서드를 사용한다.참고자료 MSDN 라이브러리 『Timer 클래스』
MSDN 라이브러리 Random 클래스
Timer 컨트롤의 Tick 이벤트 핸들러에서는 우선 모든 Label 컨트롤의 표시를 「○」으로 셋팅합니다.
그런 다음 빨간색 동그라미를 표시하는 Label 컨트롤을 지정하기 위해서 1부터 35까지의 난수를 발생시킵니다.
발생한 난수를 사용하고, 그 번호의 Label 컨트롤로 「●」을 표시합니다.
난수는 Timer 컨트롤의 Interval 속성에 설정한 1초마다 작성되므로 그 시간 간격으로 빨간색 동그라미에 대한 점멸이 시작됩니다.
그와 동시에, 폼에 표시하고 있는 초수의 카운트 다운을 개시합니다.
사용자가 빨간색 동그라미 아래의 버튼을 누르면 Label 컨트롤에 빨간색 동그라미가 표시되어 있을 때만 히트 카운트를 하나 늘립니다.
게임 동작시간 60초가 경과하면 Timer 컨트롤을 중지하고 다음 시작에 대비합니다.프로그램 시작부터 시작할 준비입니다.게임은 [Start] 버튼을 누르면 시작하기 때문에 Click 이벤트 핸들러로 처리를 하겠습니다.블록 밖에서 변수 2개를 선언합니다.하나는 게임 시간의 카운트다운에 사용하는 i이고, 다른 하나는 히트한 수의 카운트에 사용하는 hitcount입니다.그리고 Start 버튼의 Click 이벤트 핸들러를 만들고 Timer 컨트롤의 Enabled 속성을 True로 만들어서 점수 및 남은 시간 표시를 설정합니다.또, 2개의 변수를 각각 초기화해 둡니다.변수 i에 60이 아닌 59를 대입하고 있는 것은 게임 시간은 59에서 0까지이기 때문입니다.int i ;
int hitcount ;
private void StartButton _ Click ( object sender , System . EventArgs e )
{
this . timer 1 . Enabled = true ;
this . scorelabel . Text = ′ 0 ′ ;
this . countdown . Text = ′ 60 ′ ;
i = 59 ;
hitcount = 0;
} 프로그램 실행 중 Timer 컨트롤이 동작하기 시작하므로 빨간색 동그라미 표시 처리를 합니다.첫 번째, 게임 시작 전 처리입니다.포인트는 한번 게임을 끝낸 경우, 이미 ′●′이 표시되어 있으면, ′○′으로 바꿉니다.어떤 Label 컨트롤에 「●」이 표시되어 있는지 모르기 때문에 foreach 스테이트먼트에서 모든 Label 컨트롤을 「○」로 설정했습니다.foreach 스테이트먼트는 배열이나 컬렉션 오브젝트 내의 요소 하나하나에 액세스하는 처리를 반복하는 스테이트먼트입니다.아래와 같이 대상 컬렉션에서 지정한 형태로 오브젝트에 액세스하고 거기에 대한 참조를 변수 var에 저장합니다.이를 이용해 폼 상의 Label 컨트롤들을 하나하나 액세스하고 Text 속성을 ○로 설정합니다.foreach(지정한 형 변수 var in 대상 컬렉션) 나머지는 변수 var 에서 오브젝트의 속성 및 메서드를 조작합니다.컬렉션 내 모든 객체에 액세스하면 루프 처리가 종료됩니다.여기에서는 폼의 Controls 컬렉션 내에서 Control 오브젝트 하나하나에 접속합니다.foreach(System.Windows.Forms.Control lb in this.Controls) 당연히 폼에는 Label 컨트롤 이외에 Button 컨트롤도 배치되어 있기 때문에 이 중에서 Label 컨트롤만 선별합니다.컨트롤의 Name 속성을 참조하여 컨트롤명의 선두가 label로 시작하는 문자인지 여부를 Starts With 메서드를 사용하여 판단합니다.Starts With 메서드는 String 클래스의 메서드로 인수로 지정한 문자열(String)이 조작 대상 문자열의 선두와 일치하는지 여부를 판단하는 메서드입니다.if (lb.Name.StartsWith (′label′)) 이것으로 폼상의 컨트롤군 중에서 Label 컨트롤만 찾을 수 있습니다.private void timer 1 _ Tick ( object sender , System . EventArgs e )
{
int c , rnd ;
// Tick 이벤트 1회 발생 시마다 1초 차감
c = i -- ;
// 게임이 시작되면 Start 버튼을 해제한다.
this . StartButton . Enabled = false ;
//우선 이미 있는 Label 컨트롤의 빨간 동그라미 지우기
foreach ( System . Windows . Forms . Control lb in this . Controls )
{
if ( lb . Name . StartsWith ( ′ label ′ ))
{
lb . Text = ′ ○ ′ ;
lb . ForeColor = System . Drawing . Color . Black ;
}
}}다음 게임 종료 시 처리입니다.변수 c가 0미만으로 되어 있으면 게임시간이 없어진 것이 되므로 Timer컨트롤을 정지하고 [Start]버튼을 활성화 하고 다음 게임개시에 대비합니다.덧붙여 블록내에 return 스테이트먼트를 기술하면, 이 시점에서 코드의 실행을 종료시킬 수 있습니다. // 만약 게임시간이 0이 되면
if ( c < 0 )
{
this . timer 1 . Enabled = false ;
this . countdown . Text = ′ 60 ′ ;
this . StartButton . Enabled = true ;
return ;
} 게임을 실행할 수 있는 상황이라면 난수를 발생시킵니다.이는 Random 클래스의 인스턴스를 작성하고 Next 메서드를 수행합니다.Next 메소드는 오버로드이기 때문에 여기서 난수를 발생시키는 범위를 지정할 수 있는 Next 메소드를 사용하기로 했습니다.인수는 2개로, 발생시키고 싶은 난수의 하한치와 상한치를 지정합니다. // 1부터 35까지의 난수 발생
Random rd = new Random ( ) ;
rnd = rd.Next(1,35); 난수가 생성되면 다시 foreach 스테이트먼트로 폼상의 컨트롤에 액세스하여 Label 컨트롤을 찾아 TabIndex 속성값을 조사합니다.그리고 이 값이 난수와 일치하면 그 Text 속성을 ′●′으로 설정하고 ForeColor 속성을 빨간색(System.Drawing.Color.Red)으로 하겠습니다.foreach ( System . Windows . Forms . Control lb in this . Controls )
{
// 취득한 난수로 Label 컨트롤에 빨간 동그라미를 그어
if ( lb . TabIndex == rnd )
{
lb . Text = ′ ● ′ ;
lb . ForeColor = System . Drawing . Color . Red ;
}
}}마지막으로 1초를 줄인 게임의 경과시간을 표시합니다만, C#에서는 암묵적인 데이터형 변환이라는 것이 없습니다.따라서 정수인 변수 c의 값을 ToString메소드에서 문자열로 변환하는 작업이 필요합니다. // 초수의 카운트다운 표시
this . countdown . Text = c . ToString ( ) ;
}} 히트여부에 대한 판정 ′●′이 붙어 있을 때 버튼을 누르면 히트 카운터를 1개 늘리는 처리는 각 Label 컨트롤 아래에 배치한 Button 컨트롤에서 합니다.이 처리는 35개를 배치한 Button 컨트롤 모든 Click 이벤트 핸들러에 생성을 합니다.처리는 Click 이벤트가 발생했을 때 버튼 위에 위치한 Label 컨트롤에 ′●′이 표시되어 있으면 히트카운터 1개를 더 늘리고, 그렇지 않으면 아무것도 하지 않습니다.private void button 1 _ Click ( object sender , System . EventArgs e )
{
if ( this . label 1 . Text == ′ ● ′ )
{
hitcount ++ ;
this . scorelabel . Text = hitcount . ToString ( ) ;
}
}
private void button 2 _ Click ( object sender , System . EventArgs e )
{
if ( this . label 2 . Text == ′ ● ′ )
{
hitcount ++ ;
this . scorelabel . Text = hitcount . ToString ( ) ;
}
}
private void button 3 _ Click ( object sender , System . EventArgs e )
{
if ( this . label 3 . Text == ′ ● ′ )
{
hitcount ++ ;
this . scorelabel . Text = hitcount . ToString ( ) ;
}
}
// *********** 중략 **************
private void button 35 _ Click ( object sender , System . EventArgs e )
{
if ( this . label 35 . Text == ′ ● ′ )
{
hitcount ++ ;
this . scorelabel . Text = hitcount . ToString ( ) ;
}
}}정리 이번에는, Timer 컨트롤과 난수, foreach 스테이트먼트를 사용한, 간단한 게임 프로그램을 작성했습니다.Random 클래스와 Next 메소드를 사용하면 난수를 발생할 수 있다.
foreach 스테이트먼트는 컬렉션이나 배열 내의 요소 모두에 액세스 해, 각 요소에 대한 참조를 취득할 수 있는 스테이트먼트.
수치 데이터의 문자열 변환은 변수가 가진 ToString 메서드를 사용한다.참고자료 MSDN 라이브러리 『Timer 클래스』
MSDN 라이브러리 Random 클래스
반응형