AS3:只允许一定数量的某种类型的对象放入一个Array

Posted

技术标签:

【中文标题】AS3:只允许一定数量的某种类型的对象放入一个Array【英文标题】:AS3: Only allow a certain number of a certain type of object into an Array 【发布时间】:2011-04-19 15:52:19 【问题描述】:

我想找到一种方法,只允许将某些对象放入类名中包含某个单词的数组中。或者至少找到做这样的事情的最佳方式。这是细节。我有一个存储所有放入购物车的对象的数组。

function addProductToArray (e:MouseEvent):void currMC = (e.target as MovieClip); myCart.itemsInCart.push(currMC); trace(myCart.itemsInCart);

例如,如果我删除了一个 [object BreadGrain] 和一个 [object PastaGrain]。

trace(myCart.itemsInCart);// would trace [object BreadGrain],[object PastaGrain].

简单,没有问题。但是,如果我只想允许 2 个类名中带有“Grain”的对象进入数组,该怎么办?我想这样做,以便用户只能将每种食物中的 2 种放入“购物车”。食物的类型是谷物、水果、蔬菜、肉类等,我已将食物类型附加到类名的末尾,希望这样我可以使用它来检测它是什么类型的食物并阻止它被添加超出限制并显示错误。即“您已经有 2 个谷物产品”。

我希望这是有道理的。无论如何,我发现这在一定程度上效果很好:

if (currMC is BreadGrain) 
                myCart.itemsInCart.push(currMC);
             else 
                // error message code here 
            

但是我有几种产品,我不想为它们都编写 if/else 或 switch 语句。我希望用类似的东西动态地做到这一点:

//this is an example of the logic
if (currMC classNameContainsTheWord "Grain"  AND myCart.itemsInCart DoesNotContainMoreThan 2 Grain Objects) 

myCart.itemsInCart.push(currMC); 别的 //这里的错误信息代码

我被难住了。即使只是一句“伙计,你做错了”也会有所帮助。谢谢。

【问题讨论】:

【参考方案1】:

您可以使用getQualifiedClassName 函数获取任何对象的类名。然后,您可以尝试使用 RegExp 将字符串与某个模式匹配,或者您也可以只检查类名是否包含一些子字符串。

也就是说,我认为更好的方法是使用通用基类或接口。

//  assuming your objects extend MovieClip
public class Grain extends MovieClip

    public function Grain() 
        super();
    

    public function someCommonMethodToAllGrains():void 

    

//  It's customary to prefix interfaces name with an "I" in AS; 
//  I'm not doing it here so the code works for both a base class and an interface

public interface Grain 

    function someCommonMethodToAllGrains():void;

那么,如果你使用基类:

public class BreadGrain extends Grain 

    public function BreadGrain() 
        super();
    

    override public function someCommonMethodToAllGrains():void 
        //  if this makes sense for your object...
        super.someCommonMethodToAllGrains();    
        



public class PastaGrain extends Grain 

    public function PastaGrain() 
        super();
    

    override public function someCommonMethodToAllGrains():void 
        //  if this makes sense for your object...
        super.someCommonMethodToAllGrains();
        

或者,使用界面

public class BreadGrain extends MovieClip implements Grain 

    public function BreadGrain() 
        super();
    

    public function someCommonMethodToAllGrains():void 

        



public class PastaGrain extends MovieClip implements Grain 

    public function PastaGrain() 
        super();
    

    public function someCommonMethodToAllGrains():void 

        

如果这些对象是MovieClips,那么使用基类可能会不那么乏味,因为否则您必须在任何时候将对象添加回MovieClip(或DisplayObject)显示列表(或删除它们)。顺便说一句,这是因为 Adob​​e 的某个人忘记了包含 IDisplayObject 接口并让显示列表 API 接受实现此接口的对象,而不是您无法直接派生的半废抽象类(又名 DisplayObject );这将使将显示对象视为接口变得更容易,但我离题了)。

无论如何,无论是使用接口还是公共基类,您都可以使用 is 运算符进行验证,但您只需要检查一种类型:Grain。

if(theObject is Graing && theArray.lenght <= 2) 
    theArray.push(theObject);

您还可以更进一步,使用Vector 而不是数组。 Vector 的工作方式与 Array 几乎相同,但它是严格类型的,所以你可以这样做:

var items:Vector.<Grain> = new Vector.<Grain>();
items.push(grainObject);

如果您尝试添加不扩展/实现 Grain 的对象,则会出现编译时错误。

Vectors 可用于 Flash Player 10,但您需要 Flash CS4(如果您使用的是 Flash IDE;否则,我认为您至少需要 3.2 SDK 才能编译)。

【讨论】:

正要建议接口和向量,但你打败了我。【参考方案2】:

嗯。我认为您将需要一些更复杂的东西才能使其正常工作。您实际上是在问一个由两部分组成的问题:如何跟踪内容以及如何识别内容。我将从简单的部分开始,保持跟踪。

免责声明:我的 AS3 相当生疏,但至少理论上应该是合理的,即使实现可能有点偏离。

