为南京面对面装饰设计公司 量身定做 的flash版本家装体验

 

利用flash的json接口开发,将后台管理的图片和家装产品数据,调取到flash前端,并且展现配置。能够自由配置设计心仪的家长效果。

本产品已在南京面对面官方网站上上线使用,并得到客户的优异评价。

后期的接口开发和维护工作也在继续开展中。

 

本flash在线体验地址:

http://www.ftface.com/online/virtual/19/

 

AS3:width与content.width的区别

看看这段代码就明白了

Actionscript:
var l:Loader=new Loader();
l.load(new URLRequest(“test.swf”));//test.swf主场景宽度设置为550,有超出边界的元素
l.contentLoaderInfo.addEventListener(Event.COMPLETE,reSize);
addChild(l);
function reSize(e:Event):void {
trace(e.currentTarget.width);//输出550
trace(e.currentTarget.content.width);//输出931.95
}

2012新年抽奖flash

新年快到了,为公司设计开发了最新的年会抽奖flash。一共有12个奖品,每个奖品都有一个任务,完成任务需要有时间限制。

游戏开始的时候,玩家先选择一个礼盒,选择后任务卡片就会飞出来。玩家认可后,即可开始倒计时,去完成任务,任务成功结束后,就会显示出玩家获得的奖品。

逻辑很简单,但效果却很不错,值得推荐。

Flash垃圾回收机制的一些技巧。

     Flash垃圾回收机制是我们Flash编码人员必备的一个知识,若是不了解这玩意儿,哼哼~你就等着别人在玩你开发的应用的时候越来越卡吧……          很多人都多少在书本或者网贴上看到过有关垃圾回收机制的介绍,但是鲜有人付诸于实践,在写代码的时候常常没有这种意识,所以很多人会在QQ群里或者论坛上求助说“哎~我的应用怎么那么卡?求优化方案”之类的话。事实上,在Flash开发过程中,让画面流畅(保持高帧率且不降帧)的关键是节省CPU和内存的消耗。节省CPU消耗的关键在于算法以及使用的对象类型上的选择,而节省内存消耗的关键则在于编码方式上面,这也是有经验的程序员和菜鸟之间的差距之一。         我把Flash垃圾回收机制以一句话概括:一个对象满足垃圾回收的条件有二:1.没有其他对象保持着对其的引用;2.不存在强引用事件侦听。         光看文字自然很难领悟,让我们来看一些实例你就会懂了。 Test1:

1.private var a:Sprite = new Sprite();
2.this.addChild( a );

a不能被回收,因为对象a保持着对它所创建的Sprite对象的引用。 Test2:

1.private var a:Sprite = new Sprite();

2.this.addChild( a );
3.a = null;

a不能被回收,因为a被addChild到了this的显示列表中,因此this就保持着对a的引用,只清除了变量a对其所实例化的Sprite对象的引用却没有清除this对其的引用 Test3:

1.private var a:Sprite = new Sprite();
2.this.addChild( a );
3.this.removeChild( a );
4.a = null;

a能被回收,因为a所创建的Sprite对象不仅从this的显示列表中移除了,还释放了a对其的引用,此时没有任何变量保持着对此Sprite对象的引用了。   从上面三段代码中我们基本上可以理解第一条原则:没有其他对象保持着对其的引用的概念了。但是当你用上数组之后,往往会忽略数组对需要回收的对象的引用,一起来看接下来几个例子:   Test4:

1.private var a:Sprite = new Sprite();
2.private var arr:Array = [];
3.arr.push( a );
4.this.addChild( a );
5.this.removeChild(a)
6.a = null;<BR>

a不能被回收,因为数组arr中还保持着对a所实例化的Sprite对象的引用。为了能够成功地回收a,你还需要将a从数组中剔除:

1.var index:int = arr.indexOf( a );
2.arr.splice( index, 1 );

或者直接把数组清空:

1.arr = [];
2.//或者arr = null;

  有了上面的基础之后我们来看一个编码习惯的问题,先看下面两段代码,大家看过后告诉我哪段代码结构更佳。 Code1:

1.private var a:Sprite = new Sprite();
2.  
3.public function show():void
4.{
5.       addChild( a );
6.}

Code2:

01.private var a:Sprite;
02.  
03.public function show():void
04.{
05.        if( !a )
06.        {
07.                a = new Sprite();
08.        }
09.       addChild( a );
10.}

