自己動手實現一個《倒水解密》遊戲

來源:互聯網
上載者:User

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

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.