Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

i'm creating a game with flixel, and I want to have a effect when you mouse over a tile, I tried implementing it, and this is what it gives:

    public class GameState extends FlxState
{
    private var block:EmptyBlock;
    public function GameState() 
    {

    }

    override public function create():void {
        for (var i:Number = 0; i < 30; i++) {
            block = new EmptyBlock(i, 20);
            block.create();
        }
    }

    override public function update():void {
            block.update();
            super.update();
    }
}

}

GameState class

and here is the EmptyBlock class:

public class EmptyBlock 
    {

    private var x:int;
    private var y:int;
    private var row:FlxRect
    public function EmptyBlock(x:int, y:int ) 
    {
        this.x = x;
        this.y = y;
    }

    public function create():void {
         row = new FlxRect(x, y, 32, 32);
        trace ("Created block at" + x + y);
    }

    public function update():void {
        if (FlxG.mouse.screenX == row.x) {
            if (FlxG.mouse.screenY == row.y) {
                var outline:FlxSprite = new FlxSprite(row.x, row.y).makeGraphic(row.width, row.height, 0x002525);
            }
        }
    }


}

}

UPDATE:

The problem is still not solved.

I tried what you recommended, this is the new code:

  public class EmptyBlock extends FlxSprite {
       private var outline:FlxSprite;
       [Embed(source = 'freetile.png', mimeType="image/png")] private var    freeTile:Class;
    public function EmptyBlock(x:int, y:int) {
        this.x = x * 32;
        this.y = y;
        width = 32;
        height = 32;

        // Note: this is a block, rather than an outline.
        // Create an outline image, then use loadGraphic()
        // instead of makeGraphic() if you want an outline.
        outline = new FlxSprite(this.x, this.y);
        outline.loadGraphic(freeTile, false, false, 32, 32, false);
    }

    override public function draw():void {
        super.draw();
        if (overlapsPoint(FlxG.mouse.getScreenPosition()))
            outline.draw();
    }
}
}

And I call it here:

        public function  createMap():void {
        var block:EmptyBlock = new EmptyBlock(0, 0);
        block.draw();


    }

Do you see what i'm doing wrong?

Thanks!

share|improve this question
add comment

2 Answers 2

up vote 4 down vote accepted
+50

Your GameState creates a number of (overlapping) objects. However, you never store these anywhere or add them to the display list; you assign them to one variable, which means you're throwing away all but the last.

In your update loop, you update this ONE block explicitly. You never draw it explicitly.

Normally in Flixel, you'd create objects like this by deriving from FlxSprite, which is a type of FlxBasic. This object can be added to a FlxGroup; your GameState happens to be a FlxGroup you can add objects to. When an object derived from FlxBasic is added to a FlxGroup, the group automatically updates and draws it each frame for you.

In other words, by not deriving your type from FlxSprite, you're bypassing Flixel and saying "I'll update and draw this myself". But since you discard all but one object, and fail to draw this object, you see nothing.

Inside EmptyBlock, you attempt to check to see if the mouse is overlapping in your update function. You then create a FlxSprite, and assign it to a variable which is discarded and never used. In order to update and draw this object, you would want to add it to a FlxGroup such as your GameState, or to another FlxGroup which belongs to your GameState.

So, to fix this: first, change your GameState to add() the object after creating it, instead of assigning it to block. This will fail, because EmptyBlock isn't a type derived from FlxBasic; so change EmptyBlock to derive from FlxSprite. This will fail, because FlxSprite has x and y variables built-in, as well as an update function. So remove your own x and y, and change the update function to override. Besides having its own x and y variables, FlxSprite also has width and height. So instead of making a FlxRect, let's use those to store the object position and size.

Now that your object is a FlxSprite, and now that it's added to the group, it'll be updated and drawn every frame automatically. So remove the explicit call to update in your GameState. That leaves you with an update() that only calls super.update(), so you can remove it if you like.

You can also get rid of the "deferred constructor" pattern you used in EmptyBlock. The reason GameState uses a create() function instead of putting everything in the constructor is so that creating a new GameState can be deferred until the beginning of the next frame, because you're likely to be in the middle of a frame when you decide to change states. You don't need to do that for EmptyBlock, unless you have a reason you haven't expressed here.