Code2的代码结构比Code1的好,为什么?因为变量a只在公共方法show中用到,因此,在Code1中,就算你永远没有调用过show方法,变量a所实例化的Sprite对象也一直会占据着内存(因为变量a保持着对其的引用),而在Code2中就不存在这个问题,直到需要用到a了才去实例化之。这是一个较好的编码习惯,还请列位谨记。   接下来我们看看强引用事件侦听对对象垃圾回收的影响,若是一个对象存在强引用事件侦听,则其不会被垃圾回收。看下面的例子: Test5

01.private var a:Sprite = new Sprite();
02.this.addChild( a );
03.a.addEventLitener( MouseEvent.CLICK, onClick );
04.this.removeChild( a );
05.a = null;
06.  
07.private function onClick( e:MouseEvent ):void
08.{
09.      trace("oh, shit!");
10.}

a不能被回收,因为有一个鼠标点击的侦听器在其身上。即使你将其从this的显示列表中移去并把a置为了null,你也不过是以为自己闭上眼睛看不见某个东西就以为这个东西不存在了,醒醒吧,少年,别在自己骗自己了。为了顺利回收a,你需要在把a置为null前移除其所有的事件侦听器。         但是,but,如果你为需要回收的对象添加的事件侦听器为弱引用的话就可以顺利地让对象被回收掉。如何设置事件侦听器为弱引用?设置addEventListener方法的最后一个参数为true即可。

 

01.private var a:Sprite = new Sprite();
02.this.addChild( a );
03.a.addEventLitener( MouseEvent.CLICK, onClick, false, 0, true );//保持第三、四个参数为默认值,设置第五个参数为true
04.this.removeChild( a );
05.a = null;
06.  
07.private function onClick( e:MouseEvent ):void
08.{
09.      trace("oh, shit!");
10.}

a能被回收,因为没有变量保持着对a所实例化的Sprite对象的引用,且其身上也不具备强引用事件侦听器(由于addEventListener方法最后一个参数被设置为true,因此为a注册的鼠标点击事件侦听器为弱引用)。但是,虽然弱引用事件侦听器不会妨碍对象的垃圾回收,但是回收速度会被大大减慢,毕竟若引用事件侦听器也是在侦听事件,它肯定得等待一阵子发现没有动静后才会认为其宿主对象已无用,再去回收。综上所述,若是你的确用不到一个对象了,就手动调用removeEventListener去移除它的全部事件侦听器吧。         需要注意的是,事件侦听器越多越是影响性能,因此对于一些仅使用一次的事件侦听器,及时移除是个很好的习惯,就像下面两段代码: Code1:

01.package 
02.{
03.    import flash.display.Sprite;
04.    import flash.events.Event;
05.      
06.    public class Test extends Sprite
07.    {
08.        public function Test()
09.        {           
10.            addEventListener(Event.ADDED_TO_STAGE, onAdded);
11.        }
12.          
13.        private function onAdded( e:Event ):void
14.        {
15.            removeEventListener(Event.ADDED_TO_STAGE, onAdded);
16.            init();
17.        }
18.          
19.        private function init():void
20.        {
21.            //init something
22.        }
23.    }
24.}

Code2:

 

01.package 
02.{
03.    import flash.display.Bitmap;
04.    import flash.display.Loader;
05.    import flash.display.LoaderInfo;
06.    import flash.display.Sprite;
07.    import flash.events.Event;
08.    import flash.net.URLRequest;
09.      
10.    public class Test extends Sprite
11.    {
12.        public function Test()
13.        {           
14.            var loader:Loader = new Loader();
15.            loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onComp);
16.            loader.load(new URLRequest("pigdogwc.jpg"));
17.        }
18.          
19.        private function onComp( e:Event ):void
20.        {
21.            var loaderInfo:LoaderInfo = e.currentTarget as LoaderInfo;
22.            loaderInfo.removeEventListener(Event.COMPLETE, onComp);
23.            var bmp:Bitmap = loaderInfo.content as Bitmap;
24.        }
25.    }
26.}

我们看到,那些比较流行的事件,如添加到舞台事件(ADDED_TO_STAGE),加载完成事件(COMPLETE)事实上都是只用一次的事件,在触发事件后我们就可以毫无顾忌地移除事件侦听器了,这是一种良性循环,不会造成内存的不断堆积却找不到问题根源。         有同学会担心一个问题,就是当一个类A中的某一个变量被外部保持着引用,如果该变量没有被回收的话会不会牵连到整个A对象都不能被回收呢?具体代码如下:

