讨教下们属性流推箱子方法可不可行

.Net技术 码拜 9年前 (2016-02-28) 1073次浏览
C# 控制台推箱子游戏
lib:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace pushbox
{
    public enum valueType { X, Y }//坐标类型枚举
    public enum ObjType { people = 0, box = 1, food = 2, }//对象类型枚举
    public class obj//强大的对象
    {
        Random Rnd = new Random();//实例化一个随机数生成对象
        /// <summary>
        /// 初始化一个对象
        /// </summary>
        /// <param name="_type">设置对象类型</param>
        /// <param name="_add">给一个添加到List的方法</param>
        /// <param name="_print">给一个打印方法</param>
        /// <param name="_findobj">给一个查找方法</param>
        /// <param name="_x_max">场景宽(带默认)</param>
        /// <param name="_y_max">场景高(带默认)</param>
        public obj(ObjType _type, Action<obj> _add,Action _print,Func<string,ObjType,List<obj>> _findobj, int _x_max = 22, int _y_max = 11)
        {
            _objtype = _type;//设置类型
            x_max = _x_max;//场景大小存起来,以后要用
            y_max = _y_max;
            NewPoint();//随机产生坐标
            _add(this);//添加的方法存起来
            Print = _print;//打印的方法存起来
            FindObj = _findobj;//查找的方法存起来
        }
        /*--定义属性下的字段*/
        int _x;
        int _y;
        private int x_max;
        private int y_max;
        public string newStrType = string.Empty;//自定义显示的字符
        ObjType _objtype;
        string[] showObj = new string[3] { "人", "箱", "星" }; //显示内容的集合
        private obj Next { get; set; }//将要推动的对象
        private obj Last { get; set; }//推动本人的对象
        public ObjType type { get { return _objtype; } }//返回对象类型
        public override string ToString() { return "(" + x.ToString() + "," + y.ToString() + ")"; }//重写转换字符串操作,返回字符串类型坐标
        public void NewPoint() { _x = 1 + Rnd.Next(x_max - 2); _y = 1 + Rnd.Next(y_max - 2); }//生成随机坐标方法
        public Action Print { get; set; }//打印的方法
        private Func<string,ObjType,List<obj>> FindObj { get; set; }//查找的方法,返回一个对象
        private int NextMove { get; set; }//移动方向
        /// <summary>
        /// 返回显示的字符串,可以自定义
        /// </summary>
        public string strType 
        {
            get 
            { 
                if (newStrType == string.Empty)
                    return showObj[_objtype.GetHashCode()]; 
                else
                    return newStrType;
            }
            set
            {
                newStrType = value;
            }
        } 
        public int x//坐标
        {
            get { return _x; }
            set
            {
                NextMove = value - _x;
                if (OnValueChange(value, valueType.X, type))
                {
                    _x = value;
                    DoFind(valueType.X);
                    Print();
                }
                else
                    Back(valueType.X);
            }
        }
        public int y//坐标
        {
            get { return _y; }
            set
            {
                NextMove = value - _y;//存下操作的方向
                if (OnValueChange(value, valueType.Y, type))//能否允许改变
                {
                    _y = value;
                    DoFind(valueType.Y);//改变后寻找身边的对象
                    Print();//打印
                }
                else
                    Back(valueType.Y);//移动失败,退回原来状态
            }
        }
        /// <summary>
        /// 移动失败,回滚
        /// </summary>
        /// <param name="valuetype">坐标类型</param>
        private void Back(valueType valuetype)
        {
            if (Last == null)
                return;
            if (valuetype == valueType.X)
                Last._x = Last._x - NextMove;
            else
                Last._y = Last._y - NextMove;
        }
        /// <summary>
        /// 值改变时间
        /// </summary>
        /// <param name="value">改变的新值</param>
        /// <param name="valueType">坐标类型</param>
        /// <param name="objType">对象类型</param>
        /// <returns></returns>
        private bool OnValueChange(int value, valueType valueType, ObjType objType)
        {
            if (objType == ObjType.people)//是不是人动了
                return CheckValue(value, valueType, 0);//人可以走到最边上
            else
                return CheckValue(value, valueType, -1);//但箱子不行
        }
        private bool CheckValue(int value, valueType valueType, int addmax)
        {
            if (valueType == valueType.X)
                return 0 + Math.Abs(addmax) <= value && value < (x_max + addmax) ? true : false;//x值能否合法
            else
                return 0 + Math.Abs(addmax) <= value && value < (y_max + addmax) ? true : false;//y值能否合法
        }
        /// <summary>
        /// 查找事件
        /// </summary>
        /// <param name="valuetype"></param>
        private void DoFind(valueType valuetype)
        {
            if (FindObj(this.ToString(),ObjType.box).Count == 0)//找不到,算了
                return;
            Next = FindObj(this.ToString(), ObjType.box)[0];//找到了存下来
            if (type == ObjType.people)//本人是人
            {
                if (valuetype == valueType.X)//去推箱子
                {
                    Next.Last = this;
                    Next.x = Next.x + NextMove;
                }
                else
                {
                    Next.Last = this;
                    Next.y = Next.y + NextMove;
                }
            }
            else if (type == ObjType.box)//本人是箱子
            {
                if (FindObj(this.ToString(), ObjType.box).Count > 1)//看有没有与箱子重叠
                {
                    if (valuetype == valueType.X)//重叠了回滚
                    {
                        this._x = this._x - NextMove;
                        Last._x = Last._x - NextMove;
                    }
                    else
                    {
                        this._y = this._y - NextMove;
                        Last._y = Last._y - NextMove;
                    }
                }
                else if (FindObj(this.ToString(), ObjType.food).Count > 0)//能否与food重叠,改变显示的字符
                    this.strType = "興";
                else
                    this.strType = "箱";//都不是,还原回原来的字符
            }
        }
    }
}

