🍺 倒水解密
© Conmajia 2012
本文所有源代码和 VisualStudio2010
规则是这样的
有 N 个容量不同的瓶子
该游戏虽然简单
说到这里
下面是山寨游戏的屏幕录像
虽然界面有点简陋
游戏操作方式如下
- 在瓶子上双击右键可以把瓶子灌满水
- 双击左键可以把瓶子里的水倒掉
- 将一个瓶子拖动到另一个瓶子上可以把水倒过去
下面是游戏的模型结构
Bottle 类
这里我用画图鼠绘了一个丑陋的瓶子

1 public class Bottle : Element, IVisible 2 { 3 const int SIZE_FACTOR = 10; 4 5 #region Variables 6 int content = 0; 7 int capacity = 0; 8 Size size = Size.Empty; 9 Rectangle bounds = Rectangle.Empty; 10 11 Bitmap canvas; 12 Graphics painter; 13 bool dirty = true; 14 15 #endregion 16 17 #region Properties 18 public int FreeSpace 19 { 20 get { return capacity - content; } 21 } 22 23 public int Content 24 { 25 get { return content; } 26 } 27 28 public int Capacity 29 { 30 get { return capacity; } 31 } 32 33 public bool IsEmpty 34 { 35 get { return content == 0; } 36 } 37 38 public bool IsFull 39 { 40 get { return content == capacity; } 41 } 42 #endregion 43 44 #region Initiators 45 public Bottle(int capacity) 46 : this(capacity, 0) 47 { 48 49 } 50 51 public Bottle(int capacity, int content) 52 { 53 if (capacity > 0) 54 { 55 this.capacity = capacity; 56 if (content > -1 && content <= capacity) 57 this.content = content; 58 59 size.Width = 30; 60 size.Height = SIZE_FACTOR * capacity; 61 bounds.Size = size; 62 canvas = new Bitmap(size.Width, size.Height); 63 painter = Graphics.FromImage(canvas); 64 } 65 } 66 #endregion 67 68 #region Methods 69 public void DropIn() 70 { 71 DropIn(capacity); 72 } 73 public void DropIn(int amount) 74 { 75 if (amount > 0) 76 { 77 content += amount; 78 if (content > capacity) 79 content = capacity; 80 81 dirty = true; 82 } 83 } 84 85 public void DropOut() 86 { 87 DropOut(capacity); 88 } 89 public void DropOut(int amount) 90 { 91 if (amount > 0 && amount < content) 92 { 93 content -= amount; 94 } 95 else 96 { 97 content = 0; 98 } 99 100 dirty = true; 101 } 102 #endregion 103 104 #region IVisible 105 public Rectangle Bounds 106 { 107 get { return bounds; } 108 } 109 110 public int X 111 { 112 get { return bounds.X; } 113 set { bounds.X = value; } 114 } 115 116 public int Y 117 { 118 get { return bounds.Y; } 119 set { bounds.Y = value; } 120 } 121 122 public Bitmap Draw() 123 { 124 if (dirty) 125 { 126 painter.Clear(Color.Transparent); 127 128 // simple look bottle 129 int contentHeight = (int)((float)bounds.Height * ((float)content / (float)capacity)); 130 131 if (contentHeight > 0) 132 { 133 using (Brush b = new LinearGradientBrush( 134 new Rectangle( 135 0, 136 bounds.Height - contentHeight - 1, 137 bounds.Width, 138 contentHeight 139 ), 140 Color.LightBlue, 141 Color.DarkBlue, 142 90)) 143 { 144 Rectangle contentRect = new Rectangle( 145 0, 146 bounds.Height - contentHeight, 147 bounds.Width, 148 contentHeight 149 ); 150 painter.FillRectangle(b, contentRect); 151 } 152 } 153 154 painter.DrawRectangle( 155 Pens.Silver, 156 0, 157 0, 158 bounds.Width - 1, 159 bounds.Height - 1 160 ); 161 162 string s = string.Format("{0}/{1}", content, capacity); 163 painter.DrawString( 164 s, 165 SystemFonts.DefaultFont, 166 Brushes.Black, 167 2, 168 1 169 ); 170 painter.DrawString( 171 s, 172 SystemFonts.DefaultFont, 173 Brushes.Black, 174 1, 175 2 176 ); 177 painter.DrawString( 178 s, 179 SystemFonts.DefaultFont, 180 Brushes.Black, 181 2, 182 3 183 ); 184 painter.DrawString( 185 s, 186 SystemFonts.DefaultFont, 187 Brushes.Black, 188 3, 189 2 190 ); 191 painter.DrawString( 192 s, 193 SystemFonts.DefaultFont, 194 Brushes.White, 195 2, 196 2 197 ); 198 199 dirty = false; 200 } 201 202 return canvas; 203 } 204 #endregion 205 206 #region Elemenet 207 public override Type Type 208 { 209 get { return typeof(Bottle); } 210 } 211 #endregion 212 213 }
World 类

1 public class World 2 { 3 const int PADDING = 20; 4 5 #region Variables 6 List<Bottle> bottles = new List<Bottle>(); 7 8 Rectangle bounds = Rectangle.Empty; 9 #endregion 10 11 #region Properties 12 public List<Bottle> Bottles 13 { 14 get { return bottles; } 15 } 16 17 public Rectangle Bounds 18 { 19 get { return bounds; } 20 set 21 { 22 bounds = value; 23 arrangeBottles(); 24 } 25 } 26 #endregion 27 28 #region Initiators 29 public World() 30 { 31 32 } 33 public World(Rectangle bounds) 34 { 35 this.bounds = bounds; 36 } 37 #endregion 38 39 #region world methods 40 public Bottle CreateBottle(int capacity) 41 { 42 return CreateBottle(capacity, 0); 43 } 44 public Bottle CreateBottle(int capacity, int content) 45 { 46 Bottle b = new Bottle(capacity, content); 47 bottles.Add(b); 48 arrangeBottles(); 49 return b; 50 } 51 52 public void DestroyBottle() 53 { 54 bottles.Clear(); 55 } 56 public void DestroyBottle(Bottle b) 57 { 58 bottles.Remove(b); 59 } 60 public void DestroyBottle(int capacity) 61 { 62 List<Bottle> tmp = new List<Bottle>(); 63 foreach (Bottle b in bottles) 64 { 65 if (b.Capacity != capacity) 66 tmp.Add(b); 67 } 68 69 bottles.Clear(); 70 bottles.AddRange(tmp); 71 } 72 73 #endregion 74 75 #region paint helpers 76 Size getTotalSize() 77 { 78 Size sz = Size.Empty; 79 foreach (Bottle b in bottles) 80 { 81 sz.Width += PADDING + b.Bounds.Width; 82 if (sz.Height < b.Bounds.Height) 83 sz.Height = b.Bounds.Height; 84 } 85 86 return sz; 87 } 88 89 void arrangeBottles() 90 { 91 Size sz = getTotalSize(); 92 Point offset = new Point( 93 (bounds.Width - sz.Width) / 2, 94 (bounds.Height - sz.Height) / 2 + sz.Height 95 ); 96 97 foreach (Bottle b in bottles) 98 { 99 b.X = offset.X; 100 b.Y = offset.Y - b.Bounds.Height; 101 102 offset.X += PADDING + b.Bounds.Width; 103 } 104 } 105 #endregion 106 }
Game 类

1 public class Game 2 { 3 string name = string.Empty; 4 int bottleCount = 0; 5 bool initiated = false; 6 int targetBottle = -1; 7 int targetAmount = -1; 8 9 World world; 10 11 Random rand = new Random(); 12 13 public string Name 14 { 15 get { return name; } 16 } 17 18 public int Target 19 { 20 get { return targetBottle; } 21 } 22 23 public int Amount 24 { 25 get { return targetAmount; } 26 } 27 28 public World World 29 { 30 get { return world; } 31 } 32 33 public Game() 34 { 35 world = new World(); 36 } 37 38 /// <summary> 39 /// Difficaulty of game. 40 /// </summary> 41 /// <param name="difficaulty">Difficaulty from 1 to 3.</param> 42 public void AutoGenerate(int difficaulty) 43 { 44 if (difficaulty < 1) 45 return; 46 47 world.DestroyBottle(); 48 49 int bottleCount = rand.Next(3, 5); //3 + difficaulty); 50 targetBottle = rand.Next(0, bottleCount - 1); 51 52 int maxAmount = 10; 53 for (int i = 0; i < bottleCount; i++) 54 { 55 int cap = 0; 56 do 57 cap = rand.Next(3, maxAmount + difficaulty); 58 while (capacityInside(cap)); 59 world.CreateBottle(cap); 60 } 61 62 targetAmount = rand.Next(1, world.Bottles[targetBottle].Capacity); 63 64 initiated = true; 65 } 66 67 bool capacityInside(int cap) 68 { 69 foreach (Bottle b in world.Bottles) 70 if (b.Capacity == cap) 71 return true; 72 return false; 73 } 74 75 public bool CheckSuccess() 76 { 77 if (targetBottle > -1) 78 if (initiated && world.Bottles.Count > targetBottle) 79 return world.Bottles[targetBottle].Content == targetAmount; 80 return false; 81 } 82 }
游戏的计时
简单的实现
源码及工程文件
© Conmajia 2012
if(jQuery('#no-reward').text() == 'true') jQuery('.bottom-reward').addClass('hidden');
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?