01.package
02.{
03.    import flash.display.Sprite;
04.  
05.    public class A extends Sprite
06.    {
07.        public var aa:Sprite=new Sprite();
08.    }
09.}<BR type="_moz">

 在类A中声明了一个aa的Sprite变量,那么在类B中会保持着对其的引用:

 

01.package
02.{
03.    import flash.display.Sprite;
04.      
05.    public class B extends Sprite
06.    {
07.        private var a:A;
08.        private var b:Sprite;
09.          
10.        public function B()
11.        {
12.            a = new A();
13.            b = a.aa;
14.            a = null;
15.        }
16.    }
17.}

       此时,如果将a置为空,但是由于B中的一个变量b保持着对A.aa变量的引用的话会不会造成a不能被回收呢?答案是否定的,a可以被回收,但是它的aa变量实例化的那个Sprite对象被保留了下来,存于B.b中。若是在外部没有一个类保持着对A.aa的引用的话,它也会跟着它生父——a一起离开人世……          要构建一个结构良好的项目并非易事,尤其是刚搞开发不久的新人缺乏经验,就很容易出现一些严重问题,如内存溢出。为了活用刚才上面介绍的垃圾回收机制,我们在项目开发中需要注意哪些编码习惯呢?         首先,避免开放过多的复杂对象为共有静态对象,开放过多共有静态对象会造成的一个问题是,这个共有静态对象由于可以在项目中任何类中访问,则会被这个类加点东西,被那个类减点东西,到最后你自己都不知道该对象到底被外部哪些对象保持着引用,也不知道到底被外面的对象访问并添加了多少个事件侦听器,以至于垃圾回收成为了难以完成的使命。比如,存在一个单例类MyModel,其中有一个共有变量a,类型为Sprite:  

01.package
02.{
03.    import flash.display.Sprite;
04.     
05.    public class MyClass extends Sprite
06.    {
07.        public static var a:Sprite = new Sprite();
08.         
09.    }
10.}

 a被开放为共有静态变量,则有可能你在类C,D,E中都存在一个变量或多个变量持有MyClass.a的引用,如

01.package
02.{
03.    import flash.display.Sprite;
04.     
05.    public class C extends Sprite
06.    {
07.        public static var c:Sprite = MyClass.a;
08.    }
09.}

C 类中存在一个变量c持有了MyClass的a变量的引用,类D、E中也存在类似写法,声明了一个或多个变量一直持有着对MyClass.a的引用,那么当你想回收MyClass.a对象的时候你很容易清理不干净外部的全部对a的引用,比如你把C、D中对MyClass.a的引用置为了null,却忘记了处理E,只要存在任一个对MyClass.a的引用,其就不会被垃圾回收。因此我们在项目开发过程中必须注意开放成静态变量的对象的数目,且心中一定要清楚地知道所有对静态变量的引用的地方,以便日后清理。          要清理所有的事件侦听,我有一个比较好的办法,就是每次调用一个对象的addEventListener方法时把添加的事件侦听器记录起来,日后若要移除全部事件侦听只需要把全部记录着的侦听器遍历一遍,一次移除干净即可:

01.package
02.{
03.    import flash.display.Sprite;
04.     
05.    public class Test extends Sprite
06.    {
07.        /** 记录所有事件侦听器 */
08.        private var _eventListeners:Object;
09.         
10.        public function Test(){}
11.         
12.        override public function addEventListener(type:String, listener:Function, useCapture:Boolean=false, priority:int=0, useWeakReference:Boolean=false):void
13.        {
14.            super.addEventListener(type, listener, useCapture, priority, useWeakReference);
15.             
16.            if( !_eventListeners )
17.                _eventListeners = new Object();
18.             
19.            //将添加的事件侦听器侦听事件类型以及事件处理函数保存起来
20.            _eventListeners[type] = listener;
21.        }
22.         
23.        override public function removeEventListener(type:String, listener:Function, useCapture:Boolean=false):void
24.        {
25.            super.removeEventListener(type, listener, useCapture);
26.             
27.            if( _eventListeners && _eventListeners[type] )
28.            {
29.                delete _eventListeners[type];//删除该侦听器记录
30.            }
31.        }
32.         
33.        /** 移除全部事件侦听器 */
34.        public function removeAllEventListener():void
35.        {
36.            for(var event:String in _eventListeners)
37.            {
38.                removeEventListener(event, _eventListeners[event]);
39.            }
40.        }
41.    }
42.}

