Game Development Community

dev|Pro Game Development Curriculum

DragViewAreaBehavior for iT2d 1.5

by Paul Jan · 06/06/2012 (12:30 am) · 0 comments

This behavior (for iT2d 1.5) allows a StaticSprite object using SourceRect to have iOS-like behavior such as single-finger scrolling, and two-finger zoom in and out.

function clamp( %a, %min, %max)
{
    return (t2dGetMax( t2dGetMin( %a, %max), %min));
}


if (!isObject(DragViewAreaBehavior))
{
    %template = new BehaviorTemplate(DragViewAreaBehavior);

    %template.friendlyName = "DragViewArea";
    %template.behaviorType = "Input";
    %template.description  = "Touch and Drag Viewable Area for StaticSprite using SourceRect.";

   //Parameters that can be set in the levelbuilder
    %template.addBehaviorField(DragInX, "Allow dragging along the X-axis", bool, true);
    %template.addBehaviorField(DragInY, "Allow dragging along the Y-axis", bool, true);
    %template.addBehaviorField(Zoom, "Two fingers zoom in and out", bool, true);
}

function DragViewAreaBehavior::onLevelLoaded(%this, %scenegraph)
{
    %this.owner.setUseMouseEvents(true);
    %this.startSourceRect = %this.owner.getSpriteSourceRect();

    %this.frameArea = %this.owner.getImageMap().getFrameArea(%this.owner.getFrame());
    %this.maxRectx = getWord( %this.frameArea, 2) - getWord( %this.startSourceRect ,2);
    %this.maxRecty = getWord( %this.frameArea, 3) - getWord( %this.startSourceRect ,3);
}

function DragViewAreaBehavior::onTouchDown(%this, %touchID, %worldPos)
{
   if(%this.touchID != 0 && %this.touchID != 1)
        return;

    %this.originalArea = %this.owner.getArea();
    %this.originalSize = %this.owner.getSize();
    %this.frameArea = %this.owner.getImageMap().getFrameArea(%this.owner.getFrame());
    %this.frameRatio = (getWord(%this.originalSize,0)/getWord(%this.originalSize,1));
    %this.startWorldPos[%touchID] = %worldPos;
    %this.currWorldPos[%touchID] = %worldPos;
    %this.touchSourceRect = %this.owner.getSpriteSourceRect();
    %this.touchCount = %touchID;
}

function DragViewAreaBehavior::onTouchDragged(%this, %touchID, %worldPos)
{
   if(%this.touchID != 0 && %this.touchID != 1)
        return;
    
    %currsourceRect = %this.owner.getSpriteSourceRect();
    
    %sourceRectx = getWord( %this.touchSourceRect ,0);
    %sourceRecty = getWord( %this.touchSourceRect ,1);
    %sourceRectw = getWord( %this.touchSourceRect ,2);
    %sourceRecth = getWord( %this.touchSourceRect ,3);

    if (%this.touchCount == 0)
    {
        %currRectw = getWord( %currsourceRect ,2);
        %currRecth = getWord( %currsourceRect ,3);
    
        %maxRectx = getWord( %this.frameArea, 2) - getWord( %currsourceRect ,2);
        %maxRecty = getWord( %this.frameArea, 3) - getWord( %currsourceRect ,3);

        if (%this.DragInX)
        {
            %sourceRectx -= ( %worldPos.x-%this.startWorldPos[%touchID].x );
            %sourceRectx = clamp(%sourceRectx, 0.0, %maxRectx);
        }

        if (%this.DragInY)
        {
            %sourceRecty -= ( %worldPos.y-%this.startWorldPos[%touchID].y );
            %sourceRecty = clamp(%sourceRecty, 0.0, %maxRecty);
        }

        %this.owner.setSpriteSourceRect( %sourceRectx SPC
                                         %sourceRecty SPC
                                         %currRectw SPC
                                         %currRecth ); 
     }
     
     if (%this.touchCount == 1 && %this.Zoom)
     {
        %this.currWorldPos[%touchID] = %worldPos;
        %dist1 = t2dVectorDistance(%this.currWorldPos[0], %this.currWorldPos[1]);
        %dist2 = t2dVectorDistance(%this.startWorldPos[0], %this.startWorldPos[1]);

        %this.scale = %dist1 - %dist2;
        %this.scale = clamp(%this.scale/100, -100, 100);
        
        if (%this.scale < 0)
            %scale = 1/mAbs(%this.scale-1);
        else
            %scale = (1+%this.scale);
        
        %sourceRectw /= %scale;
        %sourceRecth /= %scale;
        
        %sourceRectw = clamp( %sourceRectw, 100, t2dGetMin(getWord( %this.frameArea, 2), getWord( %this.frameArea, 3)*%this.frameRatio));
        %sourceRecth = clamp( %sourceRecth, 100, t2dGetMin(getWord( %this.frameArea, 2)/%this.frameRatio, getWord( %this.frameArea, 3)));
        
        %maxRectx = getWord( %this.frameArea, 2) - %sourceRectw;
        %maxRecty = getWord( %this.frameArea, 3) - %sourceRecth;
        
        %this.owner.setSpriteSourceRect( clamp(%sourceRectx, 0.0, %maxRectx) SPC
                                         clamp(%sourceRecty, 0.0, %maxRecty) SPC
                                         %sourceRectw SPC
                                         %sourceRecth ); 
        
     }
}

function DragViewAreaBehavior::onTouchUp(%this, %touchID, %worldPos)
{
    %this.touchCount--;
}

function DragViewAreaBehavior::onMouseLeave(%this, %touchID, %worldPos)
{
    %this.onTouchUp(%this, %touchID, %worldPos);
}

Unfortunately on one occasion I had the getSpriteSourceRect() function flake out on me - it was returning a list of 3 instead of 4. As a fix, I replaced the existing ConsoleMethod in T2dStaticSprite.cc with

ConsoleMethod(t2dStaticSprite, getSpriteSourceRect, const char*, 2, 2, "() - Gets the source rect of this sprite.n"
															   "@return (four component rect) X Y Width Height")
{
	RectF source = object->mSrcRect;
    
    // Create Returnable Buffer.
    char* pBuffer = Con::getReturnBuffer(128);
    // Format Buffer.
    dSprintf(pBuffer, 128, "%d %d %d %d", (S16)source.point.x, (S16)source.point.y, (S16)source.extent.x, (S16)source.extent.y);
    // Return buffer.
    return pBuffer;
}