I also assume you don't want the blocks to overlap, so you can multiply the x coordinate by the width when you create them. If you want them to overlap, of course, don't do this.

Your overlap check is flawed, by the way, since you check for exact equality, which is only true when the mouse is at the upper-left-most pixel of the square, so you'll need to change this check to a pair of inequalities on both axes. Flixel has a function to check overlap for you, though, so you don't actually have to write out all four compares--just call overlapsAt().

What about the actual creation of a border and display? Well, as I said, you create a FlxSprite in your update() function, then discard it without ever drawing it. A more logical approach would be to create a border once, then draw it when the mouse is overlapping.

Note that the graphic you make is a filled rectangle, and not an outline. It's also an invisible rectangle, because its alpha component is zero.

Also note that you can use FlxG.log() instead of trace(), when using Flixel.

Here is the resulting code. First, GameState.as:

package {
    import org.flixel.*;

    public class GameState extends FlxState {
        override public function create():void {
            for (var i:Number = 0; i < 30; i++) {
                var block:EmptyBlock = new EmptyBlock(i, 20);
                add(block);
            }
        }
    }
}

And now EmptyBlock.as:

package {
    import org.flixel.*;

    public class EmptyBlock extends FlxSprite {
        private var outline:FlxSprite;

        public function EmptyBlock(x:int, y:int) {
            this.x = x * 32;
            this.y = y;
            width = 32;
            height = 32;

            // Note: this is a block, rather than an outline.
            // Create an outline image, then use loadGraphic()
            // instead of makeGraphic() if you want an outline.
            outline = new FlxSprite(this.x, this.y);
            outline.makeGraphic(width, height, 0xFFFFFFFF);
        }

        override public function draw():void {
            super.draw();
            if (overlapsPoint(FlxG.mouse.getScreenPosition()))
                outline.draw();
        }
    }
}

Note that I haven't created an outline. I'll leave that to you. (You can draw it with AS3, but it'd be much easier and more Flixely to make a PNG and load it with loadGraphic().)

Also note that although it's named emptyBlock, it currently shows the default Flixel graphic, which is the Flixel logo. You can remove the call to super.draw() if you don't want it to draw.

If your game scrolls, this code will break, because you're comparing screen coordinates; you can fix this by setting scrollFactor, or by comparing world coordinates instead.

I know this is an awful lot of explanation, but I hope it helps!

share|improve this answer
    
Thanks, helped so mutch! –  Arno Jul 1 '12 at 19:01
    
But can you see the original post, I didn't find a solution, I updated my original post. –  Arno Jul 5 '12 at 10:18
1  
Exactly the same problem - you create an object, call draw on it, but then never save or store it anywhere, so it gets destroyed. Check the first few paragraphs of this answer again. –  Kylotan Jul 5 '12 at 12:06
    
Well, I changed that, add(block); and I added some trace stuff, I put in my draw loop trace("Drawing"); on the console I see drawing drawing, ... but I don't see any tile :( –  Arno Jul 6 '12 at 10:24
add comment

It's been a while since I've used Flixel, so just a stab in the dark.

But the code reads like your checking if the mouse position is at an exact point instead of an area (unless I'm misunderstanding Flixels internal functions).

Maybe try something like:

public function update():void {
    if (FlxG.mouse.screenX >= row.x && FlxG.mouse.screenX <= row.x+row.width ) {
        if (FlxG.mouse.screenY >= row.y && FlxG.mouse.screenY <= row.y+row.height) {
            var outline:FlxSprite = new FlxSprite(row.x, row.y).makeGraphic(row.width, row.height, 0x002525);
        }
    }
}

see if that changes anything

share|improve this answer
    
I'm surprised that this was marked as the correct answer; it's true that this is an issue with the code, but there is the bigger issue that nothing is properly added, as described in Crystal Jacob's answer. –  Gregory Avery-Weir Jul 1 '12 at 18:15
    
Thanks for claryfing that :) –  Arno Jul 1 '12 at 18:47
    
Gregory is right the other solution is definitely tackling more problems than I anticipated! I must of been in zombie mode while glancing over your code, glad you got it sorted though. –  Kayo Jul 2 '12 at 18:17
    
I didn't get it sorted yet, still trying to get it to work :) –  Arno Jul 5 '12 at 9:51
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.