这段代码应该多少能给你一些启示。不过有少数时候我们可能会给同一个事件添加两个事件侦听器:

1.a.addEventListener( MouseEvent.CLICK, onClick1 );
2.a.addEventListener( MouseEvent.CLICK, onClick2 );

那么这样子的话用上面那重载了的addEventListener的代码就无法记录全所有的事件侦听器了,因为在一个Object对象中,一个键只能对应一个值,当第一次调用addEventListener方法后,_eventListeners[MouseEvent.CLICK] 属性的值等于 onClick1 这个方法,但是第二次调用addEventListener方法后该属性值就会改成onClick2这个方法了,此时onClick1这个侦听器就被漏记录了。因此,我们需要改写一下记录方式,使用数组来记录全部的事件侦听器:

01.package
02.{
03.    import flash.display.Sprite;
04.     
05.    public class Test extends Sprite
06.    {
07.        /** 记录所有事件侦听器 */
08.        private var _eventListeners:Object;
09.         
10.        public function Test(){}
11.         
12.        override public function addEventListener(type:String, listener:Function, useCapture:Boolean=false, priority:int=0, useWeakReference:Boolean=false):void
13.        {
14.            super.addEventListener(type, listener, useCapture, priority, useWeakReference);
15.             
16.            if( !_eventListeners )
17.                _eventListeners = new Object();
18.             
19.            //将添加的事件侦听器侦听事件类型以及事件处理函数保存起来全部事件侦听函数
20.            //都保存在一个数组中,这个数组可以通过_eventListeners[事件类型]来访问
21.            if( _eventListeners[type] == null )
22.            {
23.                _eventListeners[type] = new Array();
24.            }
25.            //防止重复
26.            if( (_eventListeners[type] as Array).indexOf(listener) == -1 )
27.            {
28.                _eventListeners[type].push(listener);
29.            }
30.             
31.        }
32.         
33.        override public function removeEventListener(type:String, listener:Function, useCapture:Boolean=false):void
34.        {
35.            super.removeEventListener(type, listener, useCapture);
36.             
37.            //查询需要移除的事件类型对应侦听器是否存在,若存在则从记录中移除
38.            if( _eventListeners[type] != null )
39.            {
40.                //查询欲移除的侦听函数是否存在于记录中,若存在则移除
41.                var index:int = _eventListeners[type].indexOf( listener );
42.                if( index != -1 )
43.                {
44.                    _eventListeners[type].splice( listener, 1 );
45.                    //若一个事件的全部侦听器都移除完毕,则在记录本中将记录该事件的数组移去
46.                    if( _eventListeners[type].length == 0 )
47.                    {
48.                        delete _eventListeners[type];
49.                    }
50.                }
51.            }
52.        }
53.         
54.        /** 移除全部事件侦听器 */
55.        public function removeAllEventListener():void
56.        {
57.            for(var event:String in _eventListeners)
58.            {
59.                for each(var listener:Function in _eventListeners[event])
60.                {
61.                    removeEventListener(event, listener);
62.                }
63.            }
64.        }
65.    }
66.}<BR>

flash游戏开发者需牢记玩家才是最终服务对象

如果你是在电子游戏产业中做事,那么你的工作目标应该是尽可能多地娱乐别人,而你所做的一切也应该依据对方的反应而得到评价。你需要知道玩家是你真正需要在乎的支持者:你所做的一切都应该让他们感到开心,如果他们不满意你的游戏,那么你的工作将会变得异常艰难,而如果他们喜欢你的游戏,你也会因此得到好处。

根据这种描述,玩家难道不就是一个急躁善变的老板形象?准确地说,如果你是这个产业中的一份子,那么你就不再是为了经理,CEO或者股东而工作,相反地,你必须去努力迎合玩家,真正为了他们而工作。

这听起来好像有点模糊,所以我想要在此详细描述这一观点的实际意义,以及为何我们要将其牢牢记在心里。首先,玩家,作为一个群体其实并不需要精通一款游戏所需要的所有原则:他们不需要知道如何设计游戏,如何平衡游戏,如何完善游戏,如何销售游戏以及如何让游戏变得有趣。你不需要让玩家做出这些决策,而是你应该全权承担起这些任务。

