AS3:只允许某个类型的对象进入一个数组

时间:2010-10-01 02:02:58

标签: arrays actionscript-3 if-statement classname

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

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]

容易,没有问题。但是,如果我只想在其Classname中允许2个带有“Grain”的对象进入数组,该怎么办?我想这样做,以便用户只能将每种类型的食物中的2种放入“购物车”中。食物的种类是谷物,水果,蔬菜,肉类等,我把食物的类型添加到了Classname的末尾,希望这样我可以用它来检测它是什么类型的食物并阻止它被添加超过限制以及显示错误。即“你已经拥有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);                 } else {                    //这里有错误消息代码                 }

我很难过。即使只是一个“伙计,你这样做是错的”会有所帮助。感谢。

3 个答案:

答案 0 :(得分:2)

您可以使用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)您想将它们添加到显示列表(或删除它们)。顺便说一句,那是因为Adobe的某个人忘了包含一个IDisplayObject接口,并且让显示列表API接受实现此接口的对象,而不是无论如何都无法直接派生的半抽象类(aka { {1}});这样可以更容易将显示对象视为接口,但我离题了。

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

is

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

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

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

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

答案 1 :(得分:0)

嗯。我认为你需要更复杂的东西来使这项工作正常进行。你实际上问的是一个由两部分组成的问题:如何跟踪内容,以及如何识别内容。我将从简单的位开始,跟踪。

免责声明:我的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" );
    }
    ...
}

使用classNameContainsTheWordgetQualifiedClassName的组合实现indexOf,但更好的方法是使用一个共同的基类,正如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" );
    }
    ...
}

比所有classname业务更清洁,并且还有一个额外的好处,即你可以设置一些独立于其类名的属性。

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

答案 2 :(得分:0)

Uni让我做了一段时间的其他事情,但最后我可以回到我的游戏项目。

我已经开始工作了。我使用了Juan Pablo Califano的方法。我最初使用的是Henry Cooke,因为我想为每种食物制作.AS文件(例如apple.as,cereal.as,bread.as,oranges.as)。用Henry Cooke的方法我创建了一个

`var foodTypeLimit:Object = new Object(); foodTypeLimit [ “颗粒”] = 2; foodTypeLimit [ “水果”] = 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(); 但是没有,我一直得到:

Error #1120: Access of undefined property foodTypeObject.

即使它是在freakin宣言下是正确的。我觉得我太老了,不明白为什么会这样。无论如何,由于这个原因(缺乏增量,这对于这个功能是必不可少的)我咬了一口子弹并使用了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语句可能并不意味着以这种方式使用。 IDK的。 :S

无论如何,感谢真正伟大的答案人,这是我最喜欢的网站来寻找宇宙和一切生命的答案。