C#开发-----百变方块游戏

转载请标明是引用于 http://blog.csdn.net/chenyujing1234

例子代码:

n 游戏在 6× 6 格子的棋盘中进行,可排出55种不同的组合图案。主要开发人的抽象思维能力、空间想象能力、动手能力、几何构建能力。游戏运行时功能如下。
n (1)实现用鼠标拖动拼块,拼块任意位置摆放。
n (2)绕拼块的中心点旋转(旋转由鼠标右键操作实现)。
n (3)拼块水平翻转(由鼠标双击操作实现)

n百变方块游戏效果如图22-1所示。用户拖动棋盘周围的8种拼块到棋盘中,直到棋盘所有空白方块格子被填满则此关游戏胜利。单击“新方块图案”按钮则进入下一关游戏。如果玩家无法完成则可以单击“参考答案”按钮查看参考拼图方案。

 

地图信息存储
 
n 地图信息采用文本文件map.txt存储保存。根据目标图案按列存放,每关占一行。0代表固定不变的绿色填充方格,1代表蓝色填充的方格(即需要用户的8种拼块填充的方格)。
1,1,1,1,1,1 , 1,1,1,1,1,1 , 0,0,0,0,0,1 , 0,1,0,1,0,1 , 1,1,1,1,1,1 , 1,1,1,1,1,1 ,
1,1,1,1,1,1,1,1,0,1,0,1,1,0,0,0,0,1,1,1,0,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,0,1,1,1,1,1,0,0,0,1,1,1,0,0,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,
n 游戏在 6× 6 格子的棋盘中进行,每关开始时从文本文件map.txt读取相应关所对应行的字符串, 分割后将数据按列将目标图案存储到二维数组 OrgMap[6,6] 而用户移动拼块后的图案按列存储到二维数组Map[6,6]中。通过对比两个数组知道是否成功完成此关。

 

