博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
自己动手实现一个《倒水解密》游戏
阅读量:2397 次
发布时间:2019-05-10

本文共 9850 字,大约阅读时间需要 32 分钟。

本文所有源代码和VisualStudio2010(.NET Fx 2.0)工程打包在本文最后下载。(别找我要源码,一概不理会)

《倒水解密》是一款很不错的手机益智类游戏,游戏界面如下:

规则是这样的:

有N个容量不同的瓶子,指定「将a升水倒入容量为b的瓶子」。游戏要求通过装水、倒水,达成给定的目标。

该游戏虽然简单,但可玩性高,也可有不同的难度变化,并且能锻炼玩家的心算能力。《倒水解密》不失为一个很好的繁忙工作之余的休闲方式。

说到这里,大家应该能猜到我想干什么了。没错,山寨之。

下面是山寨游戏的屏幕录像:

虽然界面有点简陋,但至少实现了。(屏幕录像软件不能录入鼠标光标,实际上鼠标光标是动态的)。

游戏操作方式如下:

  • 在瓶子上双击右键可以把瓶子灌满水
  • 双击左键可以把瓶子里的水倒掉
  • 将一个瓶子拖动到另一个瓶子上可以把水倒过去

下面是游戏的模型结构。

Bottle类,表示瓶子。保存了瓶子的关键属性如容量、储量,以及基本方法如倒入、倒出。该类实现了IVisible可视化接口。这个接口很简单,只是提供了一个Draw()方法,用于重绘瓶子自身并返回图像。使用这种方式,可以方便的修改瓶子的外观样式而不用修改其他部分代码。例如可以简单的用矩形画瓶子,也可以像上面的手机游戏截图一样用非常的漂亮的贴图来做。

1、这里我用画图鼠绘了一个丑陋的瓶子作为例子。

// By Conmajia
on September 6th., 2012using System;using System.Collections.Generic;using System.Text;using System.Drawing;using System.Drawing.Drawing2D;namespace DropWaterGame{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}}

(1)我们可以看到Bottle类的构造函数是Bottle(int capacity)又调用了另一构造函数Bottle(int capacity, int content).

这样的表达方式要是在C++中会编译报错的:

1>c:\users\chenyj\desktop\temp\temp\tempdlg.cpp(14) : error C2059: 语法错误 : “this”

 (2)比较复杂的是Draw方法。他做的事情有:

(2、1)画出水里占有的方形图。

画的方法是通过using里创建的线性画刷。

(2、2)分别写出文字。文字是分为5个点来写的(为什么要这样呢?至今未知)。

 2、

World类,表示瓶子所在世界。存储了所有的瓶子,用于和游戏交互。

// By Conmajia
on September 6th., 2012using System;using System.Collections.Generic;using System.Text;using System.Drawing;namespace DropWaterGame{ public class World { const int PADDING = 20; #region Variables List
bottles = new List
(); Rectangle bounds = Rectangle.Empty; #endregion #region Properties public List
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
tmp = new List
(); 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类,游戏类。保存游戏世界,负责自动生成游戏和判定游戏胜利。

// By Conmajia
on September 6th., 2012using System;using System.Collections.Generic;using System.Text;using System.IO;namespace DropWaterGame{ 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(); } ///
/// Difficaulty of game. /// ///
Difficaulty from 1 to 3. 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

 

 

 

 

 

转载地址:http://jpyob.baihongyu.com/

你可能感兴趣的文章
Nginx——防盗链的配置
查看>>
TCP——粘包/拆包
查看>>
ChannelHandler和ChannelPipeline
查看>>
Netty——传输API
查看>>
Netty——ByteBuf的API
查看>>
Netty——ChannelHandler和ChannelPipeline
查看>>
Netty——ChannelHandlerContext
查看>>
Netty——EventLoop和线程模型
查看>>
Camera 图像处理原理分析- 色彩篇 二
查看>>
Camera 图像处理原理分析- 色彩篇 三
查看>>
Camera 图像处理原理分析- 亮度及曝光控制
查看>>
Camera 图像处理原理分析- 抗噪 变焦 频闪 等
查看>>
c语言核心技术 二
查看>>
udev文件系统的使用和基本工作原理分析
查看>>
快速理解Docker - 容器级虚拟化解决方案
查看>>
Memcached 及 Redis 架构分析和比较
查看>>
Android Kernel Porting 的简单总结文档
查看>>
Tachyon架构分析和现存问题讨论
查看>>
ARM平台上蓝牙协议栈Bluez的移植使用和配置
查看>>
理解和使用Linux的硬件抽象层HAL
查看>>