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

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

© 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
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类,游戏类。保存游戏世界,负责自动生成游戏和判定游戏胜利。

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://xxdhb.baihongyu.com/

你可能感兴趣的文章
ssh与gpg区别_如何使用GPG密钥启用SSH访问进行身份验证
查看>>
apm 韩国开源项目_韩国的开源状态
查看>>
mac上将视频变小_在Mac上将Python 3设置为默认的正确和错误方法
查看>>
java jnlp_Java SE 11删除JNLP的更好解决方案
查看>>
devops 中台_DevOps中的门控生产
查看>>
keil 开源替代_您需要替代开源的哪些专有工具?
查看>>
总论点和分论点_将破坏性的论点变成富有成效的对话
查看>>
pythonic_使用Pythonic在Python中以图形方式编程
查看>>
python black_格式化Python,但您喜欢使用Black
查看>>
如何在Mac上为Python设置虚拟环境
查看>>
使用Python在GitHub Pages上运行博客
查看>>
如何使用Python和Apache Spark分析日志数据
查看>>
移动端仿钉钉聊天 git_使用Git作为聊天的后端
查看>>
raspberry pi_PiFlash入门:在Linux上启动Raspberry Pi
查看>>
固态硬盘损坏数据如何挽救_开放数据和工具如何在灾难期间挽救生命
查看>>
raspberry_您最老的Raspberry Pi多大了?
查看>>
vscode构建rust_使用rust-vmm构建未来的虚拟化堆栈
查看>>
joplin_介绍Joplin,这是Evernote的开源替代方案
查看>>
使用Pygame模块使用Python构建游戏框架
查看>>
如何使用PostgreSQL简化Python代码
查看>>