1.拼块类(CChip.cs
字段 m_nType 存储拼块的类型代号,总计有7个拼块。分别用 1 8 代表图22-3的七个拼块。 m_nPointCount 存储拼块的顶点个数, m_pointList 存储拼块的顶点坐标。 myPath 是形成拼块的路径。
 
class CChip
    {
        Point []m_pointList;     //顶点坐标
        int m_nPointCount;     //顶点个数
        int m_nType;          //类型代号
        private GraphicsPath myPath;
        …….
}

 

拼块的参数设置方法SetChip
 
      拼块类提供对拼块的参数设置方法SetChip,该方法完成拼块类型代号的设置,拼块图案顶点坐标初始化,最终形成拼块的路径。
        public void SetChip(int type,  Point []ppointlist, int count)  
        { 
            m_nType = type; 
            m_nPointCount = count; 
            m_pointList = new Point[m_nPointCount]; 
            for(int i=0; i<count; i++) 
            m_pointList[i] = ppointlist[i]; 
            myPath = new GraphicsPath(); 
            myPath.AddLines(m_pointList); 
            myPath.CloseFigure();//CloseFigure方法闭合当前图形并开始新图形。 
        } 


 

拼块的平移
Move(int x_offset, int y_offset)应用Matrix实现GraphicsPath路径的平移。
        public  void Move(int x_offset, int y_offset)
        {
            Matrix matrix = new Matrix();
            matrix.Translate(x_offset, y_offset); //追加平移
            myPath.Transform(matrix);//应用变形
            myPath.CloseFigure();
        }
        Move2(int x_offset, int y_offset)不用Matrix实现GraphicsPath路径的平移,而是直接对路径的每个顶点一一平移。
        public void Move2(int x_offset, int y_offset)
        {
            myPath.Reset();                  //清空路径
            for (int i = 0; i < m_nPointCount; i++) // 平移各顶点
            {
                m_pointList[i].X += x_offset;
                m_pointList[i].Y += y_offset;
            }
            myPath.AddLines(m_pointList);
            myPath.CloseFigure();
        }
拼块的旋转
Rotation()应用Matrix实现GraphicsPath路径的旋转,每次旋转45度。
        public  void Rotation()
        {
            Matrix matrix = new Matrix();
            RectangleF rect = new RectangleF();
            rect = myPath.GetBounds();
            // 计算旋转中心坐标(x,y)
            double x = rect.Left + rect.Width / 2;
            double y = rect.Top + rect.Height / 2;
            //matrix.Rotate(45.0f); //旋转顺时针45度
            matrix.RotateAt(45.0f, new Point((int)x, (int)y)); //旋转顺时针45度
        }
拼块的旋转(2
Rotation2()不用Matrix实现GraphicsPath路径的旋转,而是获取myPath的矩形区域,计算旋转中心,从而计算出每个顶点的新坐标。
        public void Rotation2()
        {
            RectangleF rect=new RectangleF() ;
            rect=myPath.GetBounds();
            myPath.Reset();                //清空路径
            double x = rect.Left + rect.Width/2; // 计算旋转中心
            double y = rect.Top + rect.Height/ 2;
            double dx, dy;
            for (int i = 0; i < m_nPointCount; i++) // 旋转各顶点
            {
                dx = m_pointList[i].X  - x;
                dy = m_pointList[i].Y - y;
                m_pointList[i].X = (int)(x + dx * 0.7071 - dy * 0.7071);
                m_pointList[i].Y = (int)(y + dx * 0.7071 + dy * 0.7071);
            }             
            myPath.AddLines(m_pointList);
            myPath.CloseFigure();
        }
拼块水平反转
ReverseTurn()获取myPath的矩形区域,计算旋转中心,从而计算出水平翻转后每个顶点的新坐标。
        public void ReverseTurn()               // 水平反转
        {
            RectangleF rect = new RectangleF();
            rect = myPath.GetBounds();
            myPath.Reset();
            double x = rect.Left + rect.Width / 2; // 计算旋转中心
            double y = rect.Top + rect.Height / 2;
            for (int i = 0; i < m_nPointCount; i++) // 水平反转各点
            {
                m_pointList[i].X = (int)(2 * x - m_pointList[i].X);
                m_pointList[i].Y = m_pointList[i].Y;
            }
            myPath.AddLines(m_pointList);
            myPath.CloseFigure();
        }

DrawChip( ) Graphics 对象上画出拼块。每个拼块设置不同的填充颜色。

public void DrawChip(Graphics g)//画拼块
        {  
            Pen myPen = new Pen(Color.Black, 1);
            g.DrawPath(myPen, myPath);
            int alpha = 140;   //透明度
            Color c= Color.FromArgb(alpha, 255, 255, 255);
            switch (m_nType)
            {
                case 1:
                    c = Color.FromArgb(alpha, 127, 127, 127);
                    break;
                case 2:
                    c = Color.FromArgb(alpha, 255, 0, 0);
                    break;
                case 3:
                    c = Color.FromArgb(alpha, 200, 255, 0);
                    break;
                .......
                case 8:
                    c = Color.FromArgb(alpha, 228, 128, 128);
                    break;
            }            
            SolidBrush brushNew = new SolidBrush(c);
            g.FillPath(brushNew, myPath); 
        }

对用户移动的拼块进行位置校正
Verity(int CHIP_WIDTH)对用户移动的拼块进行位置校正,方法是判断拼块的第一个顶点坐标m_pointList[0]接近棋盘中那个方格,则计算出偏移量后,对拼块的所有顶点进行修正,保证拼块移动到适当的方格位置处。
        public void Verity(int CHIP_WIDTH)
        {
            myPath.Reset();                         //清空路径
            int x_offset=0, y_offset=0;
            int d;
            d=m_pointList[0].X % CHIP_WIDTH;
            if (d != 0)
                x_offset -= (d < CHIP_WIDTH / 2 ? d:d- CHIP_WIDTH);
            d = m_pointList[0].Y % CHIP_WIDTH;
            if (d != 0)
                y_offset -= (d < CHIP_WIDTH / 2 ? d:d- CHIP_WIDTH);
            for (int i = 0; i < m_nPointCount; i++) // 平移各点
            {
                m_pointList[i].X += x_offset;
                m_pointList[i].Y += y_offset;
            }
            myPath.AddLines(m_pointList);
            myPath.CloseFigure();
        }

2.设计窗体类(Form1.cs)
 
窗体加载事件


 

int [,]Map=new int[6,6];
    int[,] OrgMap = new int[6, 6];//初始化目标地图OrgMap

     窗体加载事件中,调用Reset()对8个拼块的顶点坐标m_chipList 数组初始化。调用ReadOrgMap(1)方法读出第一关目标图案的地图信息到OrgMap二维数组中。
    private void Form1_Load(object sender, EventArgs e)
    {
        Reset();// 初始化拼图块
        //以下两句是为了设置控件样式为双缓冲,这可以有效减少闪烁的问题
        this.SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint, true);
        this.UpdateStyles();
        ReadOrgMap(1); //读出第一关目标图案的地图信息到OrgMap二维数组中
        Draw_AllChip();//画出所有拼块
    }

 

初始化拼块
Reset()初始化拼图块顶点坐标m_chipList 数组,并形成拼块的图形路径。

private void Reset()
    {
        for (int i = 0; i < CHIP_COUNT; i++)
            m_chipList[i] = new CChip();
        Point[] pointList = new Point[MAX_POINTS];
        int sx=250, sy=0;
        pointList[0] = new Point(sx , sy );
        pointList[1] = new Point(sx +  2* CHIP_WIDTH, sy );
        pointList[2] = new Point(sx +  2* CHIP_WIDTH, sy + 2 * CHIP_WIDTH);
        pointList[3] = new Point(sx , sy + 2 * CHIP_WIDTH);       
        m_chipList[0].SetChip(1, pointList, 4); //m_chipList[0]为一个2W*2W的正方形
        sx =170 ; sy = 90;
        pointList[0] = new Point(sx + CHIP_WIDTH * 2, sy);
        pointList[1] = new Point(sx + CHIP_WIDTH * 6, sy);
        pointList[2] = new Point(sx + CHIP_WIDTH * 6, sy + CHIP_WIDTH);
        pointList[3] = new Point(sx + CHIP_WIDTH * 2, sy + CHIP_WIDTH);       
        m_chipList[1].SetChip(2, pointList, 4); //m_chipList[1]为一个4W*1W的长方形
        ……
}
读出第n关的地图信息
ReadOrgMap()方法从map.txt文本文件按行读出第n关目标图案的地图信息到OrgMap二维数组中。
private void ReadOrgMap(int n)
    {
        string filename = "map.txt";
        FileStream fs = File.OpenRead(filename);
        StreamReader sr = new StreamReader(fs, Encoding.Default);
        string t = null;
        while (n > 0)
        {
            t = sr.ReadLine();
            n--;
        }
        sr.Close();
        fs.Close();
        string [] a = new string[36 + 1];
        a = t.Split(',');
        for (int i = 1; i < 7; i++)
            for (int j = 1; j < 7; j++)                
                OrgMap[i-1, j-1]=Convert.ToInt16(a[(i-1)*6+j-1]);
    }


 

新方块图案按钮单击事件
计算出新图案序号n,调用Reset()对8个拼块m_chipList 数组初始化并调用Draw_AllChip()画出所有8个拼块。
private void button1_Click(object sender, EventArgs e)//“新图案”按钮
    {
        n++;                        
        if (n > max)
        {
            MessageBox.Show("没有新图案了");
            n--;
            return;
        }
        ReadOrgMap(n);//读目标地图OrgMap文件
        Map = new int[6, 6];
        Reset();					// 初始化拼图块
        Draw_AllChip();				//画出所有拼块
    }

Draw_AllChip()画出所有拼块
Draw_AllChip()根据新图案序号n缩半画出640*480的目标图案,通过循环调用拼块类Cchip. DrawChip() 方法画出所有拼块。
private void Draw_AllChip()			///画出所有拼块及目标图案
    {
        Bitmap bmp = new Bitmap(this.Width, this.Height);
        this.BackgroundImage = bmp;
        //Graphics g = this.CreateGraphics();
        Graphics g = Graphics.FromImage(bmp);            
        g.Clear(this.BackColor);
        string r=n.ToString()+".jpg"; 
        Bitmap s = (Bitmap)Image.FromFile(r);
        //g.DrawImage(s,new  Point(400, 0)); 
        g.DrawImage(s, new Rectangle(450, 10, 320, 240), 
            new Rectangle(0, 0, 640, 480),GraphicsUnit.Pixel); //在(450,10)处显示320*240图案
        for (int i = 0; i < CHIP_COUNT; i++)
            m_chipList[i].DrawChip(g);
    }


 

窗体鼠标按下事件
在窗体鼠标按下事件中,首先获取鼠标坐标Point(e.X, e.Y),判断是否在某拼块区域中,如果在记录用户选中的拼块序号。并通过e.Button判断用户是否右键单击,如果右键单击则将用户选中的拼块顺时针旋转90度,重画所有拼块。
private void Form1_MouseDown(object sender, MouseEventArgs e)
    {
        Point p = new Point(e.X, e.Y);
        for (int i = 0; i < CHIP_COUNT; i++)
            if (m_chipList[i].PtInChip(p) == true)
            {
                m_nCurrIndex = i;           //记录用户选中的拼块
                Drag_PictBox = true;        //移动标志赋值为真
                oldx = e.X;
                oldy = e.Y;
                break;  
            }            
        if (e.Button == MouseButtons.Right) //右键旋转
        {                
            m_chipList[m_nCurrIndex].Rotation2(); //旋转顺时针45度
            m_chipList[m_nCurrIndex].Rotation2(); //旋转顺时针45度
            Draw_AllChip();//画出所有拼块
        }
     }

窗体鼠标移动事件
在窗体鼠标移动中,首先获取鼠标坐标Point(e.X, e.Y),显示在窗体上,然后计算偏移量传给拼块类Cchip.Move2方法,改变用户选中拼块m_nCurrIndex的各点坐标,重画所有拼块。
private void Form1_MouseMove(object sender, MouseEventArgs e)
    {
        Point p = new Point(e.X, e.Y);
        label1.Text = p.ToString();
        if (Drag_PictBox == true)
        {
            Cursor.Current = Cursors.Hand;
            m_chipList[m_nCurrIndex].Move2(e.X - oldx, e.Y - oldy); //移动
            Draw_AllChip();                //画出所有拼块
        }        
        oldx = e.X;
        oldy = e.Y;
    }
窗体鼠标松开事件
在窗体鼠标松开事件中,对用户移动的m_nCurrIndex拼块进行位置校正,保证移动到适当的方格位置处。并判断游戏是否成功。
private void Form1_MouseUp(object sender, MouseEventArgs e)
    {
        Drag_PictBox = false;
        //对用户选中的m_nCurrIndex拼块坐标进行修正,放置到正确位置
        m_chipList[m_nCurrIndex].Verity(CHIP_WIDTH);            
        Draw_AllChip();                //画出所有拼块
        if(Win()) MessageBox.Show("成功完成此关")  ;   //判断是否成功
    }
窗体的鼠标双击事件
在窗体的鼠标双击事件中,对相应拼块进行水平翻转。
private void Form1_MouseDoubleClick(object sender, MouseEventArgs e)
    {
        Point p = new Point(e.X, e.Y);
        for (int i = 0; i < CHIP_COUNT; i++)
            if (m_chipList[i].PtInChip(p) == true)
            {
                m_nCurrIndex = i;           //记录用户选中的拼块
                Drag_PictBox = true;         
                oldx = e.X;
                oldy = e.Y;
                break;
            }
        m_chipList[m_nCurrIndex].ReverseTurn();  水平反转
        Draw_AllChip();//画出所有拼块
    }
窗体重绘事件
在窗体重绘事件中,绘制棋盘和本关已固定的绿色方块。
    private void Form1_Paint(object sender, PaintEventArgs e)
    {
        Graphics gp = e.Graphics;
        SolidBrush myBrush = new SolidBrush(Color.Green);
        for (int i = 0; i < 6; i++)	//绘制本关已固定的绿色方块
            for (int j = 0; j < 6; j++) {
                if(OrgMap[i,j]==0)
                    gp.FillRectangle(myBrush, i * CHIP_WIDTH, 
                                    j * CHIP_WIDTH, CHIP_WIDTH, CHIP_WIDTH);
            }
        Pen p = new Pen(Color.Brown, 1);
        for (int i = 1; i < 7; i++) 				//绘制棋盘
            for (int j = 1; j < 7; j++) {
                gp.DrawLine(p, 1, j * CHIP_WIDTH, CHIP_WIDTH*6, j * CHIP_WIDTH);
                gp.DrawLine(p, i * CHIP_WIDTH, 1, i * CHIP_WIDTH, CHIP_WIDTH * 6);                     
            }
    } 





 

 


 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值