目錄
@
前言
這個賽狗日,是給個框架讓自己寫。感覺難度有點大,語言和控件不熟。讀他的說明和程序結構讀了兩三遍。最後才明白要幹啥。寫是寫出來了,但是我感覺還可以優化,優化在最後說明,線來看下效果
效果展示
步驟
熟讀任務說明
寫一個程序第一步就是要明白,它要幹啥,他怎麼實現。而不是一遍寫一遍想,寫寫改改,這樣麻煩不說而且還很撈,我們這種新手一般都沒有哪個本事一寫就過。這本書很好,給了程序的結構和邏輯,只要自己想方法實現 就行了。所以要先讀清楚任務說明,以免越寫越亂。
搭界面
書上給的網站應該換地址了,進去不是的,是他們公司官網。無奈網上找不到合適的圖片。只有自己畫了,用PPT簡單畫一個。
👇👇👇👇
然後就按照書上的界面搭建一個。👇👇👇👇
圖片網上好找。拍好佈局,設置好控件的屬性就OK,不想調圖片尺寸,我就用的 背景圖片填充,然後背景圖片設爲自適應。
開始代碼
按照書上的結構代碼分爲一下四個部分:
- Form:界面控件的邏輯控制。
- Greyhound:賽狗的對象,每個對象控制一條狗。
- Guy:賭徒對象,一個賭徒有一個對應的一個對象。
- Bet:賭局對象(個人理解),控制一個賭徒本局的下注情況。
From.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Day_at_the_Races
{
public partial class Form1 : Form
{
Greyhound[] greyhounds = new Greyhound[4];//聲明一個數組管理Grehound對象
Guy[] guys = new Guy[3];//聲明一個數組管理Guy對象
Random random = new Random();//創建一個Random對象。
public Form1()
{
InitializeComponent();
initDog();//初始化狗
initGuy();//初始化賭徒和對應的賭注。
}
/// <summary>
/// 初始化比賽的狗:綁定狗的圖片對象,賽道的長度,起點位置,隨機Random對象;同時,初始化狗的位置。
/// </summary>
public void initDog()
{
//創建對象,同時對屬性賦值。
greyhounds[0] = new Greyhound()
{
MypictureBox = dog1,
StartingPosition = raceRoad.Left,
RacetrackLength = raceRoad.Width,
randomizer = random
};
//重置狗的位置
greyhounds[0].TakeStaringPosition();
//Console.WriteLine("0號狗位置"+ greyhounds[0].StartingPosition);
//Console.WriteLine("0號狗圖片左邊位置" + greyhounds[0].MypictureBox.Left);
greyhounds[1] = new Greyhound()
{
MypictureBox = dog2,
StartingPosition = raceRoad.Left,
RacetrackLength = raceRoad.Width,
randomizer = random
};
greyhounds[1].TakeStaringPosition();
//0Console.WriteLine("1號狗位置" + greyhounds[1].StartingPosition);
//Console.WriteLine("1號狗圖片左邊位置" + greyhounds[1].MypictureBox.Left);
greyhounds[2] = new Greyhound()
{
MypictureBox = dog3,
StartingPosition = raceRoad.Left,
RacetrackLength = raceRoad.Width,
randomizer = random
};
greyhounds[2].TakeStaringPosition();
//Console.WriteLine("2號狗位置" + greyhounds[2].StartingPosition);
//Console.WriteLine("2號狗圖片左邊位置" + greyhounds[2].MypictureBox.Left);
greyhounds[3] = new Greyhound()
{
MypictureBox = dog4,
StartingPosition = raceRoad.Left,
RacetrackLength = raceRoad.Width,
randomizer = random
};
greyhounds[3].TakeStaringPosition();
//Console.WriteLine("3號狗位置" + greyhounds[3].StartingPosition);
//Console.WriteLine("3號狗圖片左邊位置" + greyhounds[3].MypictureBox.Left);
}
/// <summary>
/// 初始化賭徒,姓名 ,賭資,radio button,和label;最後創建每個的賭注(bet)對象;
/// </summary>
public void initGuy()
{
guys[0] = new Guy()
{
Name = "盧本偉",
Cash = 50,
MyRadio = radiolbw,
Mylabel = lablbwInfo
};
guys[1] = new Guy()
{
Name = "孫笑川",
Cash = 60,
MyRadio = radsxc,
Mylabel = labsxcInfo
};
guys[2] = new Guy()
{
Name = "大司馬",
Cash = 20,
MyRadio = raddsm,
Mylabel = labdsmInfo
};
initbet();
}
/// <summary>
/// 初始化bet對象,默認以0未初始化。
/// </summary>
public void initbet()
{
guys[0].UpdateLabel();
guys[0].PlaceBet(0, 0);
guys[1].UpdateLabel();
guys[1].PlaceBet(0, 0);
guys[2].UpdateLabel();
guys[2].PlaceBet(0, 0);
}
/// <summary>
/// timer調用的方法,每次調用都進行四條狗的Run函數,檢測到有true返回就開始進行Guy的Collect(),結算。
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void timer1_Tick(object sender, EventArgs e)
{
for (int i = 0; i < 4; i++)
{
if (greyhounds[i].Run())
{
timer1.Stop();
for (int j = 0; j < 3; j++)
{
guys[j].Collect(i);
}
//顯示提示信息
MessageBox.Show("本局" + i + "號狗取得勝利!");
//釋放每個狗的對象
for (int k = 0; k < 4; k++)
{
greyhounds[k] = null;
}
//初始化狗
initDog();
//初始化賭注,賭注對象已經在Collect()裏面刪除。
initbet();
//將面板組件激活,進行下次賭局。
groupBox1.Enabled = true;
//重置單選框
radiolbw.Checked = false;
radsxc.Checked = false;
raddsm.Checked = false;
money.Text = "0";//下注輸入框重置
dog.Text = "0";
break;//一定要加上,結束循環,如果不加初始化後還會調用greyhounds[i].Run(),就會不在原點。
}
}
}
/// <summary>
/// 點擊後進行最下方Label跟新和兩個輸入框的刷新。
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void radiolbw_Click(object sender, EventArgs e)
{
labguy.Text = "盧本偉壓注";
money.Text = "0";
dog.Text = "0";
}
private void raddsm_Click(object sender, EventArgs e)
{
labguy.Text = "大司馬壓注";
money.Text = "0";
dog.Text = "0";
}
private void radsxc_Click(object sender, EventArgs e)
{
labguy.Text = "孫笑川壓注";
money.Text = "0";
dog.Text = "0";
}
/// <summary>
/// 比賽開始按鈕,激活計時器。
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btn_start_Click(object sender, EventArgs e)
{
//驗證本局是否有人下注
if (guys[0].Mybet.Amount == 0 && guys[1].Mybet.Amount == 0 && guys[2].Mybet.Amount == 0)
{
MessageBox.Show("暫無選手下注!");
}
else
{
groupBox1.Enabled = false;//禁用下注面板
timer1.Interval = 100;//設置計時器的時間間隔爲100ms。
timer1.Start();//開始計時器
}
}
/// <summary>
/// 確認下注按鈕,跟新Guy的bet對象,跟新label
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btn_ok_Click(object sender, EventArgs e)
{
//如果此時選中的是盧本偉的單選按鈕。
if (radiolbw.Checked)
{
if (Int32.Parse(money.Text) < 5)
{
MessageBox.Show("下注金額至少爲5元!");
}
else if (Int32.Parse(dog.Text) < 0 || Int32.Parse(dog.Text) > 3)
{
MessageBox.Show("沒有" + Int32.Parse(dog.Text) + "號狗!");
}
else
{
guys[0].PlaceBet(Int32.Parse(money.Text), Int32.Parse(dog.Text));//更新bet對象
guys[0].UpdateLabel();//更新label
}
}
//如果此時選中的是孫笑川的單選按鈕。
if (radsxc.Checked)
{
if (Int32.Parse(money.Text) < 5)
{
MessageBox.Show("下注金額至少爲5元!");
}
else if (Int32.Parse(dog.Text) < 0 || Int32.Parse(dog.Text) > 3)
{
MessageBox.Show("沒有" + Int32.Parse(dog.Text) + "號狗!");
}
else
{
guys[1].PlaceBet(Int32.Parse(money.Text), Int32.Parse(dog.Text));
guys[1].UpdateLabel();
}
}
//如果此時選中的是大司馬的單選按鈕。
if (raddsm.Checked)
{
if (Int32.Parse(money.Text) < 5)
{
MessageBox.Show("下注金額至少爲5元!");
}
else if (Int32.Parse(dog.Text) < 0 || Int32.Parse(dog.Text) > 3)
{
MessageBox.Show("沒有" + Int32.Parse(dog.Text) + "號狗!");
}
else
{
guys[2].PlaceBet(Int32.Parse(money.Text), Int32.Parse(dog.Text));
guys[2].UpdateLabel();
}
}
}
}
}
Greyhound.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Day_at_the_Races
{
public class Greyhound
{
public int StartingPosition;//起點位置,我設置的是以賽道的左邊爲起點
public int RacetrackLength;//賽道長度,就是賽道圖片的with寬度,由於我算終點的寬度,我量的是100個像素,所以計算的時候要減去95(營造衝線假象)
public PictureBox MypictureBox = null;//狗的圖片
public int Location = 0;//狗跑出的距離,再次距離上進行位置疊加
public Random randomizer;
public bool Run()
{
bool isWin = false;//輸贏的標誌變量
Location += randomizer.Next(0,20);//隨機對象,隨機移動0-20個像素。
MypictureBox.Left = StartingPosition + Location;//位置更新
if(MypictureBox.Left>= (RacetrackLength-95) - MypictureBox.Width)//判斷是否衝線,95在上方屬性有解釋。
{
isWin = true;
}
return isWin;
}
//初始狗的位置
public void TakeStaringPosition()
{
this.MypictureBox.Left = StartingPosition;
this.Location = 0;
}
}
}
Guy.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Day_at_the_Races
{
public class Guy
{
public string Name;//姓名
public Bet Mybet;//賭注對象
public int Cash;//賭資
public RadioButton MyRadio;//radio button對象
public Label Mylabel;//label對象
//跟新radio button對象
public void UpdateLabel()
{
MyRadio.Text = Name + "有" + Cash + "元";
}
//清除賭局對象
public void ClearBet()
{
Mybet = null;
}
//創建賭局對象
public bool PlaceBet(int BetAmount,int DogTOWin)
{
if (Mybet != null)//爲空就初始化
{
//if (BetAmount < 5)
//{
// MessageBox.Show("下注金額至少爲5元!"); //已經在開始按鈕處判斷
// return false;
//}
if(BetAmount > Cash){
MessageBox.Show(Name+"的金額不足"+BetAmount+"!");
return false;
}
else
{
//進行行賭局對象屬性的更新
Console.WriteLine("下注成功!");
Mybet.Amount = BetAmount;
Mybet.dog = DogTOWin;
Mylabel.Text = Mybet.GetDiscreaption();
return true;
}
}
else
{
//初始化
Mybet = new Bet() { Amount = BetAmount, Better = this, dog = DogTOWin };
Mylabel.Text = Mybet.GetDiscreaption();
return false;
}
}
//進行賭局結算,更新資產,radio button的文字,刪除上局的bet對象。
public void Collect(int Winner)
{
Cash += Mybet.Payout(Winner);
ClearBet();
MyRadio.Text= Name + "有" + Cash + "元";
}
}
}
Bet.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Day_at_the_Races
{
public class Bet
{
public int Amount;//下注金額
public int dog;//壓得狗
public Guy Better;//賭徒
//賭徒在本局一個描述
public string GetDiscreaption()
{
string dis = "";
if (Amount == 0)
{
dis = Better.Name + "沒有下注";
}
else
{
dis = Better.Name + "下注" + Amount + "元,賭" + dog + "號狗會贏";
}
return dis;
}
//返回本局的輸贏金額
public int Payout(int Winner)
{
if (dog == Winner)
{
return Amount;
}
else
{
return -Amount;
}
}
}
}
寫在後面的話
本次遇見的一些問題
論壇給了這麼好的交流平臺,當然要交流下自己的問題。作爲初學者更應該交流。
- 書要仔細,最開始遺漏了一個bet按鈕,書上也不顯眼,糾結了好久Raadiobutton功能寫不好,總不滿意。最後一看下注那句話裏面藏個按鈕。。。這樣就好辦了。
- 最後判斷完勝利者,重新初始化狗的位置時總有偏移。👇👇
然後我輸出圖片的位置查看一下初始化時圖片的位置發現沒毛病。👇
然後我以爲是電腦有問題了,直到一次0號狗跑了第一和一次3號狗跑了第一,一對比才想到,沒有控制好結束的邏輯,結束後不適用break初始化後還會調用後面狗的Run(),從而發生偏移。
關於優化
可以設定狗的特性
可以參照遊戲設定狗的一些特性,讓比賽隨機,但又可以預料。
去掉Bet類
我覺得哪個Bet類顯得有點礙事,讓程序有點複雜。可以直接合併到Guy類裏面。==這個只是個人見解,如不正確還望大神指點==。
自己的不足
我寫完後自己有看了遍代碼,雖然完成了書上的功能,但是覺得自己也有寫偏的。比如:
- Bet類默認都創建,我覺得書上得意思是,這局賭了纔會創建一個Bet對象,而我是默認都創建了。同時還增加了多餘的判斷條件。
關於label的跟新我都是依賴Bet類裏面的GetDiscreaption()來獲得文本,總體我覺得不好。
可能還有許多不足的地方,希望有大佬看出來能夠交流下,我以後避免再犯這樣的錯誤。❤❤❤🙇♂️
2020-2-24