© Conmajia 2012
本文所有源代码和VisualStudio2010(.NET Fx 2.0)工程打包在本文最后下载。(别找我要源码,一概不理会)
《倒水解密》是一款很不错的手机益智类游戏,游戏界面如下:
规则是这样的:
有N个容量不同的瓶子,指定「将a升水倒入容量为b的瓶子」。游戏要求通过装水、倒水,达成给定的目标。
该游戏虽然简单,但可玩性高,也可有不同的难度变化,并且能锻炼玩家的心算能力。《倒水解密》不失为一个很好的繁忙工作之余的休闲方式。
说到这里,大家应该能猜到我想干什么了。没错,山寨之。
下面是山寨游戏的屏幕录像:
虽然界面有点简陋,但至少实现了。(屏幕录像软件不能录入鼠标光标,实际上鼠标光标是动态的)。
游戏操作方式如下:
下面是游戏的模型结构。
Bottle类,表示瓶子。保存了瓶子的关键属性如容量、储量,以及基本方法如倒入、倒出。该类实现了IVisible可视化接口。这个接口很简单,只是提供了一个Draw()方法,用于重绘瓶子自身并返回图像。使用这种方式,可以方便的修改瓶子的外观样式而不用修改其他部分代码。例如可以简单的用矩形画瓶子,也可以像上面的手机游戏截图一样用非常的漂亮的贴图来做。
这里我用画图鼠绘了一个丑陋的瓶子作为例子。
public class Bottle : Element, IVisible { const int SIZE_FACTOR = 10; #region Variables int content = 0; int capacity = 0; Size size = Size.Empty; Rectangle bounds = Rectangle.Empty; Bitmap canvas; Graphics painter; bool dirty = true; #endregion #region Properties public int FreeSpace { get { return capacity - content; } } public int Content { get { return content; } } public int Capacity { get { return capacity; } } public bool IsEmpty { get { return content == 0; } } public bool IsFull { get { return content == capacity; } } #endregion #region Initiators public Bottle(int capacity) : this(capacity, 0) { } public Bottle(int capacity, int content) { if (capacity > 0) { this.capacity = capacity; if (content > -1 && content <= capacity) this.content = content; size.Width = 30; size.Height = SIZE_FACTOR * capacity; bounds.Size = size; canvas = new Bitmap(size.Width, size.Height); painter = Graphics.FromImage(canvas); } } #endregion #region Methods public void DropIn() { DropIn(capacity); } public void DropIn(int amount) { if (amount > 0) { content += amount; if (content > capacity) content = capacity; dirty = true; } } public void DropOut() { DropOut(capacity); } public void DropOut(int amount) { if (amount > 0 && amount < content) { content -= amount; } else { content = 0; } dirty = true; } #endregion #region IVisible public Rectangle Bounds { get { return bounds; } } public int X { get { return bounds.X; } set { bounds.X = value; } } public int Y { get { return bounds.Y; } set { bounds.Y = value; } } public Bitmap Draw() { if (dirty) { painter.Clear(Color.Transparent); // simple look bottle int contentHeight = (int)((float)bounds.Height * ((float)content / (float)capacity)); if (contentHeight > 0) { using (Brush b = new LinearGradientBrush( new Rectangle( 0, bounds.Height - contentHeight - 1, bounds.Width, contentHeight ), Color.LightBlue, Color.DarkBlue, 90)) { Rectangle contentRect = new Rectangle( 0, bounds.Height - contentHeight, bounds.Width, contentHeight ); painter.FillRectangle(b, contentRect); } } painter.DrawRectangle( Pens.Silver, 0, 0, bounds.Width - 1, bounds.Height - 1 ); string s = string.Format("{0}/{1}", content, capacity); painter.DrawString( s, SystemFonts.DefaultFont, Brushes.Black, 2, 1 ); painter.DrawString( s, SystemFonts.DefaultFont, Brushes.Black, 1, 2 ); painter.DrawString( s, SystemFonts.DefaultFont, Brushes.Black, 2, 3 ); painter.DrawString( s, SystemFonts.DefaultFont, Brushes.Black, 3, 2 ); painter.DrawString( s, SystemFonts.DefaultFont, Brushes.White, 2, 2 ); dirty = false; } return canvas; } #endregion #region Elemenet public override Type Type { get { return typeof(Bottle); } } #endregion }
World类,表示瓶子所在世界。存储了所有的瓶子,用于和游戏交互。
public class World { const int PADDING = 20; #region Variables List<Bottle> bottles = new List<Bottle>(); Rectangle bounds = Rectangle.Empty; #endregion #region Properties public List<Bottle> Bottles { get { return bottles; } } public Rectangle Bounds { get { return bounds; } set { bounds = value; arrangeBottles(); } } #endregion #region Initiators public World() { } public World(Rectangle bounds) { this.bounds = bounds; } #endregion #region world methods public Bottle CreateBottle(int capacity) { return CreateBottle(capacity, 0); } public Bottle CreateBottle(int capacity, int content) { Bottle b = new Bottle(capacity, content); bottles.Add(b); arrangeBottles(); return b; } public void DestroyBottle() { bottles.Clear(); } public void DestroyBottle(Bottle b) { bottles.Remove(b); } public void DestroyBottle(int capacity) { List<Bottle> tmp = new List<Bottle>(); foreach (Bottle b in bottles) { if (b.Capacity != capacity) tmp.Add(b); } bottles.Clear(); bottles.AddRange(tmp); } #endregion #region paint helpers Size getTotalSize() { Size sz = Size.Empty; foreach (Bottle b in bottles) { sz.Width += PADDING + b.Bounds.Width; if (sz.Height < b.Bounds.Height) sz.Height = b.Bounds.Height; } return sz; } void arrangeBottles() { Size sz = getTotalSize(); Point offset = new Point( (bounds.Width - sz.Width) / 2, (bounds.Height - sz.Height) / 2 + sz.Height ); foreach (Bottle b in bottles) { b.X = offset.X; b.Y = offset.Y - b.Bounds.Height; offset.X += PADDING + b.Bounds.Width; } } #endregion }
Game类,游戏类。保存游戏世界,负责自动生成游戏和判定游戏胜利。
public class Game { string name = string.Empty; int bottleCount = 0; bool initiated = false; int targetBottle = -1; int targetAmount = -1; World world; Random rand = new Random(); public string Name { get { return name; } } public int Target { get { return targetBottle; } } public int Amount { get { return targetAmount; } } public World World { get { return world; } } public Game() { world = new World(); } /// <summary> /// Difficaulty of game. /// </summary> /// <param name="difficaulty">Difficaulty from 1 to 3.</param> public void AutoGenerate(int difficaulty) { if (difficaulty < 1) return; world.DestroyBottle(); int bottleCount = rand.Next(3, 5); //3 + difficaulty); targetBottle = rand.Next(0, bottleCount - 1); int maxAmount = 10; for (int i = 0; i < bottleCount; i++) { int cap = 0; do { cap = rand.Next(3, maxAmount + difficaulty); } while (capacityInside(cap)); world.CreateBottle(cap); } targetAmount = rand.Next(1, world.Bottles[targetBottle].Capacity); initiated = true; } bool capacityInside(int cap) { foreach (Bottle b in world.Bottles) { if (b.Capacity == cap) return true; } return false; } public bool CheckSuccess() { if (targetBottle > -1) { if (initiated && world.Bottles.Count > targetBottle) { return world.Bottles[targetBottle].Content == targetAmount; } } return false; } }
游戏的计时、计步、界面操作等统统放在主窗体,这里不做赘述。
简单的实现,还有倒计时、高分榜等功能可以扩展,界面也可以做的更漂亮些,欢迎大家扩展。
源码及工程文件(VS2010)打包 :点击下载
© Conmajia 2012