植物大战僵尸(from next-gen)
玩家擅长什么?

对于玩家来说,他们真正擅长的是享乐,快速理解一款游戏设计是否适合于自己。但他们的技巧却不只这些。经过验证,玩家同样也擅于判断游戏什么时候取悦了自己,欺骗了自己,利用了自己或者未公平地对待自己。总的来看,玩家扮演着一个熟练的经济学家角色,精通于评估自己能够从游戏中获得多少价值,并与他们所投入的时间,情感或金钱进行价值比较。

从传统意义上来看,这种等式总是很明确:当游戏进入市场开始说服玩家的时候总是会面临一道很高的门槛(游戏邦注:这里指价格因素),而如果开发者能够提供品牌价值,进行市场营销,发布新闻报道或者有效的游戏预告片,那么这道门槛将会有所降低。一旦玩家打算尝试游戏,并愿意为游戏投入自己的血汗钱,那么他们一定需要有足够的财政投入和情感投入才能保证自己可以掌握游戏技巧,并享受到游戏乐趣。如果开发者能够在游戏开发中多投入点时间,从而提高游戏吸引力,并让它变得更加优秀,提供给玩家难以忘怀的体验,那么这定是一个非常棒的作品,而玩家也会因此期待它的续作。

长期研究证明,这些观点都是正确的,但是我们同样也必须清楚,我们现在正生活在一个完全不同的时代里:在这个时代,玩家处在一个充满各种游戏的平台中,并且能够在游戏中频繁地进行交流,而且很多游戏都会免费为玩家提供部分内容。玩家之前是希望先付钱再玩游戏,现在他们却是希望先免费试玩,再判断游戏是否值得掏钱。除此之外,玩家的注意力也越来越有限,他们很容易分心,除非你已经建立起知名的品牌或者良好的声誉,不然很难让游戏获得玩家关注。无论如何,你都必须在一开始与玩家进行交流之时就向玩家明确地传达游戏的质量和“乐趣因素”。特别是在手机设备中,第一分钟的游戏体验是决定用户粘性和留存率的最关键时刻。

正确的起步

因此,制作出能让玩家感到有趣的首次体验变得非常重要,而这也是PopCap多年来一直在实践的一个观点。这也许是受到传统休闲游戏“先试后买”模式的影响,玩家可以在一个有限的时间内去尝试游戏并做出评判,然后决定是否购买游戏,但是在这里也有一些不同之处:你必须意识到现在的玩家也有许多选择,所以如果玩家愿意选择你的游戏,你就必须确保他们能够在游戏的前几分钟体验后便真正认可你的游戏。

在一开始便提供给玩家有趣的游戏体验非常重要,并且必须渗透到你的所有工作,且清晰地体现在你的游戏,你的营销信息,以及你所传达给玩家的态度中。如果你始终牢记自己是在为玩家效力,那么你将会努力地为他们创造出最优秀的产品,最大限度地为他们服务,清晰明确地向他们传达信息,并适当地给予他们支持。这其实是一件再简单不过的事了,所以你必须随时提醒自己,如此你才能够制作出最易亲近,且通俗易懂的有趣游戏。同时你还需要记得,如果游戏出现了错误,那这一定是你的问题,而不是玩家“不理解游戏”。

在这个过程中,如Facebook或者应用商店等发行平台扮演着一个很重要的角色,能够帮助游戏获得更多玩家,并且这些平台同时也为游戏提供了一个充满竞争的环境,让它们必须费劲心思才能够吸引玩家们的注意。同时,这些平台中还有许多收集和分析游戏数据的功能,如果你们能够合理使用的话,将能够更好地了解玩家在做什么,以及玩家对游戏的看法,而因此能够更好地完善并优化游戏体验。但是不管怎样,最重要的是你的游戏首先必须是有趣且具有独特的吸引力,因为缺少了这点,所有的一切也就不再有意义。

建立长期关系

一旦玩家决定花时间去玩你的游戏,建立玩家与游戏之间的长期关系就变得更加重要了,因为事实上,忠实的玩家会向好友宣传你的游戏,成为游戏的最佳宣传者,而且因为获取玩家的费用较高,所以一旦你获得了玩家,就一定要想方设法留住他们。最重要的是,培养信誉对于游戏最后的成功非常关键,包括建立坚实的品牌意识和良好的信誉。从玩家的角度来看,人们最讨厌的就是被欺骗或者受到非公平的待遇,所以你在游戏开发过程中应该尽可能地避免这些因素。如果能做到这一点,你不仅能够高枕无忧,也能够因此建立起稳定持久的用户关系了。

