「玩一玩」自制一个《倒水解密》游戏

Conmajia 2012-09-06 11:52:24
加精
© 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
...全文
9010 168 打赏 收藏 转发到动态 举报
写回复
用AI写文章
168 条回复
切换为时间正序
请发表友善的回复…
发表回复
why123qaz 2015-04-27
  • 打赏
  • 举报
回复
留言,支持。
Vict0r Chen 2013-10-06
  • 打赏
  • 举报
回复
mark
linuxca 2013-01-15
  • 打赏
  • 举报
回复
谢谢LZ分享。
光与影的嬉戏 2012-12-26
  • 打赏
  • 举报
回复
支持路过学习
yann_2012 2012-12-25
  • 打赏
  • 举报
回复
经过
Siliphen 2012-12-25
  • 打赏
  • 举报
回复
请问下楼主, 录制gif动画,你用的是什么软件? 录制了这么长时间,才200KB大小。。。
  • 打赏
  • 举报
回复
楼主好强,支持ing
wushuang443 2012-12-12
  • 打赏
  • 举报
回复
野比你又来了啊。不错不错
shamini35 2012-11-17
  • 打赏
  • 举报
回复
shamini35 2012-11-17
  • 打赏
  • 举报
回复
Conmajia 2012-11-17
  • 打赏
  • 举报
回复
引用 212 楼 porenasckx 的回复:
LZ把这个再改经典一点啊,,判断一下啊。 像3,6,9.注入8升 2,4,8注入3升。 这都没解啊。。。
囧。。抛砖引玉。。抛砖引玉。。
E次奥 2012-11-17
  • 打赏
  • 举报
回复
LZ把这个再改经典一点啊,,判断一下啊。 像3,6,9.注入8升 2,4,8注入3升。 这都没解啊。。。
cyneuzk 2012-11-17
  • 打赏
  • 举报
回复
看起来不错哇
  • 打赏
  • 举报
回复
被顶到顶啦,楼主啊,这游戏的主要技术是什么?
Vinnking 2012-10-05
  • 打赏
  • 举报
回复
不错,感谢楼主分享。学习了。
wei_yi_de 2012-09-29
  • 打赏
  • 举报
回复
学习,打酱油
晚安苏州 2012-09-24
  • 打赏
  • 举报
回复
我去……顶一个~
ymim2005 2012-09-24
  • 打赏
  • 举报
回复
英文也存在多义词的现象,楼主不写注释,别人要多花多少时间才能看完
creatce 2012-09-23
  • 打赏
  • 举报
回复
内行看门道,外行看热闹。鼓掌!
ayzk05301 2012-09-23
  • 打赏
  • 举报
回复
不错,很不错,值得学习。。。。。。
加载更多回复(148)

110,533

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