이 글에서는 C#을 이용하여 지뢰찾기 게임을 처음부터 만드는 방법에 대한 자세한 설명을 주로 소개하는데, 매우 실용적입니다. 필요하신 분들은 참고하시면 됩니다.
C#을 배우는 이유는 사실 꽤 간단해요. 확인한 결과, 인기 게임 엔진인 Unity의 주요 개발 언어는 C#이므로 C#부터 시작하여 객체 지향 프로그래밍 방법을 배우기로 결정했습니다.
예전에는 임베디드 개발을 기본으로 했습니다. 오랫동안 임베디드 개발을 하다 보니 기본적으로 C 언어만 사용했습니다. C 언어의 프로세스 지향적 특성은 실제로 리소스가 필요한 임베디드 프로그래밍과 같은 상황에서 매우 유용합니다. 극히 제한적이지만, 대규모 소프트웨어 개발에 직면하면 이 방법은 어렵습니다. 프로그래밍 모델은 사실 일종의 사고습관이에요. 오랫동안 익숙해지면 바꾸기 힘든 과정이잖아요...
C# 얘기가 나와서 말인데, 사실 대학에서 한 학기 동안 공부했어요. 그 때 배우지 못한 게 부끄러워서 객체지향 언어로 취급하고(사실 당시에는 객체지향이 뭔지도 몰랐어요) 조금밖에 없는 것 같은 느낌이 듭니다. C 언어와의 구문 차이 모든 사용법은 구문 차이로 분류됩니다. 이 방법도 프로그래밍할 수 있다는 것이 마술적입니다. 학기말에 Winform으로 개발한 지뢰찾기 게임을 제출했는데, 그 일로 C# 학습이 끝났습니다. 그 후로 다시는 C#을 건드리지 않았습니다.
이제 C#으로 돌아왔습니다. 불필요한 간섭을 피하기 위해 Unity에서 직접 공부하지 않고 여전히 VS에서 공부했지만 이번에는 WInform 대신 비교적 새로운 WPF를 선택했습니다. 학습 단계에서 지뢰찾기 게임을 만드는 작업은 이전과 동일합니다.
앞부분에 작성: 이 글은 주로 프로그램 분석 과정을 공유합니다. 구체적인 구현 방법은 이 글의 초점이 아닙니다. 구현에 문제가 있는 친구는 댓글 영역에 메시지를 남겨 소스 코드를 요청하거나 질문할 수 있습니다. 질문^_^.
1. 분석
1. 게임 분석
본 게임을 완료하는 방법에 대해 알아보겠습니다. 세부 사항(예: 타이밍, 남은 지뢰 표시, 메뉴 표시줄 등)은 무시하고 게임의 본체인 지뢰 제거 영역에 대해서만 이야기하겠습니다.
게임 시작 전 지뢰찾기 구역에는 사실 딱 하나 있었는데 그게 블록이었는데...
빛과 그림자 효과를 무시하고(네 또 무시했습니다...), 모두 블록의 색상은 모두 동일하며 모두 동일한 이벤트, 즉 왼쪽 버튼과 오른쪽 버튼에 반응합니다. 블록을 열려면 마우스 왼쪽 버튼을 클릭하고, 블록을 지뢰로 표시하려면 마우스 오른쪽 버튼을 클릭하세요. 분석을 계속하면 다양한 유형의 블록이 있습니다. 일부 블록을 클릭하면 주변에 큰 블록 블록이 열립니다. 일부 블록 아래에는 지뢰가 있습니다. 이를 클릭하면 GameOver가 됩니다. 또한 사각형 아래에는 주변에 광산이 몇 개 있는지 나타내는 숫자도 있습니다. (물론, 두 개의 마우스 버튼을 동시에 눌러 주변 그리드를 자동으로 열고 두 번째 마우스 오른쪽 버튼을 클릭하여 물음표를 표시하는 기능도 무시했습니다... 하지만 실제로 이 기능은 실제로 매우 유용하다는 것을 알게 될 것입니다. 간단하게 추가할 수 있습니다.)
먼저 지뢰찾기 게임의 핵심 구현을 요약해 보겠습니다.
블록은 마우스 이벤트(왼쪽 버튼 누르기, 왼쪽 버튼 클릭, 오른쪽 버튼 누르기, 마우스 이동, 마우스 이동)에 반응합니다.
블록을 클릭하면 세 가지 효과(폭탄, 숫자, 비어 있음)가 있습니다. 블록이 비어 있으면 주변의 모든 블록이 자동으로 확장됩니다.
블록은 한 번만 열 수 있으며 그 이후에는 더 이상 주요 이벤트에 응답하지 않습니다.
깃발이 있는 사각형의 수가 지뢰의 수와 같고, 지뢰가 있는 모든 사각형에 깃발이 있으면 게임이 승리합니다.
광산이 포함된 블록이 열리면 게임이 실패합니다.
2. 구현 기술 분석
분석 결과 지뢰 찾기의 게임 플레이는 실제로 매우 간단하고 이를 구현하는 기술도 어렵지 않은 것으로 나타났습니다.
사각형은 한 번만 누를 수 있는 버튼처럼 동작합니다(사실 저는 대학 시절 버튼 컨트롤을 직접 물려받았습니다).
그런데 이번에는 C# 관련 것들을 더 많이 사용하기 위해 좀 더 번거로운 커스텀 컨트롤 방법을 사용했습니다.
큐브에는 세 가지 형태의 표현이 있는데, 구체적이면서도 공통점도 분명히 있기 때문에 디자인할 때 버튼의 공통점을 추출하여 추상 베이스 클래스 큐브로 디자인했습니다. 큐브에는 세 가지 유형이 있지만 게으르기 때문에 그 중 두 개(공백과 숫자)를 NumCube 클래스에 병합했고, 광산이 포함된 큐브는 BombCube 클래스입니다. 이 두 클래스는 각각 Cube를 상속합니다.
Cube 구현:
Cube 클래스에는 다음 필드가 있습니다.
ImageSource cubeNormalPic ImageSource cubeOnPic ImageSource cubeDownPic ImageSource cubeDisablePic ImageSource cubeFlagPic
이 5개 필드는 큐브가 표시하는 그림을 다양한 상태(일반, 마우스 입력, 왼쪽)로 설정하는 데 사용됩니다. 버튼 누름, 비활성화, 표시됨)
Bool isEnable Bool isFlag
这两个字段就是标记Cube是否被使能和Flag
Image cubeImageHigh Image cubeImageLow
这2个是两个image控件,作用是用来显示图片,之所以要2个图片是因为旗子图片被设计为一个叠加在Cube上的图片。
下面再来重点讲下下面2个东西:
displayCube mouseEvent
在设计中,这是两个接口,分别用来处理鼠标事件和方块的展开。不同于直接在内部直接实现接口,将两个接口设计为Cube属性是为了能动态的修改这两个接口的实现方式,不至于每次修改都需要对Cube内的代码进行修改,且可以实现每个不同的Cube都使用不同的代码而不需要使用重写,这种方式在设计模式中也叫“策略模式”。
Cube只拥有一个方法,那就是Open,但这个方法其实也是有display接口代理实现。
public void Open() { if (displayCube != null) { displayCube.Open(this); } }
displayCube.Open(this)之所以要把自身传入,是因为Open方法要用到Cube自己的参数和方法。
BombCube继承自Cube
只添加了一个字段:
ImageSource bombPic
用来存储地雷图片.
NumCube 继承自Cube
Int bombNum
用来记录方块周围有多少个BombCube,当其为0的时候,NumCube就是显示为空的方块。
添加了一个组件lable用来显示数字Text。
interface的实现
分别为每种Cube设计了一种接口的实现方式,使用这种方式,若后期需要改为动画显示,也只需要实现一个动画的接口,赋值给对应的Cube就可以了。
二、实现
控件继承:
Wpf进行控件继承的时候需要注意,被继承的控件不能有xaml。
在继承的时候,xaml中需要加入如下语句:
< myTypes:Cube x:Class="扫雷.UserControl.NumCube" xmlns=" http:// schemas.microsoft.com/w infx/2006/xaml/presentation " xmlns:x=" http:// schemas.microsoft.com/w infx/2006/xaml " xmlns:mc=" http:// schemas.openxmlformats.org /markup-compatibility/2006 " xmlns:d=" http:// schemas.microsoft.com/e xpression/blend/2008 " mc:Ignorable="d" xmlns:myTypes="clr-namespace:扫雷.UserControl" d:DesignHeight="18" d:DesignWidth="18">
Cube 鼠标事件的实现:
鼠标事件主要是在各个事件中实现对Cube图片的变换,例如鼠标移出事件
public void MouseLeaveCube(object sender, MouseEventArgs e) { BombCube bombCube = sender as BombCube; if (bombCube.IsEnable) { isClicking = false; bombCube.cubeImageLow.Source = bombCube.cubeNormalPic; } }
关于地雷位置的生成算法实现:
游戏很重要的一个方面是,每次地雷的位置应该不同。很容易想到应该用随机数来产生地雷的位置。这就需要随机生成N个不相同的坐标。本程序的实现方法是创建一个listbd43222e33876353aff11e13a7dc75f6,之后使用随机数在0-sizeX * sizeY - 1之间随机生成一个数,检查list中是否包含该数字,若不包含则添加进list,直到list拥有N个元素停止。
List<int> BombIndexList=new List<int>(); Random ran = new Random(); do { int bombIndex = ran.Next(0,sizeX * sizeY - 1); if(!BombIndexList.Contains(bombIndex)) { BombIndexList.Add(bombIndex); } else { continue; } } while (BombIndexList.Count < BombNum); IndexList = BombIndexList;
之后根据生成的list来确定坐标上应该是NumCube还是BombCube
for (int y = 0; y < sizeY; y++) { for (int x = 0; x < sizeX;x++) { //cube属性设置 if(bombIndexList.Exists((int temp) => temp == x + y * cubeX)) { cubexMatrix[x, y] =bombCubeList[bombIndex++]; } else { numCubeList[numIndex].Text =""; cubexMatrix[x, y] =numCubeList[numIndex++]; } cubexMatrix[x, y].IsFlag =false; cubexMatrix[x, y].Margin =new Thickness(x * 18, y * 18, 0, 0); cubexMatrix[x, y].IsEnable = true; SetCubeBombNum(cubexMatrix,cubeX, cubeY); bombGrid.Children.Add(cubexMatrix[x, y]); } }
如何让空白Cube打开以后会打开周围的Cube:
因为这种打开方式有点类似于递归,需要有传染性(即若打开的也是空白Cube,则其也应该打开周围的Cube),所以执行该事件的时候一定要具有周围Cube的信息(即能获取到周围的控件)。
获取周围的Cube的方法有两种:
1.保存Cube自身的位置,并获取所有Cube的位置
2.保存周围Cube的信息
我使用的是第二种方式,之前Cube类中的Cubelist就是用来保存周围Cube的信息的。通过CubeList找到周围Cube,并触发他们的左键单击事件。
public void MouseLeftButtonUp(object sender, MouseButtonEventArgs e) { NumCube numCube = sender as NumCube; if (numCube.IsEnable && numCube.IsFlag == false) { // 完成在控件上点击 if (isClicking) { isClicking = false; numCube.IsEnable = false; if (numCube.BombNum != 0) numCube.Text = Convert.ToString(numCube.BombNum); else { foreach (Cube cubeTemp in numCube.CubeList) { MouseButtonEventArgs args = new MouseButtonEventArgs(Mouse.PrimaryDevice, 0, MouseButton.Left); args.RoutedEvent = Cube.MouseLeftButtonDownEvent; cubeTemp.RaiseEvent(args); args.RoutedEvent = Cube.MouseLeftButtonUpEvent; cubeTemp.RaiseEvent(args); } } } } }
一些小技巧:
1.可以把一些图片的修改放在属性的set内,例如disable的图片。
public bool IsEnable { get { return isEnable; } set { isEnable = value; if (isEnable) { if (cubeNormalPic != null) cubeImageLow.Source = cubeNormalPic; } else { if (cubeDisablePic != null) cubeImageLow.Source = cubeDisablePic; } } }
2.Wpf创建控件较慢,为了提升(修改宽度长度或地雷数量之后)游戏开始速度,应该预先创建控件,并把控件放入list或者arr保存,按照需求取出。
到这扫雷游戏的制作就没什么难度技术上的难度的,只需要通过百度了解一些WPF常用的事件,控件,xalm相关的知识就能做出一个扫雷游戏啦。相关源码就不发在这了,需要的朋友可以评论中找我,这次游戏制作让我对面向对象的基本编程方法的了解有了一个很大的提升,下次应该就可以在Unity中做游戏啦 哈哈。
위 내용은 C#을 사용하여 지뢰찾기 게임용 그래픽 코드 튜토리얼을 만드는 방법의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!