总括来说,以玩家为中心的视角看问题要求你的游戏必须能够立刻体现出游戏乐趣,能够在游戏的第一分钟便吸引玩家的注意,容易理解(尽管不一定容易精通)并且能够为玩家带来真正的价值。你同样也要努力去满足玩家这个苛刻老板的要求,虽然你难以预见他们的喜好并且不是很了解他们。听起来很难?的确,但是制作一款优秀游戏哪有那么容易?

转自 游戏邦

flash 游戏中适当限制“滑坡效应”可增强玩家游戏体验

游戏中的“滑坡效应”是指当你落后时,你还会因此落到更后面;遭受损失时,这个损失还会继续对你造成伤害。(有点像“雪上加霜”的意思。)

比如,篮球赛游戏中,每当一方得分时,另一方则损失一名队员。在这里,落后的损害是双倍的,一是每次投篮都是计分的,二是落后方更加不可能得分。尽管现实的篮球赛并没有这个别扭的特征,所以真正的篮球赛中并不存在“滑坡效应”。在现实的篮球赛中,得分只是让你更接近胜利,但完全不会损害对方的得分能力。

“滑坡效应”的另一个名称是正反馈,就是一个扩大自身效应的环路。因为人们总是很容易就混淆正反馈与负反馈,所以我更倾向于称之为“滑坡效应”。

滑坡效应在游戏中造成的结果通常是不好的(游戏邦注:当然,这是对对“滑坡方”而言)。如果游戏的滑坡效应太过强大,这意味着当一名玩家稍微领先一点,他就更可能离最终的胜利再进一步,再再进一步。像这样的游戏,赢家其实早有定数,无论你是玩家还是看客,游戏的过程基本上是多余的。

《星际争霸》和象棋中确实存在滑坡效应,但撇开这个消极属性不提,这两者都是好游戏。在象棋中,玩家损失一个棋子,他的攻击能力、防御能力和控制能力都会稍逊一筹。当然,象棋中还有其他许多因素——定位、势头、布阵等,决定着玩家到底是不是“失败”,当然损失一枚棋子也确实产生了一定的效应。显然,损失太多棋子,比如8个,玩家就彻底处于劣势了。要赢回来简直是猴子捞月了。所谓的胜利,其实是“赢”了很多、很多步,最后来一个“致命一击”的累积效应。

这就是为什么象棋中存在那么多惩罚。如果意识到对方最终会赢,好玩家其实不会再作无谓的挣扎。象棋玩家认为游戏存在这种经常性惩罚很好,没什么不合适,但与不存在滑坡效应的游戏相比,这是个令人扫兴的特点。但不论如何,象棋仍然是一种好游戏。

《星际争霸》中也有滑坡效应。当你损失一个单位时,你受到的是双重打击。第一,你离最终的失败更近一步了(完全没有单位事实上相当于损失了所有建筑);第二,你更难进攻和防御,因为你不仅损失了得分,用于进攻和防御的单位也减少了。

在篮球赛中,得分与玩法完全是分离开的。你的得分能力并不取决于当前的得分。无论你是领先20分还是落后20分,再次得分的机会都是一样的。在《星际争霸》(和象棋)中,得分与玩法密切相关。损失一个单位意味着离失败更近一步,并且更难反击。

说到游戏的经济系列方面,《星际争霸》的滑坡效应表现更为明显。假设对方提前进攻你,你hold住了。其他方面损失不相上下,但你还多损失了一个生产单位。放到其他游戏中,这大约就相当于落后一分。但在《星际争霸》里,后果就严重多了,因为采矿量的增长接近于指数型,你的对手在资源上只领先你一个生产单位,收益就比你翻了好几番。在你损失那个生产单位起,你就已经在斜坡上往下滚了,此时的劣势效应正在无限放大。

格斗游戏

格斗游戏中一般不存在滑坡效应。比如在《街霸》中,你的角色即使只剩一口气了,仍然行动自如。被打中只是让你的命值(得分)受损,但并不会限制你的行动选择,这点和象棋中损失一个棋子或在《星际》中损失一个工作单位造成的恶果是不一样的。《武士之刃》中倒是意外地存在滑坡效应。在游戏中,被打中腿,玩家就会行走蹒跚;被打中手臂,可能那手臂膊就算是残了。这在格斗游戏中是极为罕见的。

