Game Development Community

Self Moving GuiControls

by Griffin Milsap · in Torque Game Engine · 04/14/2007 (3:09 pm) · 12 replies

Hey. I'm modding the GuiBitmapButtonCtrl so that I can give it coordinates to slide to, and it slide there nicely.

My only problem is that I'm having difficulty accessing any sort of Parent::SetPosition(x,y). (I know it doesn't exist, but I wish it did.

I've been all over the forums and back looking for resouces with sliding guicontrols, and all I found was the guiAutoScroll resource, and that doesn't quite do what I want it to.

Any help?

-Griff

#1
04/15/2007 (6:54 am)
Griff - There is a SetPosition function you can use, if you look at the hierarchy for GuiBitmapButtonCtrl, for example in the console window type:
==>[b]MyGuiBitmapButton.dumpclasshierarchy();[/b]
GuiBitmapButtonCtrl ->
GuiButtonCtrl ->
GuiButtonBaseCtrl ->
GuiControl ->
SimGroup ->
SimSet ->
SimObject ->

You can see in the chain it is inherited from the GuiControl class which exposes a getPosition and setPosition function that is usuable both in C++ and via Torquescript. So you can get your button to slide without altering the engine code just by writing some script, for example:

function slideGuiControl(%object, %x, %y, %step, %speed)
{
    // where %obect is the handle to the item you wish to move (either it's name or id)
    // %x and %y are the target coordinates
    // %step is number of pixels to move the object by in each step
    // %speed is the number of milliseconds between movements

    // Find the position of the Object currently
    if(!%currentPos = %object.GetPosition())
        return false;
        
    %posX = getWord(%currentPos,0);
    %posY = getWord(%currentPos,1);
    
    if (%posX != %x || %posY != %y)
    {
        // Set the movement for X
        if(%posX < %x)
            %posX += %step;
        else if (%posX > %x)
            %posX -= %step;         

        //set the moment for Y
        if(%posY < %y)
            %posY += %step;
        else if (%posY > %y)
            %posY -= %step;

        // Move the object    
        %object.setPosition(%posX, %posY);

        // schedule another call to make the next step
        schedule(%speed,0,slideGuiControl, %object, %x, %y, %step, %speed);
    }       

}

The schedule command will only approximately run it at that interval so you may find if you try and move too many controls at once or have a lot of other things going on that your animations become a little jerky, in which case I would look to altering the engine code where you make the movements based on real world time.

If the script approach doesn't work for you then let me know and I'm happy to help you modify the engine code to achieve the effect you're after.

Andy
#2
04/15/2007 (8:44 am)
Wow. I wasn't expecting that thourogh of a response! Thanks Andy!

Anyway, I had thought about doing script, but then came to the conclusion that exploiting schedule like that is bad (somehow). Seeing how well this works, I don't know why though.

When I tried out your code, it seemed to work out well. I ended up having to make a consolefunction for getPosition within guiControl (I'm using an early version of 1.4 :( but all in all, it ended up working out well.

The screen coords are a little funky. I'm still trying to figure it out.

[edit] The coords are fine, its just that once it goes to 0,0, you can't move it away without resetting the engine.
I'll look into it.

Anyway, thanks a ton.

-Griff
#3
04/15/2007 (9:04 am)
I would also recommend implementing something liike this in Engine, not in script.

a couple things you might want to be aware of -

* each GuiControl's coordinates are relative to its parent's origin.

* GuiControls are clipped to their parent's bounding box.
- so if you want your control to have the freedom to move all over the screen,
you should first create a plain GuiControl container which fills the whole screen.
(note, you *can* override this, but unless you've got a really compelling reason to do so, i'd stick w/ the stock behaviour)

* i think the default way to move a GuiControl in TGE is via control.resize(position, extent).
the resizing aspects of that can be a little expensive if it's happening every frame.
i recommend throwing a check in there to test whether the control's extent has actually changed,
and/or writing a new method along the lines of the following:
void GuiControl::reposition(const Point2I &newPosition)
{
   mBounds.point = newPosition;
}

* i found it convenient to have a script callback when the control arrives at its destination location

* you might want to consider animating the control's size while you're at it

* GuiControl coordinates are stored internally as integers. Depending on the nature of the "smooth" animation you're envisioning, this might cause you problems. I went ahead and added internal floating-point versions of position and size, and did the core of the animating on that.

* you may want to animate the controls with respect to time, not framerate. ie, instead of moving say N pixels per frame, frame it as N pixels per second. This way you get a more consistent user experience across a range of machines.

fun stuff !
#4
04/15/2007 (9:05 am)
Oh, one more -

* why not modify GuiControl itself instead of GuiBitmapButtonCtrl ? I don't think it'll be any more work, and that way you can slide any control at all around !
#5
04/15/2007 (9:15 am)
Orion, you always go above and beyond the call of duty to help people out - consider this a thank you from all whom you've helped.

I nominate Orion for "Associate" status!
#6
04/15/2007 (10:09 am)
You could also use the GuiWindowCtrl as a parent and turn it into an Alpha background, this is draggable already across torque and then use the GuiBitmapCtrl as a child in it. Then add in your scripting to it which is only a couple lines, Nice Simple, and to the point. If you need help on the scripting aspect of what to do Hit me back.
#7
04/15/2007 (10:18 am)
Shouldnt have to touch source code at all.
#8
04/15/2007 (10:23 am)
But thats just draggable to the client, If your looking to actually input the co-oridnates then look above at those posts :P
#9
04/15/2007 (10:27 am)
But thats just draggable to the client, If your looking to actually input the co-oridnates then look above at those posts :P
#10
04/15/2007 (10:37 am)
Wow guys. Above the call of duty indeed.

The script that Andy posted works very nicely indeed. It works with any guiControl too. A source implementation would definitely be nice. For now, the script implementation works for my needs, but if I find out later that it drags with 7 moving objects at a time, I'll definitely work on that code implementation.

I can see now that it would be smarter to add the functionality to guiControl and not just one of its derivatives :P

-Griff
#11
04/15/2007 (11:46 am)
Great thread, All.

Griffin - glad the script approach works for you !

Tim - thanks for the compliment ! the GG community in general is fantastic and i try to give back when i can.
#12
04/16/2007 (1:25 am)
Orion - You're sure right there, the GG community is one of the things I find most appealing.

Griff - Glad the solution works for you