Program:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
namespace pushbox
{
    class Program
    {
        static int x_max = 22;//场景大小
        static int y_max = 11;
        public static List<obj> ObjList = new List<obj>();//建立一个集合存全部的对象
        private static void print()//打印时间,实例化是传给对象
        {
            string show = string.Empty;//初始化
            for (int j = 0; j < y_max; j++)//循环去写每一个坐标
            {
                for (int i = 0; i < x_max; i++)
                {
                    string strPoint = "(" + i.ToString() + "," + j.ToString() + ")";//转换成字符串型的坐标
                    obj obj = ObjList.Find(o => o.ToString() == strPoint);//遍历所以对象有没有一样的
                    if (obj != null)
                        show += obj.strType;//有的话就显示出来
                    else
                        show += "空";//没有就补格子
                }
                show += "\r\n";//换行
            }
            Console.Write("\r\n" + show + "\r\n");//输出
        }
        private static List<obj> FindObj(string point,ObjType objtype)//查找时间,实例化时传入对象
        {
            return ObjList.FindAll(o=>o.type == objtype && o.ToString() == point);
        }
        static void Main(string[] args)
        {
            obj people = new obj(ObjType.people, p => ObjList.Add(p),print,FindObj);//实例化人
            System.Threading.Thread.Sleep(50);//延时,不延时随机数忙不过来,都产生一样的随机数
            for (int i = 0; i < 10; i++)//生成一堆箱子
            {
                obj box = new obj(ObjType.box, b => ObjList.Add(b), print, FindObj);
                System.Threading.Thread.Sleep(50);
            }
            for (int i = 0; i < 10; i++)//生成一堆星星
            {
                obj food = new obj(ObjType.food, f => ObjList.Add(f), print, FindObj);
                System.Threading.Thread.Sleep(50);
            }
            print();
            ConsoleKeyInfo Key;//存按键
            do
            {
                Key = Console.ReadKey();//按键捕捉
                switch (Key.Key)
                {
                    case ConsoleKey.A:
                        people.x = people.x - 1;
                        break;
                    case ConsoleKey.D:
                        people.x = people.x + 1;
                        break;
                    case ConsoleKey.S:
                        people.y = people.y + 1;
                        break;
                    case ConsoleKey.W:
                        people.y = people.y - 1;
                        break;
                }
            } while (true);//不断循环
        }
    }
}

