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

发布于 2024-09-25 19:25:13 字数 1193 浏览 1 评论 0原文

我想找到一种方法,只允许某些对象进入其类名中具有特定单词的数组。或者至少找到做这样的事情的最佳方法。这是详细信息。我有一个数组,用于存储放入购物车的所有对象。

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

例如,如果我放下一个 [object BreadGrain] 和一个 [object PastaGrain]。

trace(myCart.itemsInCart);// 将跟踪 [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); } 别的 { //这里是错误信息代码 。

我很困惑 即使只是一句“伙计,你做错了”也会有帮助。谢谢。

I want to find a way to only allow certain objects into an array that have a certain word in thier class name. Or at least find the optimal way of doing something like this. Heres the details. I have an Array that stores all the objects dropped into a cart.

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

If, for example, I drop an [object BreadGrain] and a [object PastaGrain].

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

Easy, no problems there. But what do I do if I only want to allow 2 objects with "Grain" in their Classname into the array? I want to do this so that the user can only drop 2 of each type of food into the 'cart'. The types of food are Grain, Fruit, Vegetable, Meats etc and I've appended the type of food to the end of the Classname, hopefully so that I can use it to detect what type of food it is and stop it from being added over the limit as well as displaying an error. i.e "You already have 2 Grain products".

I hope that makes sense. Anyway, i've found that works well to a degree:

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

BUT I have several products and I don't want to have to write a if/else or switch statement for them all. I was hoping to do this dynamically with something similar to:

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

myCart.itemsInCart.push(currMC);
} else {
// error message code here
}

I'm stumped. Even just a "Dude, you are doing this all wrong" would help. Thanks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

碍人泪离人颜 2024-10-02 19:25:13

您可以使用 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 的对象,您将收到编译时错误。

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

You can get the class name of any object with the getQualifiedClassName function. Then you could try to match strings agains a certain pattern, with a RegExp or you could also just check if the class name contains some substring.

That said, I think a better approach could be using either a common base class or an interface.

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

    public function Grain() {
        super();
    }

    public function someCommonMethodToAllGrains():void {

    }
}

or

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

Then, if you went with the base class:

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();
    }    
}

Or, with the interface

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 {

    }    
}

If these objects are MovieClips, perhaps it's less tedious to use a base class, because otherwise you'd have to cast your objects back to MovieClip (or DisplayObject) any time you want to add them to the display list (or remove them). By the way, that's because someone at Adobe forgot to include an IDisplayObject interface and have the display list API accept objects that implemented this interface instead of a half-assed abstract class that you can't derive directly anyway (a.k.a. DisplayObject); this would have make it easier to treat display objects as interfaces, but I digress).

Anyway, either with an interface or a common base class you could do your validation with the is operator, but you'd just have to check for one type: Grain.

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

You could also take this further and use a Vector instead of an Array. A Vector works almost the same as an Array, but it's strictly typed, so you could do:

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

You'll get a compile time error if you try to add an object that does not extend/implement Grain.

Vectors are available for Flash Player 10 and you'd need Flash CS4, though (if you're using the Flash IDE; otherwise, I think you'd need at least the 3.2 SDK to compile).

绝影如岚 2024-10-02 19:25:13

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

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

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

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

Hm. I think you're going to need something a bit more complex to make this work properly. You're actually asking a two-part question: how to keep track of stuff, and how to identify stuff. I'll start with the easy bit, keeping track.

DISCLAIMER: My AS3 is pretty rusty, but at least the theory should be sound, even if the implementation might be a bit off.

First, you'd want to define the limits for each type of food, thus:

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

Then, you want to keep count of objects you're adding to your cart

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

Then, when you add a new object, first check its type against the relevant count. If the counter is less than the limit, let it in and increment the counter:

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

You'll notice that I've created an imaginary function, getFoodTypeForObject(). This is the trickier bit: identification.

You could implement your example logic like so:

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

Where classNameContainsTheWord is achieved with a combination of getQualifiedClassName and indexOf, but better would be to use a common base class, as suggested by Juan Pablo Califano. I'd suggest a slightly different style though:

public class CartItem extends MovieClip{

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

    public function CartItem() {
        super();
    }
}

use that as the base Class for your cart item MCs, then set those boolean properties on the instances of MCs on your stage. Then, you can detect the type of something like this:

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

Cleaner than all that classname business, and has the added benefit that you can set something's properties independent of its class name.

It's not perfect; for instance, you'd need something more advanced if you needed a lot of properties, but it should be enough for you to keep going.

踏雪无痕 2024-10-02 19:25:13

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

我已经成功了。我使用了胡安·巴勃罗·卡利法诺的方法。我最初确实使用了 Henry Cooke's,因为我想摆脱为每种食物制作一个 .AS 文件(即 apple.as、grays.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[ 类型 ] < foodTypeLimit[ 类型 ] ){
items.push( currMc );
foodTypeCount[类型]++;
} 别的 {
// 抛出错误
}

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

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

不管怎样,感谢你们提供了非常好的答案,这是我最喜欢的网站,可以找到生命、宇宙和一切的答案。

Uni had me doing other stuff for a while but finally I can get back into my game project.

I've got it working. I used Juan Pablo Califano's method. I did initially use Henry Cooke's because I wanted to get away with making a .AS file for each food (i.e. apple.as, cereal.as, bread.as, oranges.as). With Henry Cooke's method I created a

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

And var foodTypeCount:Object = new Object();
etc etc
`

For each food type. Then used the:

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

As suggested. The function returned the string and viola it worked fine. However because my foodTypeCount variables (for example foodTypeCount["grain"]=0;) was inside the function, every time the function called these were set to 0 so the increment never got above with each call. So I thought, ok, i'll put these foodTypeCount variables outside of the function along with the instantiation of the var foodTypeCount:Object = new Object(); BUT NO, I kept getting the:

Error #1120: Access of undefined property foodTypeObject.

Even though it was right under the freakin declaration. I get i'm just too noob to understand why this is so. Anyway, for this reason (the lack of incrementation, which was essential to this function) I bit the bullet and used Juan Pablo Califano's way.

First I wrote out the classes like so:

public class Bread extends MovieClip implements Grain {

public function Bread() {
    super();
}

public function someCommonMethodToAllGrains():void {

}

}

And then added the interface

`public interface Grain {

    function someCommonMethodToAllGrains():void;
}
`  

And now my function looks something like this:

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";
 }

I tried to put all this into a switch. For example:

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

The above implementation didn't work. Perhaps switch statements probably aren't meant to be used that way. idk. :S

Anyway, thanks for the really great answers guys, this is my favorite site to come to for answers to life the universe and everything.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文