虽然,从现实一点的角度讲,快死的角色也是可能慢慢地爬着,至于能爬多远就另当别论了,但这样的游戏也太没意思了。(游戏邦注:至少在《武士之刃》中,这部分会持续数秒钟,然后你才挂掉。)在《街霸》中,复原是很频繁的,所以所有玩家都能“笑到最后”。其实《街霸》中还是存在一点点滑坡效应的(如果你气数将近,你肯定很担忧被堵在角落,而当你的血条全满时,你从来不担心这个),但总的来说,这是个中性的滑坡效应。

有一款格斗游戏因为是个例外而显得格外突出,它就是《Marvel vs. Capcom 2》。在这款游戏中,各名玩家选择3名角色。在任意给定的时间内,屏幕是只出显一名可活动的角色,其余二名则在屏幕之外的地方恢复受损的精力。玩家可以召唤屏幕之外的角色来辅助主角色,之后再切换屏幕。主角色可以与辅助角色一起发动攻击,从而丰富进攻策略和技巧。玩家可以任意转换活动角色,但如果他已经损失了所有角色,就算是失败了。在这里,滑坡效应就出现了。当玩家只剩最后一个角色时,而其对方仍然有两个甚至全部角色无损,那么前者就明显处于下风。玩家的当前角色没有办法得到辅助攻击,胜算可谓微乎其微。恢复在这款游戏中相当少,游戏往往在玩家“技穷”以前就结束了。

带有“出圈即败”设计的格斗游戏,如《Virtua Fighter》和《Soul Calibur》就尤其不具有滑坡特征了。在这些游戏中,如果一名玩家的角色被推出圆圈,则玩家马上失败,无论此时角色的血条还有多长。从根本上说,无论你目前落后对手多少、无论你的血条还有多少,出了圆圈对你的造成的伤害都是100%的。很久以前,我曾认为这个概念并不高明,除了速战速决,不见得有什么好处,但事实上,“出圈即败”的危险给游戏加分不少。因为“出圈即败”的危险度太高了,无形中给游戏增加了一个“定位”的玩法;也就是,玩家必须在打击对手的同时稳住自己的位置,以免被推出圆圈。

有限的滑坡效应

格斗游戏的滑坡效应范围非常小、非常有限,这对格斗游戏来说是一个优良的特点。如果游戏在任何时候都不存在滑坡效应,那么各个环节之间可能会让人觉得比较脱节。虽然,如果你做出的决定始终会引发某种结果,进而影响到后面的游戏,那样会比较有趣。但问题是,如果这种影响发展成了“滚雪球”呢?

在受限的滑坡效应中,你能“滑”多远存在上限,造成的后果也是暂时的。在《街霸》中,被击倒了确实会引发一点滑坡效应。你的命值(得分)受损,同时,角色的活动受到短暂的限制。角色摔倒,显然是劣势情况。这里我们要注意到两点:1、击倒结束后,你恢复所有动作;2、你不能进一步被击倒。


图中的Ken被击倒了,暂时处于下风,但这个劣势不会像滚雪球一样越滚越大。

将对手击倒的影响确实在后面体现出来了,但这个优势很快就被重新组合,不会再“滚雪球”了,因为不存在“进一步击倒”对手这种事。如果你已经摔倒了,你当然不可能“再摔倒”。

另一个例子是把对手逼到角落(游戏界面的边缘)。如果你这么做了,你就占据了“地利”,因为对手的行动受限了。但还是存在一个限度——一旦对手被逼到角落了,他不可能再被逼进“角落的角落”了。对手所处的劣势程度是有限度的。

再举一个更直接的例子,任何时候你采取阻挡动作,你就得到一定的复原量。此时,你的恢复速度会领先于正在进攻的对手,所以在下一次进攻时,你在时间上有可能先出手。这是你的优势,因为如果你们双方都打算发动相同速度的进攻,你的角色会赢(因为它会先行动)。你的阻挡动作的成效就在这里表现出来了,但这个效益是转瞬即逝的,可能仅仅过了一秒,优势就不复存在了。