人代表人物,箱代表箱子,星代表星星,興代表装着星星的箱子,空代表没有东西,本来用符号的,但特殊字符发不上来改成文字。
这是一个推箱子游戏的代码,不难看出,本人非常喜欢在属性的set里面带上一个方法去作为一个值变更事件来用,并为这种方法命名为属性流,但有人说这种方法不可取,在这讨教下各位高手们,这种方法有什么利与弊,究竟利大还是弊大?

解决方案

10

死循环是你本人写的有问题
至少Control.Text里就调用OnTextChanged事件,说明这样做是合理的

20

说“可取”或“不可取”这种话有点空洞了,你应该理解你所谓的“有人说”时的背后的理由,而不是纠结一些带有情绪化的肤浅的词儿。一旦你去真正去理解理由,那么不同理由就会产生不同的结果,绝不能用本人的洁癖去要求别人,不能用本人所见去要求别人的是非,这时候你就不会动不动就用绝对化的词儿来说事非,而是比较客观地去讨论不同人的设计想法的差异性。
假设有一个位置是(2,1),另一个位置是(3,2),假设这是“积木系统”可以从位置1将积木移动到位置2,那么你所谓的“先设置x为3、后设置y为2”跟“先设置y为2、后设置x为3”有区别吗?
对于静态概念,那么“坐标位置”概念本身是x-y方式标识的,是不可分割的两部分,不区分谁先谁后。对于动态行为概念,那么才会去用各种真正对应于实际领域的方式去设计它。因此一般来说,对于动态行为,会使用”goto(2,1)”一个数据作为第一个操作数据,然后使用“goto(3,2)”作为第二个操作数据。
例如说,一个人从上海到达了北京,问一下这个事件跟“这个人的左脚先从上海到达了北京,然后他的右脚又从上海到达了北京”这样的描述有区别吗?假如你觉得没有区别,那么你可以继续去研究。但是别人假设预见到了你这种不靠谱、不真实的冗余表述方式“不可取”,你应该理解他以什么事实为本,而你以什么来对付(凑合)。你从他的角度去理解,而不是纠结什么事非。
任何东西的是非争议都是没有尽头的,任何人都能找到每一件事情里边的是非。关键是哪一种方式更自然、更适合下一步的复杂情况,也就是适用本人地方法为最好。
你用技术化的思维方式、认为“反正本人说‘先是左脚到达、然后右脚又到达”也完成了程序编写,那就是你的理解方式。而别人用更加符合自然的方式,可能说明别人此时更加注重实践、注重其它系统设计也需要相同的编程框架。

10

你是指代码1的 71 ~ 102 中的 set 代码段吗?
首先,属性访问器就是为这类需求设计的,假如仅仅是赋值、取值就没有必要加这个累赘了
在属性被访问时,调用某个方法,就好比是触发器。这是在普通不过的需求了,并且几乎所用面向对象的语言都提供有这个能力。只是称谓不同而已
当然,你也可以单写个方法去实现这个行为,估计这就是称不可取的人的做法
对于你目前的应用,完全是没有问题的:x 和 y 不会同时改变
但假如你改变规则,允许斜线方向移动
那么你这样做就有点问题(也就是 不可取 了)

CodeBye 版权所有丨如未注明 , 均为原创丨本网站采用BY-NC-SA协议进行授权 , 转载请注明讨教下们属性流推箱子方法可不可行
喜欢 (0)
[1034331897@qq.com]
分享 (0)