自己动手实现一个《倒水解密》游戏

2023-11-07

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

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

规则是这样的:

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

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

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

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

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

游戏操作方式如下:

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

下面是游戏的模型结构。

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

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

// By Conmajia<conmajia@gmail.com> on September 6th., 2012
using 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<conmajia@gmail.com> on September 6th., 2012
using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;

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

// By Conmajia<conmajia@gmail.com> on September 6th., 2012
using 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();
        }

        /// <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

 

 

 

 

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

自己动手实现一个《倒水解密》游戏 的相关文章

  • 在bash中将两个变量相除

    我试图在 bash 中划分两个 var 这就是我得到的 var1 3 var2 4 echo var1 var2 我总是遇到语法错误 有谁知道出了什么问题吗 shell 解析仅对整数除法有用 var1 8 var2 4 echo var1
  • 在 FlaskForm (WTForms) 中传递并使用变量

    该代码非常不言自明 我想将一个变量传递给FlaskForm子类以供进一步使用 from flask import Flask render template string from flask wtf import FlaskForm fr
  • 使用 @abstractproperty 和 @abstractmethod 实现/覆盖的实际差异

    考虑一个抽象基类 它具有您希望每个后续子类重写的函数 使用 abc 模块和 ABCMeta 装饰有 abstractproperty or abstractmethod实际上强制子类 开发人员实现创建装饰器指定的函数类型 根据我的实验 您可
  • Swift 1.2 重新声明 Objective-C 方法

    我刚刚从 swift 1 1 更新到 swift 1 2 并得到编译器错误 Method setVacation redeclares Objective C method setVacation 这里有一些代码 var vacation
  • 如何在 Dart 中打印美元符号 $

    我实际上需要在 Dart 中在变量之前打印一个美元符号 例如 void main int dollars 42 print I have dollars I have 42 我希望输出为 我有 42 美元 我怎样才能做到这一点 谢谢 飞镖弦
  • C# 反射和获取属性

    我有以下虚拟类结构 我试图找出如何从 PeopleList 中 People 类的每个实例获取属性 我知道如何从 People 的单个实例中获取属性 但我无法弄清楚如何从 PeopleList 中获取它 我确信这真的很简单 但有人能指出我正
  • 如何使用户输入与变量相关?

    我不知道如何准确地表达这个问题 但这就是我想要实现的目标 我正在使用堆栈实现河内塔插图 这是里面的main 功能 System out println Type the source pole number and the destinat
  • html 表单发布到 Flex 应用程序

    我有一个基本完成的 Flex 应用程序 它使用 Zend AMF 来连接 提供数据 我的应用程序确实有一个登录屏幕 看起来工作正常 现在我想在我的网站上添加另一个登录表单 允 许用户输入用户名 密码 提交表单时应将数据传递给 Flex 应用
  • C语言中变量名是如何存储在内存中的?

    在 C 中 假设你有一个名为variable name 假设它位于0xaaaaaaaa 在该内存地址处 您有整数 123 换句话说 variable name包含 123 个 我正在寻找有关措辞的澄清 variable name位于0xaa
  • 操纵 setter 以避免 null

    通常我们有 public string code get set 如果最终有人将代码设置为 null 我需要避免空引用异常 我尝试这个想法 有什么帮助吗 public string code get set if code null cod
  • 有时 Properties.load() 会跳过行

    在以下情况下 Properties load 会跳过 InputStream 的第二行 这是 Java 的错误还是正常行为 public class PropTest public static void main String args
  • 在 Spring Boot application.properties 中指定信任存储信息

    我在用springBoot版本1 2 0 RELEASE 我正在尝试通过配置我的密钥库和信任库application properties 当我添加以下设置时 我可以使密钥库正常工作 但不能使信任库正常工作 server ssl key s
  • F# nameof 运算符不是一等函数

    我正在使用 F 4 7
  • 如何动态创建新属性

    如何从对象方法内的给定参数创建属性 class Foo public function createProperty var name val here how can I create a property named var name
  • 实体框架 - 循环更新属性

    我正在尝试找到一种方法来循环 EF 对象的属性并更新这些属性的值 更具体地说 我有 50 个字段 其中最多填充 50 个下拉列表 所有 50 个可能都需要填充 也可能不需要填充 为了解决这个问题 我有一个中继器 最多可以创建 50 个 DD
  • 如何让 C# 设计器编辑我的结构属性?

    我正在使用 C 创建一个具有多个自定义属性的自定义 Windows 窗体控件 这些属性之一是一个带有几个整数字段的简单结构 public struct Test public int A B Test Test Category MyCat
  • 属性文件中的特殊字符

    在我的 Java Spring Web 应用程序中 我在打印从属性文件检索的意大利语特殊字符 等 时遇到问题 我找到了这篇文章http docs oracle com cd E26180 01 Platform 94 ATGProgGuid
  • Python 属性和 Swig

    我正在尝试使用 swig 为一些 C 代码创建 python 绑定 我似乎遇到了一个问题 试图从我拥有的一些访问器函数创建 python 属性 方法如下 class Player public void entity Entity enti
  • ssh远程变量赋值?

    以下内容对我不起作用 ssh email protected cdn cgi l email protection k 5 echo k 它只是返回一个空行 如何在远程会话 ssh 上分配变量 Note 我的问题是not关于如何将本地变量传
  • 如何将变量插入 PHP 数组?

    我在网上查了一些答案 但都不是很准确 我希望能够做到这一点 id result id info array id Example echo info 0 这有可能吗 您需要的是 不推荐 info array id Example varia