所以,格斗游戏中充满了小型滑坡效应,这确实给游戏增添了乐趣。但从宏观的角度看,这些不算真正意义上的滑坡效应,因为其效果不会像滚雪球般随着游戏进程渐渐变大。与象棋相比,相当于你是在几个回合后就把失去的棋子拿回来了。

没有滑坡效应的RTS

这里我有一个想法,就是把完全的滑坡效应(通常是恶性的)变成有限的滑坡效应(通常是良性的)。双方玩家一开始均持有相当的资本去购买单位。当你的单位被摧毁后你的资本就会得到偿还。一方面,偿还需要一定的时间,另一方面,重新生产新单位需要一定的时间,这两方面意味着损失单位确实产生了消极影响,但这种劣势会渐渐消失,这与格斗游戏中的被击倒是一样的。即时策略游戏《World in Conflict》正是这么做的,不过我本人没有玩过。

我说这些的目的不是评判《World in Conflict》这款游戏好不好,或者讨论上述的“恢复系统”可取不可取。我只是想表明,如果你能努力研究一下,消除RTS中的滑坡效应还是可能的。那些非常乐衷于此的人可能会想出更高明的解决方案吧,然后一款更高深的游戏就此诞生。

为南京房地产网 house365开发的flash版的webcad

因南京房地产(house365.com)网站的巨无霸的开发需求,我们为其开发了这款在线的webcad。用户可在线上传房产图,并且在房产图上做简易的修改,并且可将配置好的家装图形放置到房产图上,并能对颜色,位置,角度等进行修改;最终可输出绘制好的图形,作为客户的参考。该系统方便简单,对那些并没有多少家装专业知识的客户,帮助很大。客户方对该系统的成功开发并上线运行后的效果,表示非常满意。

在线演示地址

为什么我的网站做的那么难看,为什么不如别人的好看?

经常会遇到客户会抱怨,网站为什么那么难看,为什么做的不如别人的好。

尽管设计师投入了很多热情和想法,但最终的产品还是和客户的预想有差距,甚至差距很大,尽管客户在初稿的时候,已经满意了,但在最终的产品上,总也找不到当初需求迸发时的快感。

抛除设计师设计的缺陷和前端工程师在细节的处理能力问题外,我发现客户在参与网站前期开发策划的工作中的贪全冒进、以及对网站后期内容管理能力不足也是导致客户对最终产品不满的重要因素。

很多客户都希望自己的网站大而全,为了让网站看起来丰满充满生机,也为了减少后期开发的成本,尽可能的将网站开发的成本用到极致,所以在前期策划中,就将自己所有的产品以及未来的产品规划都一股脑的展现到自己的网站上,在前期设计中,设计师可以用美好的图片来妆点页面,但在网站上线的时候,却发现很多商品或者内容都还没整理好,这使网站出现很多空白区域,或者同一个产品图片重复出现,自然影响了整体效果;甚至有的时候初期规划的栏目和板块,因为在制作过程中,发现不合适,或者产品线突然有问题,无法展示,而匆忙更换,也导致了网站的界面设计和产品设计出现问题,最终的效果当然会出现偏差。

在这样的情况下网站,网站效果将会与建设双方预想的结果,会折损百分之20左右。当网站内容需要更新的时候,客户团队里的内容管理和图片设计的能力的问题又凸显出来。更新的文章,无论是标题处理和是内容选编上,都和客户的想法有差距;客户的产品图片在修改和编辑的效果上,也是参差不齐,直接影响了网站的展示效果。

网站最终的建设的效果好坏,应该是承建方和发起方共同努力的结果。可客户往往会将责任推卸到承建方,当然,承建方在设计制造网站的经验方面,也对结果有很大的作用。

前期规划方案的时候,就应该深入到企业内部,研究企业组织架构和产品线,对网站的设计要有慎重认真的态度,对栏目模块的设计要反复比对公司的真实数据。当然在报价方面也应该考虑到客户的多而全的心态,在力保项目健康发展的前提下,要多方面的提供合适客户心态的建设方案,要向客户传递合理建站的理念。

对于客户的技术团队,也应该进行必须的评估,对未来网站更新效率的情况,要向客户做风险预知。并且建议客户做一点的改善工作,比如:1、承担维护工作2、培训客户的技术团队3、调整网站的维护工作量减少维护工作。

网站制作,犹如家庭装修,需要从头至尾,双方都要深入的沟通分析,对房屋和网站都要做慎重思考和规划,任何一方,任何一步出现设计误差,都会影响最终的结果。