首先,您需要定义每种食物的限制,因此:

var dctLimits = new Object(); // not really a Dictionary, but we'll use it like one
dctLimits[ "grain" ] = 3;
dctLimits[ "meat" ] = 5;
...

然后,您要保留要添加到购物车的对象的数量

var dctCount = new Object();
dctCount[ "grain" ] = 0;
dctCount[ "meat" ] = 0;
...

然后,当您添加一个新对象时,首先根据相关计数检查其类型。如果计数器小于限制,让它进入并增加计数器:

var type:String = getFoodTypeForObject( currMc );
if( dctCount[ type ] < dctLimit[ type ] )
    items.push( currMc );
    dctCount[ type ]++;
 else 
    // throw error

您会注意到我创建了一个虚构的函数 getFoodTypeForObject()。这是比较棘手的一点:识别。

您可以像这样实现您的示例逻辑:

function getFoodTypeForObject( currMc )
    if( getQualifiedClassName( currMc ).indexOf( "Grain" ) > -1 )
    return( "grain" );
     else if( getQualifiedClassName( currMc ).indexOf( "Meat" ) > -1 )
    return( "meat" );
    
    ...

classNameContainsTheWord 是通过 getQualifiedClassNameindexOf 的组合实现的,但更好的是使用公共基类,如 Juan Pablo Califano 所建议的那样。不过,我会建议一种稍微不同的风格:

public class CartItem extends MovieClip

    public var isGrain:Boolean;
    public var isMeat:Boolean;

    public function CartItem() 
        super();
    

将其用作购物车项目 MC 的基类,然后在舞台上的 MC 实例上设置这些布尔属性。然后,你可以检测出类似这样的类型:

function getFoodTypeForObject( object )
    if( object.isGrain )
        return( "grain" );
     else if( object.isMeat )
        return( "meat" );
    
    ...

比所有类名业务更干净,并且具有额外的好处,您可以设置独立于其类名的某些属性。

这并不完美;例如,如果您需要很多属性,则需要更高级的东西,但它应该足以让您继续前进。

【讨论】:

【参考方案3】:

Uni 让我做了一段时间的其他工作,但最后我可以重新开始我的游戏项目。

我已经开始工作了。我使用了 Juan Pablo Califano 的方法。我最初确实使用了 Henry Cooke's,因为我想摆脱为每种食物制作一个 .AS 文件(即 apple.as、谷物.as、面包.as、橙子.as)。使用 Henry Cooke 的方法,我创建了一个

`var foodTypeLimit:Object = new Object(); foodTypeLimit["grain"]=2; foodTypeLimit["fruit"]=2;

还有 var foodTypeCount:Object = new Object(); 等等等等 `

针对每种食物类型。然后使用了:

var type:String = getFoodTypeForObject( currMc ); if( foodTypeCount[ type ] < foodTypeLimit[ type ] ) items.push( currMc ); foodTypeCount[ type ]++; else // throw error

按照建议。该函数返回了字符串,中提琴它工作正常。但是,由于我的 foodTypeCount 变量(例如 foodTypeCount["grain"]=0;)在函数内部,因此每次调用这些函数时都将其设置为 0,因此每次调用的增量都不会超过。所以我想,好吧,我会将这些 foodTypeCount 变量连同 var foodTypeCount:Object = new Object(); 的实例化一起放在函数之外,但是不,我一直得到: p>

Error #1120: Access of undefined property foodTypeObject.

即使它就在该死的声明之下。我知道我太菜鸟了,无法理解为什么会这样。无论如何,出于这个原因(缺少增量,这对这个函数来说是必不可少的)我硬着头皮使用了 Juan Pablo Califano 的方式。

首先我这样写出类:

public class Bread extends MovieClip implements Grain 

public function Bread() 
    super();


public function someCommonMethodToAllGrains():void 


然后添加接口

`public interface Grain 

    function someCommonMethodToAllGrains():void;

`  

现在我的函数看起来像这样:

if(currMC is Grain)
    if(grainCount<2)
        addProductToBasket();
        grainCount++;
     else 
        notAllowed("Grain");
    
 

function addProductToBasket()
    removeChild(currMC);
    basketArray.push(currMC);
    //remove listeners set mc to null etc
 

function notAllowed(foodType:String)
    error.text="Sorry but you already have 2"+foodType+"products";
 

我试图将所有这些都放入一个开关中。例如:

switch(currMC)
   case is Grain:
   //do this
   break;
  

上述实现不起作用。也许 switch 语句可能不应该以这种方式使用。身份证。 :S

无论如何,感谢你们提供了非常棒的答案,这是我最喜欢来的网站,可以找到有关宇宙生活和一切事物的答案。

【讨论】:

以上是关于AS3:只允许一定数量的某种类型的对象放入一个Array的主要内容,如果未能解决你的问题,请参考以下文章

Python只请求一定数量的字节

PHP 对象数组

如何键入属性和值均来自其他类型的对象

使用“文件”保存场景对象位置以便稍后在 AS3 中重建

[AS3]registerClassAlias的用法

计算特定区域中有多少实例(AS3 代码)