A Flash Developer Resource Site

Page 1 of 2 12 LastLast
Results 1 to 20 of 27

Thread: Help

  1. #1
    Senior Member
    Join Date
    Mar 2010
    Posts
    107

    Help

    Hello,


    Im creating a game and I need to ask a question. Ive got several classes, the Main class, character class, words class and a WordItem class.

    In the game the character needs to collect as many words as possible.

    Ive been trying to think how I would solve the problem if my character hits the words, because I want to remove the words the character hits.

    How is that possible?

  2. #2
    Will moderate for beer
    Join Date
    Apr 2007
    Location
    Austin, TX
    Posts
    6,801
    Define the problem more clearly, and post code.

    Why is the fact that it's a word relevant? Is this just asking how to detect when one instance hits another?

    What's the difference between a word (or words), and a WordItem?

  3. #3
    Senior Member
    Join Date
    Mar 2010
    Posts
    107
    Sorry that I'm not entirely clear, but thanks for answering at least!

    Ok let me explain: Im creating a game which is having a character who must collect "words" he finds in a side scrolling level. My class structure is as follows:

    Main > Character
    Main > Words > WordItem

    To clear things up about the Word class, that class is holding all words (WordItems)

    In the WordItem class I'm just describing how one word must look like (font etc)

    What I want to do is that my character needs to collect those words by taking them (hitTest) and then having the word he catches to vanish from the stage.


    I hope this is clear!


    Code:
    Main:
    Actionscript Code:
    // Actor class maken die weer character en enemy als afstammeling heeft

    package
    {
        import flash.display.Sprite;
        import flash.display.StageAlign;
        import flash.display.StageScaleMode;
        import flash.events.Event;
        import flash.events.IOErrorEvent;
        import flash.events.KeyboardEvent;
        import flash.events.MouseEvent;
        import flash.media.Sound;
        import flash.media.SoundChannel;
        import flash.net.URLRequest;
        import flash.ui.Keyboard;
       
        /**
         * ...
         * @author marciano
         */

        public class MainGame extends Sprite
        {
            private var _character:Character;
            private var _background:Background;
           
            private var _velY:int = 0;
            private var _gravity:Number = 7;
           
            private var _jumping:Boolean = true;
            private var _level:Level;
           
            private var _startSpel:Boolean = false;
            private var _beginSpel:BeginSpel;
            private var _beginSchermManager:BeginSchermManager;
           
           
            // put sounds in Array
            private var _levelSound:Sound;
           
            private const WORDS:Array = ["Astronaut", "Spelletje", "Boris", "Super Mario", "Honden Ras"];
            private var _words:Words;
            private var box:Sprite;
            private var _pause:Boolean;
           
       
            public function MainGame()
            {
                if (stage) init();
                else addEventListener(Event.ADDED_TO_STAGE, init);
               
            }
           
       
            private function init(e:Event = null):void
            {
                removeEventListener(Event.ADDED_TO_STAGE, init);
               
                makeBeginManager();
           
                makeWelcomeScreenButton();
                checkBeforeStartingGame();
               
               
               
                //stage.align = StageAlign.TOP_LEFT;
                //stage.scaleMode = StageScaleMode.NO_SCALE;
               
            }
           
            private function makeBeginManager():void
            {
                _beginSchermManager = new BeginSchermManager();
                addChild(_beginSchermManager);
            }
           
            private function makeWelcomeScreenButton():void
            {
                _beginSpel = new BeginSpel();
                addChild(_beginSpel);
               
            }
           
            private function makeSound():void
            {
                _levelSound = new Sound();
                _levelSound.load(new URLRequest("boris.mp3"));
                _levelSound.addEventListener(Event.COMPLETE, soundComplete);
            }
           
            private function soundComplete(e:Event):void
            {
                trace("sound loaded!");
            }
           
            private function checkBeforeStartingGame():void
            {
               
                _beginSpel.buttonMode = true;
               
                _beginSpel.addEventListener(MouseEvent.CLICK, beginnen)
               
                createBackground();
                createLevel();
                makeCharacter();
               
                   
                makeSound();
                makeWords();
               
               
               
            }
           
            private function makeWords():void
            {
                _words = new Words(WORDS);
                addChild(_words);
               
               
            }
           
            private function beginnen(e:MouseEvent):void
            {
               
                setCharacterListeners();
                _character.visible = true;
                _background.visible = true;
                _level.visible = true;
                _words.visible = true;
               
                _levelSound.play();
               
               
            }
           
           
           
            private function makeCharacter():void
            {
                _character = new Character();
                addChild(_character);
           
            }
           
            private function createLevel():void
            {
                _level = new Level();
                addChild(_level);
           
            }
           
            private function createBackground():void
            {
                _background = new Background();
                addChild(_background);
               
           
            }
           
            private function setCharacterListeners():void
            {
                //To do: Zorgen dat deze event listeners nog uit staan als het spel nog niet gestart is.
                    removeObjects();
                    stage.addEventListener(KeyboardEvent.KEY_DOWN, keyDown, false, 0, false);
                    stage.addEventListener(KeyboardEvent.KEY_UP, keyUp, false, 0, false);
                    stage.addEventListener(Event.ENTER_FRAME, characterWalk);  
               
            }
           
            private function removeObjects():void
            {
                removeEventListener(MouseEvent.CLICK, beginnen);
                removeChild(_beginSchermManager);
               
                removeChild(_beginSpel);
           
            }
           
            private function pauseGame():void
            {
                _pause = true;
               
            }
           
           
            private function keyDown(e:KeyboardEvent):void
            {
                var key:uint = e.keyCode;
               
                switch (key)
                {
                         case Keyboard.LEFT :
                            _level.x += 1;
                            _character.x -= 7;
                           
                         break;
                          case Keyboard.RIGHT :
                            _level.x -= 1;
                            _character.x += 7;
                           
                         break;
                          case Keyboard.UP :
                           
                            characterJump();
                         break;
                       
                }
               
                if (_character.hitTestObject(_words))
                {
                    createBox();
                   
                    stage.removeEventListener(KeyboardEvent.KEY_DOWN, keyDown);
                    stage.removeEventListener(KeyboardEvent.KEY_UP, keyUp);
                    stage.removeEventListener(Event.ENTER_FRAME, characterWalk);
                   
                   
                }
            }
           
           
           
            private function keyUp(event:KeyboardEvent):void
            {
               
                    if (event.keyCode == 38 || event.keyCode == 87)
                    {
                        _character.y += _gravity;
                       
                    }
            }
                   
           
            private function characterWalk(e:Event):void
            {
               
                _velY += _gravity;
               
                _character.y += _velY ;
               
                if(_character.y > 370)
                {
                    _character.y = 370;
                    _velY = 0;
                }
               
               
                if (_character.x > stage.stageWidth - 70 )
                {
                    _character.x -= 11;
                }
               
                if (_character.x < stage.stageWidth - 500 )
                {
                    _character.x += 11;
                }
               
                _words.x -= 2;
           
               
            }
           
            private function characterJump():void
            {
                if(_velY==0)
                {
                    _velY = -40
                }
            }
       
            public function createBox():void
            {
                box = new Sprite();
                addChild(box);
               
                box.graphics.beginFill(0xFF0000, .5);
                box.graphics.drawRect(100, 100, 350, 200);
                box.graphics.endFill();
               
                box.addEventListener(MouseEvent.CLICK, clickAway);
                box.buttonMode = true;
               
           
               
            }
           
            private function clickAway(e:MouseEvent):void
            {
                box.visible = false;
                stage.addEventListener(KeyboardEvent.KEY_DOWN, keyDown, false, 0, false);
                stage.addEventListener(KeyboardEvent.KEY_UP, keyUp, false, 0, false);
                stage.addEventListener(Event.ENTER_FRAME, characterWalk);  
               
               
            }
           
       
      }
       
       
    }

    Words Class
    Actionscript Code:
    package
    {
        import flash.display.Sprite;
        import flash.events.MouseEvent;

       
        /**
         * ...
         * @author marciano
         */

        public class Words extends Sprite
        {
            private var _words:Array;
            private var _wordHolder:Sprite;
            private var _wordsItems:Array;
            private var box:Sprite;
           
           
            public function Words(words:Array)
            {
                visible = false;
                _words = words;
                showWords();
            }
           
            private function showWords():void
            {
                var wordItem:WordItem;
                _wordHolder = new Sprite();
               
                addChild(_wordHolder);
                _wordsItems = [];
               
                for ( var i:int = 0; i < 3; i++)
                {
                    wordItem = new WordItem(_words[i]);
                    _wordHolder.addChild(wordItem);
                   
                   
                    wordItem.id = i;
                    _wordsItems.push(wordItem);
                   
                    wordItem.x = Math.random () * 900 + 400;
                    wordItem.y = Math.random () * 225 + 150;
                   
               
                   
               
                }
           
            }
           
            //public function createBox():void
            //{
                //box = new Sprite();
                //addChild(box);
                //
                //box.graphics.beginFill(0xFF0000, .5);
                //box.graphics.drawRect(100, 100, 350, 200);
                //box.graphics.endFill();
                //
                //box.addEventListener(MouseEvent.CLICK, clickAway);
                //box.buttonMode = true;
                //
            //}
            //
            //private function clickAway(e:MouseEvent):void
            //{
                //box.visible = false;
            //}
            //
           
           
           
           
        }
       
    }

    WordItem
    Actionscript Code:
    package
    {
        import flash.display.Sprite;
        import flash.text.TextField;
        import flash.text.TextFieldAutoSize;
        import flash.text.TextFormat;
       
        /**
         * ...
         * @author marciano
         */

        public class WordItem extends Sprite
        {
            private var _words:Array;
            private var _id:int;
            private var _wordSprite:Sprite;
           
           
            public function WordItem(words:String)
            {
               
               
               
                //set words before adding it to the stage, else it will complain about getting nothing
               
                _wordSprite = createWords(words);
               
           
                addChild(_wordSprite);
            }
           
            private function createWords(label:String):Sprite
            {
                var wordField:TextField = new TextField();
                var format:TextFormat = new TextFormat ();
                var holder:Sprite = new Sprite ();
               
               
       
                addChild(holder);
                holder.addChild (wordField);
               
                format.size = 18;
                format.color = 0xFF0000;
                format.font = "Calibri";
               
                wordField.selectable = false;
                wordField.autoSize = TextFieldAutoSize.CENTER;  
                wordField.defaultTextFormat = format;
               
                holder.mouseChildren = false;
               
                wordField.text = label;
               
                // put this below for scaling the holder properly
                //holder.graphics.beginFill(0x00FF00, 1);
                //holder.graphics.drawRect(0, 0, wordField.width, wordField.height);
                //holder.graphics.endFill();
                //
               
                trace("wordField.height : " + wordField.height);
               
                return holder;
               
               
               
            }
           
            public function get id():int
            {
                return _id;
            }
           
            public function set id(value:int):void
            {
                _id = value;
            }
           
           
           
           
           
        }
       
    }

  4. #4
    Will moderate for beer
    Join Date
    Apr 2007
    Location
    Austin, TX
    Posts
    6,801
    Looks like the main trouble you're having is that you are hittesting the character against the whole collection of words instead of each individual word.

    Create a method in Words which takes a DisplayObject (the character) or a point (character's coordinates) and hitTests against each word. You can either return the list of hit words back to Main, or act on it directly. I'd suggest returning it, and also creating a removeWords(warray:Array) method in Words to remove the given words.

  5. #5
    Senior Member
    Join Date
    Mar 2010
    Posts
    107
    Could you possibly help me on my way? I tried it and I still cant solve it.

  6. #6
    Will moderate for beer
    Join Date
    Apr 2007
    Location
    Austin, TX
    Posts
    6,801
    I don't have time to give you a complete solution right now (and you wouldn't learn much from that anyway), but here's a first stab at a method in Words which takes a DisplayObject and returns an Array full of all the WordItems that are touching that object.

    Code:
    public function getWordsTouchingObject(obj:DisplayObject):Array{
      var hitwords:Array = []; //we'll return this at the end.
      for (var i:int = 0; i < _words.length; i++){
         var w:WordItem = _words[i];
         if (obj.hitTestObject(w)){
            hitwords.push(w);
         }
      }
      return w;
    }
    Now, call that instead of hitTestObject(_words) in main to get your collection of words hit.
    Code:
      var hitWords:Array = _words.getWordsTouchingObject(_character);
      for (var i:int = 0; i < hitWords.length; i++){
        //do something with each word.  If that something is "remove it", then you should make a method in Words to do that, and call it here.
      }
    Edit: stupid profanity filter doesn't like word****ByObject

  7. #7
    Senior Member
    Join Date
    Mar 2010
    Posts
    107
    First of all, thanks alot. And to make things clear, I just wanted something to start with. But I'm stuck again...

    I just don't understand how it works with this. I've never really done this before. I made a function removeWords, which obvious enough, removes the words which the character touches. I did it like this:


    public function removeWords():void
    {

    for (var i:int = 0; i < _words.length; i++)
    {
    var wordItem:WordItem = new WordItem(_words[i]);
    wordItem.id = i;


    }

    if (_words[1])
    {
    trace("one");
    }
    if (_words[2])
    {
    trace("two");
    }
    if (_words[3])
    {
    trace("three");
    }


    }

    I can't think of a way to make them dissapear, the one the character touches. Im really stuck in here, it drives me crazy!

  8. #8
    Will moderate for beer
    Join Date
    Apr 2007
    Location
    Austin, TX
    Posts
    6,801
    Please use [code] tags.

    Let's think about the requirements of your removeWords function. It needs to remove words, yes, but what does that mean? How about, that means remove them from the display, and from the internal _words array.
    Okay, great. Now, what do we give this method, and what do we expect back?
    The method has to know which words to remove, so giving it an array of those words is a pretty good idea. You could give it an array of ids if you had those instead, but since we already have the words themselves lets just do that. And we don't really need anything back from the method.

    So, the method signature should look like this:
    Code:
    public function removeWords(toremove:Array):void{
    }
    We have an array of WordItems to remove. We know those words are children of the Words instance, and are in the _words array that the Words instance has. Let's iterate through the toremove words and do something with all of them.
    Code:
    public function removeWords(toremove:Array):void{
      var w:WordItem;
      for (var i:int = 0; i < toremove.length; i++){
        w = toremove[i];
    
        //first part's easy.  remove from display
        removeChild(w);
    
        //now, we need to remove it from the _words array too.
        var pos:int = _words.indexOf(w);
        if (pos != -1){ //we found it somewhere
          _words.splice(pos,1); //remove it from array.
        }
    
      }
    }
    That should work.

    Advanced stuff follows, do not worry about this yet:
    But note that to find the index of a WordItem in the _words array, we have to linearly search that array. Since we are doing that for possibly all the words, a call to removeWords may take n^2 operations. We don't particularly care that _words is ordered, we just need to put things in and take things out. Array is a poor data structure for this. What we really would like is a Set. But Set isn't built in to AS3.
    A Set is a datastructure that holds stuff. It tells you if something is a member of that set (contains), lets you add new stuff (add), remove a member (remove) and iterate over the items (foreach). I leave it as an exercise for the reader to implement Set. And if they're feeling ambitious, implement a Collection interface that makes swapping out collection implementations easy. Hint: A Dictionary can use arbitrary objects as keys, and can iterate over keys and values with for-in and for-each.

  9. #9
    Senior Member
    Join Date
    Mar 2010
    Posts
    107
    I really really appreciate your help, 5tonsOfFlax.
    This learned me more in as3, how to handle those situations.

    Though im wondering what value the removeWords function expects when i am Kicking off the function in the main class?

  10. #10
    Will moderate for beer
    Join Date
    Apr 2007
    Location
    Austin, TX
    Posts
    6,801
    It expects the list of words to remove. You got a list of words that your character is touching already.
    You could combine the hit detection and removal into a single method, but if you wanted to do anything else (like increase the players score based on the words, or remove only those words that begin with a vowel, or any other processing of the hit words list) then this way is more flexible.

  11. #11
    Senior Member
    Join Date
    Mar 2010
    Posts
    107
    So that'll be the the WORDS const in the main?

    If I do that I get this:

    TypeError: Error #1034.

    I've missed something I guess.

  12. #12
    Will moderate for beer
    Join Date
    Apr 2007
    Location
    Austin, TX
    Posts
    6,801
    No, WORDS in Main is not an array of WordItem, it is an array of Strings. And you don't want to remove all those words even if they were WordItems. You only want to remove the ones the character touched, so pass back the array you got from getWordsTouchingObject.

  13. #13
    Senior Member
    Join Date
    Mar 2010
    Posts
    107
    I know how to pass a value from the Main to a lower class, but how do we do that the other way round?

  14. #14
    Will moderate for beer
    Join Date
    Apr 2007
    Location
    Austin, TX
    Posts
    6,801
    I know how to pass a value from the Main to a lower class
    I don't. What's a lower class? Is it one that sits around all day watching NASCAR and eating Cheetos?

    A method call is a method call, regardless of the relationship between calling instance and called instance. Just get a reference to the instance, and call the method on it.

    Also, why do you think you need to pass a value from something to Main? getWordsTouchingObject is already returning a value, and since you're calling that from Main, Main has access to that value. Just store it somewhere.

  15. #15
    Senior Member
    Join Date
    Mar 2010
    Posts
    107
    I'm sorry for not being clear, but I meant the child class of the Main (the word class in my case)

    The only logical option to me would be the hitWords Array, like this:

    Actionscript Code:
    if (_character.hitTestObject(_words))
                {
                   
                    createBox();
                   
                    stage.removeEventListener(KeyboardEvent.KEY_DOWN, keyDown);
                    stage.removeEventListener(KeyboardEvent.KEY_UP, keyUp);
                    stage.removeEventListener(Event.ENTER_FRAME, characterWalk);
                   
                    var hitWords:Array = _words.getWordsTouchingObject(_character);
                   
                    for (var i:int = 0; i < hitWords.length; i++)
                    {
                       
                        _words.removeWords(hitWords);
                    }

    But yeah, also that doesn't work. ArgumentError: Error #2025 is the problem.

    Man, I must be ruining your day

  16. #16
    Will moderate for beer
    Join Date
    Apr 2007
    Location
    Austin, TX
    Posts
    6,801
    When posting an error, always post the error message, not just the error number. Personally, I haven't memorized any of them except for 1009, and that's only because it is asked about so darn often.

    2025 is apparently "Supplied DisplayObject must be a child of the caller". This happens when you try to remove something from the wrong parent, or try to remove something which is not on the display at all.

    In this case, it is the second, because you are repeatedly calling removeWords, even though removeWords removes ALL the words in the array. So the second time you call it, none of the words given are on the display and you get that error. Remove that loop.

    You should probably also not have the _character.hitTestObject(_words) test. Instead, just use the hitWords array from getWordsTouchingObject. If that array is not empty, then a hit happened. I do not know what you are doing with createBox and removing those event listeners, but it is entirely possible to hit _words, but not hit any individual WordItem in it. You probably don't want to do the createBox stuff in that case.

    Code:
    var hitWords:Array = _words.getWordsTouchingObject(_character);
    if (hitWords.length > 0){
      createBox();
      stage.removeEventListener(KeyboardEvent.KEY_DOWN, keyDOwn);
      stage.removeEventListener(KeyboardEvent.KEY_UP, keyUp);
      stage.removeEventListener(Event.ENTER_FRAME, characterWalk); //why is this on the stage?
      _words.removeWords(hitWords);
    }

  17. #17
    Senior Member
    Join Date
    Mar 2010
    Posts
    107
    Ok so I did this:


    Actionscript Code:
    private function characterWalk(e:Event):void
            {
               
                _velY += _gravity;
               
                _character.y += _velY ;
               
                if(_character.y > 370)
                {
                    _character.y = 370;
                    _velY = 0;
                }
               
               
                if (_character.x > stage.stageWidth - 70 )
                {
                    _character.x -= 11;
                }
               
                if (_character.x < stage.stageWidth - 500 )
                {
                    _character.x += 11;
                }
               
                _words.x -= 2;
               
                var hitWords:Array = _words.getWordsTouchingObject(_character);
               
                if (hitWords.length > 0)
                {
                   
                   
                    createBox();
                   
                    stage.removeEventListener(KeyboardEvent.KEY_DOWN, keyDown);
                    stage.removeEventListener(KeyboardEvent.KEY_UP, keyUp);
                    stage.removeEventListener(Event.ENTER_FRAME, characterWalk);
                   
                   
                   
                    _words.removeWords(hitWords);
                }
               
           
               
            }

    The ENTER_FRAME is here to let the character walk. So it automatically checks every frame if the character hits something.

    What I want is when the character hits a random word, it needs to be removed from the screen.

    The createBox is there to pop up when the character hits a word. The meaning of that is that a definition of a word is given. When the box is created I want to "pause" the game. The character should stop with its walk, and the words must stop floating around in the level.

    I still get the error 2025 supplied DisplayObject must be a child of the caller.

  18. #18
    Will moderate for beer
    Join Date
    Apr 2007
    Location
    Austin, TX
    Posts
    6,801
    Use [code] tags.

    What line is throwing the error?

  19. #19
    Senior Member
    Join Date
    Mar 2010
    Posts
    107
    It doesn't give any compiler errors, it just says:

    Actionscript Code:
    Error 2025: supplied DisplayObject must be a child of the caller.
    at flash.display::DisplayObjectContainer/removeChild()
        at Words/removeWords()
        at MainGame/characterWalk()

    So that would be at line 270.

  20. #20
    Will moderate for beer
    Join Date
    Apr 2007
    Location
    Austin, TX
    Posts
    6,801
    Hm. I don't see how it could be doing that, but I did notice an error in getWordsTouchingObject. I accidentally put "return w" when I should have put return hitwords. It wouldn't have compiled the way I had it so you must have changed it somehow, did you correct it to hitwords?

    Okay, I just looked again. In your Words class, you are adding your WordItems to a _wordHolder instance. That means they need to be removed from that as well. So change removeChild(w) to _wordHolder.removeChild(w).

    There's really no need for a _wordHolder in the first place, but maybe you had a reason for not adding them directly to Words.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  




Click Here to Expand Forum to Full Width

HTML5 Development Center