随机推荐

  • 数据库相关

    目录 第一章 数据库概述 1 1 数据库的好处 1 2 数据库的常见概念 1 3 数据库的存储特点 1 4 数据库的常见分类 1 5 SQL语言的分类 第二章 MySQL概述 2 1 MySQL的背景 2 2 MySQL的优点 2 3 My
  • 闲谈IPv6-IPv6地址的scope到底是什么?

    一台主机启动后 每一块网卡都会自动生成一个fe80打头的 链路本地地址 这个地址在Linux上你删都删不掉 不信你试试 在Windows是可以删掉的 但是只要你重置网卡 它就会自动生成 这个所谓的链路本地地址到底有何怪异 我的主机安装两块网
  • 复购客户sql

    复购客户 用户分析是电商数据分析中重要的模块 在对用户特征深度理解和用户需求充分挖掘基础上 进行全生命周期的运营管理 拉新 gt 活跃 gt 留存 gt 价值提升 gt 忠诚 请尝试回答以下3个问题 现在数据库中有一张用户交易表order
  • 大模型部署避坑指南之: undefined symbol: cublasLtGetStatusString,version libcublasLt.so.11

    问题描述 OSError opt conda envs python35 paddle120 env lib python3 7 site packages nvidia cublas lib libcublas so 11 symbol
  • 当我遇到线上内存溢出问题是如何查看的

    首先我们自己写一个demo 来模拟内存溢出 新建User类 private int id private String name byte a new byte 1024 1000 public User public User int i
  • python oj刷题网站_程序员常用的刷题网站

    1 Lintcode Lintcode com LintCode网站是国内较大的在线编程 测评网站 此网站提供各大IT公司的算法面试题类型 行分门别类 由简单到中等 再到难 便于不同水平的程序员进行刷题练习 同时网站支持多种语言 Java
  • LeetCode905. 按奇偶排序数组

    给你一个整数数组 nums 将 nums 中的的所有偶数元素移动到数组的前面 后跟所有奇数元素 返回满足此条件的 任一数组 作为答案 示例 1 输入 nums 3 1 2 4 输出 2 4 3 1 解释 4 2 3 1 2 4 1 3 和
  • PostgreSQL之pgsql命令行常用命令

    文章目录 1 登录 1 1 psql报错 1 2 psql 错误 致命错误 用户 postgres Password 认证失败 2 常用操作 1 登录 1 1 psql报错 详情 分析 C Users Administrator gt pg
  • typecho反序列化漏洞复现

    typecho框架存在反序列化漏洞 利用此漏洞可执行任意代码 环境搭建 第一步 第二步 第三步 第三步 第四步 第五步 第六步 第七步 第八步 第九步 漏洞分析 typecho build install php 文件中 使用unseria
  • Eclipse 安装集成 FindBugs BUG分析插件

    一 下载eclipse软件 https www eclipse org downloads 下载Zip压缩包 解压缩即可 二 下载findbugs plugin压缩包 官网下载或者是从其他资源获取 http findbugs sourcef
  • 阿里推荐算法:BERT4Rec: Sequential Recommendation with Bidirectional Encoder Representations from Transform

    这篇是阿里猜你喜欢的一篇transformer paper 含金量很高 注意 1 bert用在推荐系统中 将用户的历史序列看做是词序列 2 测试时 将序列的最后一个item进行masked Abstract 根据用户历史的行为信息 对用户动
  • [论文阅读] (16)Powershell恶意代码检测论文总结及抽象语法树(AST)提取

    娜璋带你读论文 系列主要是督促自己阅读优秀论文及听取学术讲座 并分享给大家 希望您喜欢 由于作者的英文水平和学术能力不高 需要不断提升 所以还请大家批评指正 非常欢迎大家给我留言评论 学术路上期待与您前行 加油 前一篇介绍分享英文论文审稿意
  • python1_4字符串

    字符串 string My name string My name string My name 字符串可以是单 双 三引号 三引号可以空行 res string 1 字符串的索引 res string 2 print res 如图所示1
  • rstudio 导出结果_R语言结果输出方法

    输出函数 cat sink writeLines write table 根据输出的方向分为输出到屏幕和输出到文件 1 cat函数即能输出到屏幕 也能输出到文件 使用方式 cat file sep fill FALSE labels NUL
  • SpringBoot--基础--09--条件注解

    SpringBoot 基础 09 条件注解 一 条件注解 1 1 代码和测试 SysService public interface SysService void show WindowService public class Windo
  • apache beam入门之group分组操作

    目录 apache beam 个人使用经验总结目录和入门指导 Java 如果我们希望将相同的元素进行分组 则可以用Group的转化方法进行操作 首先我们生成1个单词数据集 List
  • 最新uniApp微信小程序获取头像open-type=“chooseAvatar“ @chooseavatar方法

    小程序用户头像昵称获取规则调整公告 调整说明 自 2022 年 10 月 25 日 24 时后 以下统称 生效期 用户头像昵称获取规则将进行如下调整 自生效期起 小程序 wx getUserProfile 接口将被收回 生效期后发布的小程序
  • matlab-滤波系数生成频响曲线

    转载自 matlab 滤波系数生成频响曲线 设计滤波器 build filter sample rate fs 6250 cutoff frequency fc 1000 build a 6th order highpass Butterw
  • 判断多边形与多边形是否相交的方法,代码来自于OpenLayers。

    在做GIS开发时 常常需要用到空间判断的算法 比如 判断地图中的多边形与多边形是否相交 我在项目中具体的需求就是如此 需要过滤某个区域的瓦片地图 先把瓦片地图反向解析成Envolope 然后和该区域进行比对 再做其他处理 其实在已经有开源的
  • 自己动手实现一个《倒水解密》游戏

    本文所有源代码和VisualStudio2010 NET Fx 2 0 工程打包在本文最后下载 别找我要源码 一概不理会 倒水解密 是一款很不错的手机益智类游戏 游戏界面如下 规则是这样的 有N个容量不同的瓶子 指定 将a升水倒入容量为b的