您好,登錄后才能下訂單哦!
這篇文章給大家介紹使用C#怎么制作一個俄羅斯方塊小游戲,內容非常詳細,感興趣的小伙伴們可以參考借鑒,希望對大家能有所幫助。
1.調色板代碼
namespace Tetris { class Palette { private int _width = 15;//畫板寬度 private int _height = 25;//畫板高度 private Color[,] coorArr;//固定磚塊數組 private Color disapperColor;//背景色 private Graphics gpPalette;//磚塊活動畫板 private Graphics gpReady;//下一個磚塊樣式畫板 private BlockGroup bGroup;//磚塊生產機制 private Block runBlock;//正在活動的磚塊 private Block readyBlock;//下一個磚塊 private int rectPix;//單元格像 public delegate void IniCountHandle(int _count,int state);//分數變量 public event IniCountHandle CountEvent; public static int _Count = 0; static int mark = 100;//靜態變量衡量過關的標準 public static int state = 1; private System.Timers.Timer timerBlock;//定時器 private static int timeSpan = 800;//定時器的時間間隔 public Palette(int x, int y, int pix, Color dColor, Graphics gp, Graphics gr)//構造函數 { _width = x; _height = y; coorArr = new Color[_width, _height]; disapperColor = dColor; gpPalette = gp; gpReady = gr; rectPix = pix; } public void Start()//游戲開始 { state = 1; _Count = 0; bGroup = new BlockGroup(); runBlock = bGroup.GetABlock(); runBlock.XPos = _width / 2; int y = 0; for (int i = 0; i < runBlock.Length ; i++)//垂直位置 { if (runBlock[i].Y > y) { y = runBlock[i].Y; } } runBlock.YPos = y; gpPalette.Clear(disapperColor);//清空畫板 runBlock.Paint(gpPalette);//畫運行磚塊 Thread.Sleep(20); readyBlock = bGroup.GetABlock(); readyBlock.XPos = 2; readyBlock.YPos = 2; gpReady.Clear(disapperColor);//清空畫板 readyBlock.Paint(gpReady); //初始化并啟動定時器 timerBlock = new System.Timers.Timer(timeSpan); timerBlock.Elapsed += new System.Timers.ElapsedEventHandler(OnTimedEvent); timerBlock.AutoReset = true; timerBlock.Start(); } public void nextstate() { PaintBackground(gpPalette); timerBlock = new System.Timers.Timer(timeSpan); timerBlock.Elapsed += new System.Timers.ElapsedEventHandler(OnTimedEvent); timerBlock.AutoReset = true; timerBlock.Start(); } private void OnTimedEvent(object source, ElapsedEventArgs e) { CheckAndOverBlock(); Down(); } public bool Down()//磚塊下移 { int xPos = runBlock.XPos; int yPos = runBlock.YPos + 1; for (int i = 0; i < runBlock.Length; i++) { if (yPos - runBlock[i].Y > _height - 1)//如果超出下邊界則失敗 return false; if (!coorArr[xPos + runBlock[i].X, yPos - runBlock[i].Y].IsEmpty)//如果下邊有東西擋則失敗 return false; } runBlock.erase(gpPalette);//擦除原來位置磚塊 runBlock.YPos++; runBlock.Paint(gpPalette); return true; } public void Drop()//丟下磚塊 { timerBlock.Stop(); while (Down()) ; timerBlock.Start(); } public void MoveLeft()//向左移動 { int xPos = runBlock.XPos - 1; int yPos = runBlock.YPos; for (int i = 0; i < runBlock.Length; i++) { if (xPos + runBlock[i].X < 0) return; if (!coorArr[xPos + runBlock[i].X, yPos - runBlock[i].Y].IsEmpty)//如果左邊有東西擋則失敗 return; } runBlock.erase(gpPalette); runBlock.XPos--; runBlock.Paint(gpPalette); } public void MoveRight()//向右移動 { int xPos = runBlock.XPos + 1; int yPos = runBlock.YPos; for (int i = 0; i < runBlock.Length; i++) { if (xPos + runBlock[i].X > _width -1)//如果超出右邊界則失敗 return; if (!coorArr[xPos + runBlock[i].X, yPos - runBlock[i].Y].IsEmpty)//如果右邊有東西擋則失敗 return; } runBlock.erase(gpPalette); runBlock.XPos++; runBlock.Paint(gpPalette); } public void DeasilRotate()//順時針旋轉 { for (int i = 0; i < runBlock.Length; i++) { int x = runBlock.XPos + runBlock[i].Y; int y = runBlock.YPos + runBlock[i].X; if (x < 0 || x > _width - 1) return; if (y < 0 || y > _height - 1) return; if (!coorArr[x, y].IsEmpty) return; } runBlock.erase(gpPalette); runBlock.DeasilRotate(); runBlock.Paint(gpPalette); } public void ContraRotate()//逆時針旋轉 { for (int i = 0; i < runBlock.Length; i++) { int x = runBlock.XPos - runBlock[i].Y; int y = runBlock.YPos - runBlock[i].X; if (x < 0 || x > _width - 1) return; if (y < 0 || y > _height - 1) return; if (!coorArr[x, y].IsEmpty) return; } runBlock.erase(gpPalette); runBlock.ContraRotate(); runBlock.Paint(gpPalette); } private void PaintBackground(Graphics gp)//重畫畫板背景 { gp.Clear(Color.Black);//清空畫板 for (int i = 0; i < _height; i++) { for (int j = 0; j < _width; j++) { if (!coorArr[j, i].IsEmpty) { SolidBrush sb = new SolidBrush(coorArr[j, i]); gp.FillRectangle(sb, j * rectPix + 1, i * rectPix + 1, rectPix - 2, rectPix - 2); } } } } public void PaintPalette(Graphics gp)//重畫整個畫板 { PaintBackground(gp);//先畫背景 if (runBlock != null)//再畫活動的磚塊 { runBlock.Paint(gp); } } public void PaintReady(Graphics gp)//重畫下一個磚塊 { if (readyBlock != null) { readyBlock.Paint(gp); } } public void CheckAndOverBlock()//檢查磚塊是否到底 { bool over = false; for (int i = 0; i < runBlock.Length; i++) { int x = runBlock.XPos + runBlock[i].X; int y = runBlock.YPos - runBlock[i].Y; if (y == _height - 1) { over = true; break; } if (!coorArr[x, y + 1].IsEmpty)//如果下面有磚塊,則當前磚塊結束 { over = true; break; } } if (over)//如果當前磚塊已經結束 { for (int i = 0; i < runBlock.Length; i++)//把當前磚塊歸入coordinatearr { coorArr[runBlock.XPos + runBlock[i].X, runBlock.YPos - runBlock[i].Y] = runBlock.BlockColor; } //檢查是否有滿行現象,如果有,則刪除 CheckAndDelFullRow(); //產生新的磚塊 runBlock = readyBlock;//新的磚塊為準備好的磚塊 runBlock.XPos = _width / 2; int y = 0; for (int i = 0; i < runBlock.Length; i++)//垂直位置 { if (runBlock[i].Y > y) { y = runBlock[i].Y; } } runBlock.YPos = y; //檢查新產生的磚塊所占用的地方是否已經有磚塊,如果有,則游戲結束 for (int i = 0; i < runBlock.Length; i++) { if (!coorArr[runBlock.XPos + runBlock[i].X, runBlock.YPos - runBlock[i].Y].IsEmpty) { //游戲結束 StringFormat drawFormat = new StringFormat(); drawFormat.Alignment = StringAlignment.Center; gpPalette.DrawString("GAME OVER"+"\r\n"+"得分:" + _Count.ToString()+"\r\n等級:"+state .ToString (), new Font("Arial Black", 25f), new SolidBrush(Color.Yellow ), new RectangleF(0, _height * rectPix / 2 - 100, _width * rectPix, 150), drawFormat); timerBlock.Stop(); return; } } runBlock.Paint(gpPalette); //獲取新的準備磚塊 readyBlock = bGroup.GetABlock(); readyBlock.XPos = 2; readyBlock.YPos = 2; gpReady.Clear(Color.Black); readyBlock.Paint(gpReady); } } private void CheckAndDelFullRow()//檢查并刪除滿行 { //找出當前磚塊所在行范圍 int lowRow = runBlock.YPos - runBlock[0].Y;//lowRow代表當前磚塊的Y軸的最小值 int highRow = lowRow;//highRow代表當前磚塊的y軸的最大值 for (int i = 0; i < runBlock.Length;i++ )//找出當前磚塊所占行的范圍,放入low,high變量內 { int y = runBlock.YPos - runBlock[i].Y; if (y < lowRow) { lowRow = y; } if (y > highRow) { highRow = y; } } int count=0; bool repaint = false;//判斷是否重畫 for (int i = lowRow; i <= highRow; i++)//檢查是否滿行 { bool rowFull = true; for (int j = 0; j < _width; j++) { if (coorArr[j, i].IsEmpty)//如果有一個單元格為空,說明這一行不可能為滿行 { rowFull = false; break; } } if (rowFull)//如果滿行,則刪除這一行 { count ++; repaint = true;//如果刪除,則需重畫 for (int k = i; k > 0; k--) { for (int j = 0; j < _width; j++) { coorArr[j, k] = coorArr[j, k - 1]; } } for (int j = 0; j < _width; j++)//清空第0行 { coorArr[j, 0] = Color.Empty; } } } //計算每滿幾行加的分值 if (count == 1) { _Count += 10; CountEvent(_Count,state); } if (count == 2) { _Count += 30; CountEvent(_Count,state); } if (count == 3) { _Count += 60; CountEvent(_Count,state ); } if (count >= 4) { _Count += 80; CountEvent(_Count,state); } if (repaint)//重畫 { PaintBackground(gpPalette); } if (_Count >= 1000)//如果通關初始化為原來的值 { StringFormat drawFormat = new StringFormat(); drawFormat.Alignment = StringAlignment.Center; gpPalette.DrawString("O(∩_∩)O"+"\r\n"+"***通關***"+"\r\n"+"按“開始”按鈕\r\n王者歸來", new Font("Arial Black", 20f), new SolidBrush(Color.Red), new RectangleF(0, _height * rectPix / 2 - 100, _width * rectPix, 120), drawFormat); timeSpan = 800; state = 1; _Count = 0; timerBlock.Close(); } if (_Count >= mark) { mark += 100; timeSpan -= 70; state++; CountEvent(_Count ,state); StringFormat drawFormat = new StringFormat(); drawFormat.Alignment = StringAlignment.Center; gpPalette.DrawString("\tO(∩_∩)O~\r\n***恭喜過關***\r\n按“下一關”按鈕\r\n開始新的遠征", new Font("Arial Black", 20f), new SolidBrush(Color.DodgerBlue ), new RectangleF(0, _height * rectPix / 2 - 80, _width * rectPix, 120), drawFormat); timerBlock.Stop();//關閉計時器 } } public void Pause()//暫停 { if (timerBlock.Enabled == true) { timerBlock.Enabled = false; StringFormat drawFormat = new StringFormat(); drawFormat.Alignment = StringAlignment.Center; gpPalette.DrawString("暫停" + "\r\n" + "得分:" + _Count.ToString(), new Font("Arial Black", 25f), new SolidBrush(Color.Aqua), new RectangleF(0, _height * rectPix / 2 - 100, _width * rectPix, 100), drawFormat); } } public void EndPause()//結束暫停 { if (timerBlock.Enabled == false) { timerBlock.Enabled = true; PaintBackground(gpPalette); } } public void Close()//關閉 { timerBlock.Close(); gpPalette.Dispose();//釋放畫布 gpReady.Dispose(); } } }
2.保存信息數組代碼
namespace Tetris { class InfoArr { private ArrayList info = new ArrayList();//存放多個BlockInfo累得的數組 private int _length = 0;//存放Arraylist的長度,以供訪問 public int Length { get { return _length; } } public BlockInfo this[int index]//索引器,根據下標,返回一個blockinfo的值 { get { return (BlockInfo)info[index]; } } public string this[string id]//索引器,根據一個字符串的id值下標,給相應id的顏色賦值 { set { if (value == "") { return; } for (int i = 0; i < info.Count; i++) { if (((BlockInfo)info[i]).GetIdStr() == id) { try { ((BlockInfo)info[i]).BColor = Color.FromArgb(Convert.ToInt32(value)); } catch (System.FormatException) { MessageBox.Show("顏色信息錯誤!請刪除BlockSet.xml文件,并重新啟動程序,很抱歉給您帶來麻煩", "錯誤信息", MessageBoxButtons.OK, MessageBoxIcon.Error); } } } } } public BitArray StrToBit(string id)//把字符串轉換為bitArray { if (id.Length != 25) { throw new System.FormatException("磚塊樣式信息不合法!請刪除BlockSet.xml文件,并重新啟動程序"); } BitArray ba = new BitArray(25); for (int i = 0; i < 25; i++) { ba[i] = (id[i] == '0') ? false : true; } return ba; } public void Add(BitArray id, Color bColor)//添加一個磚塊信息 { if (id.Length != 25) { throw new System.FormatException("磚塊樣式信息不合法!請刪除blockset.xml文件,并重新啟動程序"); } info.Add(new BlockInfo(id, bColor));//給動態數組info添加一個磚塊信息 _length++;//長度加一 } public void Add(string id, string bColor) { Color temp; if (!(bColor == "")) { temp = Color.FromArgb(Convert.ToInt32(bColor));//把字符串轉換為顏色類 } else { temp = Color.Empty; } info.Add(new BlockInfo(StrToBit(id), temp));//把字符串轉換為bitarray類 _length++; } } }
3.方塊信息代碼
namespace Tetris { class BlockInfo { private BitArray _id;//存放磚塊樣式 private Color _bColor;//存放顏色信息 public BlockInfo(BitArray id, Color bColor)//構造函數,給似有函數變量賦值 { _id = id; _bColor = bColor; } public BitArray ID { get { return _id; } set { _id = value; } } public Color BColor { get { return _bColor; } set { _bColor = value; } } public string GetIdStr() { StringBuilder s = new StringBuilder(25); foreach (bool b in _id) { s.Append(b ? "1" : "0"); } return s.ToString(); } public string GetColorStr() { return Convert.ToString(_bColor.ToArgb()); } } }
4.方塊組代碼
namespace Tetris { class BlockGroup { private InfoArr info;//存放所有磚塊樣式信息 private Color disapperColor;//背景色 private int rectPix;//單元格像素 public BlockGroup()//構造函數 { Config config = new Config(); config.LoadFromXmlFile(); info = new InfoArr(); info = config.Info; disapperColor = config.BackColor; rectPix = config.RectPix; } public Block GetABlock()//從磚塊組中隨機抽取一個磚塊樣式并返回 { Random rd = new Random();//聲明一個產生隨機數的類 int keyOrder = rd.Next(0, info.Length);//產生一個隨機數 BitArray ba = info[keyOrder].ID;//把抽取出的磚塊樣式賦給BitArray類對象ba int struNum = 0;//確定這個磚塊樣式中被填充方塊的個數 foreach (bool b in ba)//需要確定point數組的長度 { if (b) { struNum++; } } Point[] structArr = new Point[struNum];//新建一個point數組,并確定其長度,以創建新的block int k = 0; for (int j = 0; j < ba.Length; j++)//用循環給point數組structarr賦坐標值 { if (ba[j]) { structArr[k].X = j / 5 - 2; structArr[k].Y = 2 - j % 5; k++; } } return new Block(structArr, info[keyOrder].BColor, disapperColor, rectPix);//創建一個新磚塊并返回 } }
5.方塊的基本屬性代碼
namespace Tetris { class Block { protected Point[] structArr;//存放磚塊組成信息的坐標數組 protected int _xPos;//磚塊中心點所在的X坐標 protected int _yPos;//磚塊中心點所在的y坐標 protected Color _blockColor;//磚塊顏色 protected Color disapperColor;//擦除顏色 protected int rectPix;//每單元格像素 public Block()//默認構造函數,聲明此構造函數是為了子類能創建 { } public Block(Point[] sa, Color bColor, Color dColor, int pix) { //重載構造函數,給成員變量賦值 _blockColor = bColor; disapperColor = dColor; rectPix = pix; structArr = sa; } public Point this[int index]//索引器,根據索引訪問磚塊里的小方塊坐標 { get { return structArr[index]; } } public int Length//屬性,表示structArr的長度 { get { return structArr.Length; } } #region 成員變量相應的屬性 public int XPos { get { return _xPos; } set { _xPos = value; } } public int YPos { get { return _yPos; } set { _yPos = value; } } public Color BlockColor { get { return _blockColor; } } #endregion public void DeasilRotate()//順時針旋轉 { int temp; for (int i = 0; i < structArr.Length; i++) { temp = structArr[i].X; structArr[i].X = structArr[i].Y; structArr[i].Y = -temp; } } public void ContraRotate()//逆時針旋轉 { int temp; for (int i = 0; i < structArr.Length; i++) { temp = structArr[i].X; structArr[i].X = -structArr[i].Y; structArr[i].Y = temp; } } private Rectangle PointToRect(Point p)//把坐標點轉化為畫布的坐標值 { return new Rectangle((_xPos + p.X) * rectPix + 1, (_yPos - p.Y) * rectPix + 1, rectPix - 2, rectPix - 2); } public virtual void Paint(Graphics gp)//在指定畫板下繪制磚塊 { SolidBrush sb = new SolidBrush(_blockColor ); foreach (Point p in structArr) { lock (gp) { gp.FillRectangle(sb, PointToRect(p)); } } } public void erase(Graphics gp)//擦除矩形 { SolidBrush sb = new SolidBrush(disapperColor); foreach (Point p in structArr) { lock (gp) { gp.FillRectangle(sb, PointToRect(p)); } } } } }
6.俄羅斯方塊窗體代碼
namespace Tetris { public partial class FrmTetris : Form { public FrmTetris() { InitializeComponent(); CheckForIllegalCrossThreadCalls = false; } private Palette p; private Keys downKey; private Keys dropKey; private Keys moveLeftKey; private Keys moveRightKey; private Keys deasilRotateKey; private Keys contraRotateKey; private int paletteWidth; private int paletteHeight; private Color paletteColor; private int rectPix; private void btnStart_Click(object sender, EventArgs e) { lblState.Text = "等級:1"; lblcount.Text = "得分:0"; if (p != null) { p.Close(); } p = new Palette(paletteWidth, paletteHeight, rectPix, paletteColor, Graphics.FromHwnd(pbRun.Handle), Graphics.FromHwnd(lblReady.Handle)); p.CountEvent += new Palette.IniCountHandle(p_CountEvent); p.Start(); } void p_CountEvent(int _count,int state) { lblcount.Text = "得分:"+_count.ToString(); lblState.Text = "等級:" + state.ToString(); } private void pbRun_Paint(object sender, PaintEventArgs e) { if (p != null) { p.PaintPalette(e.Graphics); } } private void lblReady_Paint(object sender, PaintEventArgs e) { if (p != null) { p.PaintReady(e.Graphics); } } private void FrmTetris_Load(object sender, EventArgs e) { //讀取xml文件中的參數配置信息,并依次賦給似有成員變量 Config config = new Config(); config.LoadFromXmlFile(); downKey = config.DownKey; dropKey = config.DropKey; moveLeftKey = config.MoveLeftKey; moveRightKey = config.MoveRightKey; deasilRotateKey = config.DeasilRotateKey; contraRotateKey = config.ContraRotateKey; paletteWidth = config.CoorWidth; paletteHeight = config.CoorHeight; paletteColor = config.BackColor; rectPix = config.RectPix; //根據畫板的長度和寬度信息動態改變窗體及畫板的規格 this.Width = paletteWidth * rectPix + 215; this.Height = paletteHeight * rectPix + 38; pbRun.Width = paletteWidth * rectPix; pbRun.Height = paletteHeight * rectPix; } private void FrmTetris_KeyDown(object sender, KeyEventArgs e) { if (e.KeyValue == 32)//屏蔽回車鍵 { e.Handled = true; } if (e.KeyCode == downKey)//下降 { p.Down(); } else if (e.KeyCode == dropKey) { p.Drop(); } else if (e.KeyCode == moveLeftKey) { p.MoveLeft(); } else if (e.KeyCode == moveRightKey) { p.MoveRight(); } else if (e.KeyCode == deasilRotateKey) { p.DeasilRotate(); } else if (e.KeyCode == contraRotateKey) { p.ContraRotate(); } } private void btnPause_Click(object sender, EventArgs e) { if (p == null) { return; } if (btnPause.Text == "暫停") { p.Pause(); btnPause.Text = "繼續"; } else { p.EndPause(); btnPause.Text = "暫停"; } } private void btnConfig_Click(object sender, EventArgs e) { if (btnPause.Text == "暫停") { btnPause.PerformClick(); } using (Frmconfig frmconfig= new Frmconfig()) { frmconfig.ShowDialog(); } } private void FrmTetris_FormClosing(object sender, FormClosingEventArgs e) { if (p !=null ) { p.Close (); } } private void button5_Click(object sender, EventArgs e) { p.Down(); } private void button1_Click(object sender, EventArgs e) { p.MoveLeft(); } private void button2_Click(object sender, EventArgs e) { p.MoveRight(); } private void button3_Click(object sender, EventArgs e) { p.DeasilRotate(); } private void button4_Click(object sender, EventArgs e) { p.ContraRotate(); } private void button6_Click(object sender, EventArgs e) { p.Drop(); } private void button7_Click(object sender, EventArgs e) { OpenFileDialog ofDialog = new OpenFileDialog(); ofDialog.AddExtension = true; ofDialog.CheckFileExists = true; ofDialog.CheckPathExists = true; //the next sentence must be in single line ofDialog.Filter = "MP3文件(*.mp3)|*.mp3|Audio文件(*.avi)|*.avi|VCD文件(*.dat)|*.dat|WAV文件(*.wav)|*.wav|所有文件 (*.*)|*.*"; ofDialog.DefaultExt = "*.mp3"; if (ofDialog.ShowDialog() == DialogResult.OK) { this.axWindowsMediaPlayer1.URL = ofDialog.FileName; } } private void timer1_Tick(object sender, EventArgs e) { DateTime dt = DateTime.Now; //當前時間的實例; lbltime.Text = dt.ToString(); //轉為string類型 把值交給lbltime的Text屬性; } private void button8_Click(object sender, EventArgs e) { p.CountEvent += new Palette.IniCountHandle(p_CountEvent); p.nextstate(); } } }
7.游戲設置窗體代碼
namespace Tetris { public partial class Frmconfig : Form { public Frmconfig() { InitializeComponent(); } private bool[,] struArr = new bool[5, 5]; private Color blockColor = Color.Red; private void lblMode_Paint(object sender, PaintEventArgs e) { Graphics gp = e.Graphics; gp.Clear(Color.Black); Pen p = new Pen(Color.White); for (int i = 31; i < 155; i = i + 31) gp.DrawLine(p, 1, i, 155, i); for (int i = 31; i < 155; i = i + 31) gp.DrawLine(p, i, 1, i, 155); //填充顏色 SolidBrush s = new SolidBrush(blockColor); for (int x = 0; x < 5; x++) { for (int y = 0; y < 5; y++) { if (struArr[x, y]) { gp.FillRectangle(s, 31 * x + 1, 31 * y + 1, 30, 30); } } } } private void lblMode_MouseClick(object sender, MouseEventArgs e) { if (e.Button != MouseButtons.Left) return; int xPos, yPos; xPos = e.X / 31; yPos = e.Y / 31; struArr[xPos, yPos] = !struArr[xPos, yPos]; bool b = struArr[xPos, yPos]; Graphics gp = lblMode.CreateGraphics(); SolidBrush s = new SolidBrush(b ? blockColor : Color.Black); gp.FillRectangle(s, 31 * xPos + 1, 31 * yPos + 1, 30, 30); gp.Dispose(); } } }
關于使用C#怎么制作一個俄羅斯方塊小游戲就分享到這里了,希望以上內容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。