Box BodyPart dynamic sizing for varying frames?

edited June 2014 in General discussions
Researched all though the forum but I couldn't find any discussion on this topic.

Say for example, I have the following four frames of animation on a orxObject with a Box BodyPart:

Frame1: 90 x 160
Frame2: 96 x 160
Frame3: 102 x 162
Frame4: 96 x 160

Does the sizing of the Box BodyPart only fit automatically to the first frame and stay that way even though the size of the object will change during animation?

The wiki says at http://orx-project.org/wiki/en/orx/config/settings_structure/orxbody
TopLeft/BottomRight: Define the extrema of the box (in 2D it's a rectangle, of course) in the parent's space (ie. in object's space). By default their values are full which means TopLeft and BottomRight will match the full rectangle defined by the parent object's current graphic.

The current graphic could change size and so this quote seems to indicate the size of the box should hopefully change with it. By adding a ShowDebug = true to the Physics section on my config, I can see that the box size doesn't change.

One last thing, this is a test under Orx from last October so things might have changed in this area. I can supply a small zipped demo if anyone needs it.

Comments

  • edited June 2014
    The wording is confusing, I'll change it: the size of the part is using the size of the graphic, which actually never changes, even if there are animation playing. If you call orxOBJECT_GET_STRUCTURE(MyObject, GRAPHIC), you'll always get the initial graphic, no matter which animation is currently playing. It's this graphic that defines the size property of the object.

    Also it's good to note that most physics engine do not support scaling up/down bodies at runtime, orx is working around this limitation by deleting a part and re-creating a new one whenever the scale of an object changes.
  • edited June 2014
    Yep sorry, I wrote that fairly poorly.

    You mentioned scaling an object, but I think perhaps I haven't presented the problem clearly, as I'm not scaling the object.

    In my example I have four animation frames, something like:

    [ManRunningAnim]
    KeyData1 = Run1
    KeyData2 = Run2
    KeyData3 = Run3
    KeyData4 = Run4

    The legs in frames Run2 and Run3 are much further apart so that their pixel width is greater than Run1 and Run4.

    Because I have a box bodypart, and ShowDebug = true, the debug box surrounding the object stays the same width even though my running man sprite varies in width as it animates.

    Apologies if I have gotten this wrong based on what you said, and there may be nothing I can do about it.
  • edited June 2014
    No I think that's me who wasn't very clear. :)

    What I meant is that there's no runtime scaling of parts except when an object gets scaled (and in that case, it's not really scaling that happens for the parts but deletion+re-creation).

    Animation frames never have any impact on physics bodies & parts.

    If you want to have different body/part configurations based on animation frames, you'll have to do it manually, using animation custom events.
  • edited June 2014
    Yep I did wonder that. I started to consider last night if I could resize my box bodypart on each frame event, so I was happy you mentioned that. This is good solution.

    I confirmed yesterday (as you also mentioned) that the size of the physics box comes from the initial graphic assigned to an object. And as you say, the animation that comes after has no bearing.

    That's fair enough. I'll do this up and post the solution for anyone else that might be interested.
  • edited June 2014
    Spent a couple of nights going over the API looking into how I can go about this... I can certainly trap an event on every frame, that part is not a worry.

    But is there a way to alter the TopLeft/BottomRight parameters of a box bodypart during runtime?

    I could perhaps do a orxPhysics_DeletePart / orxPhysics_CreatePart on every frame but I feel this is pretty dangerous.
  • edited June 2014
    Very close to a solution.. I run this and it resizes my box body part to 50 x 60 pixels every frame:
    
    orxOBJECT *obj = orxOBJECT(_pstEvent->hRecipient);
    orxSTRUCTURE *graphicStructure = _orxObject_GetStructure(obj, orxSTRUCTURE_ID_GRAPHIC );
    			
    /* this is the object graphic, not the frame graphic I need */
    orxGRAPHIC *graphic = (orxGRAPHIC*)graphicStructure;
    
    orxVECTOR size;
    orxGraphic_GetSize(graphic, &size); 
    size.fX = 50; //work out how to get current frame size,
    size.fY = 60; //then replace these hardcoded values.
    
    orxGraphic_SetSize(graphic, &size);
    			
    orxSTRUCTURE *bodyStructure = _orxObject_GetStructure(obj, orxSTRUCTURE_ID_BODY);
    
    orxBODY *body = (orxBODY*)bodyStructure;
    orxBODY_PART *part = orxBody_GetNextPart(body, orxNULL);
    			
    orxBody_RemovePart(part);
    orxBody_AddPartFromConfig(body, "DroidPart");
    
    

    Next, I have to work out how to get the size of the current frame graphic, give it to the object graphic, and I should be ok.
  • edited June 2014
    Hi, sorry for the late replies, I haven't spent much time on my computer on evenings lately.

    If you change the size of your graphic this way, you'll eventually end up with graphical artifacts.

    What you will need to do is to delete the current part and create a new one at the correct size. You have two options for this:

    - Either you modify the config values for the parts and simply call orxBody_AddPartFromConfig() for the re-creation, but that means you'll have to precise the size of the parts and not rely on orx to use the graphic's size

    - Or you can simply call orxBody_AddPart() which takes an orxBODY_PART_DEF which contains all the info to create the new part. In this case, you can get the def from the former part, modify its size, and create a new part with it.

    Here's an example (untested as I'm typing in the forum editor):
    // Gets event's object
    orxOBJECT *pstObject = orxOBJECT(_pstEvent->hRecipient);
    
    // Gets object's animation pointer
    orxANIMPOINTER *pstAnimPointer = orxOBJECT_GET_STRUCTURE(pstObject, ANIMPOINTER);
    
    // Gets current animation graphic
    orxGRAPHIC *pstGraphic = orxGRAPHIC(orxAnimPointer_GetCurrentAnimData(pstAnimPointer));
    
    // Gets its size
    orxVECTOR vSize;
    orxGraphic_GetSize(pstGraphic, &vSize);
    
    // Gets Body
    orxBODY *pstBody = orxOBJECT_GET_STRUCTURE(pstObject, BODY);
    
    // Gets its part
    orxBODY_PART *pstPart = orxBody_GetNextPart(pstBody, orxNULL);
    
    // Copies its definition
    orxBODY_PART_DEF stPartDef;
    orxMemory_Copy(&stPartDef, orxBody_GetPartDef(pstPart), sizeof(orxBODY_PART_DEF));
    
    // Modifies the definition using the graphic's size: stPartDef.stMesh/stPartDef.stBox/stPartDef.stSPhere depending on its type (stPartDef.u32Flags & orxBODY_PART_DEF_KU32_MASK_TYPE)
    // ... Do it here!
    
    // Removes part
    orxBody_RemovePart(pstPart);
    
    // Adds a new one with the new dimensions
    orxBody_AddPart(pstBody, &stPartDef);
    
  • edited June 2014
    This is great, thank you Iarwain. Thankfully I can see I was mainly on the right track. I did try to experiment with orxBODY_PART_DEF but couldn't understand how to work the structures, until now.

    I'm continuing with this at the moment.
  • edited June 2014
    Major success! I think this is a very important technique for people to be aware of as it can be used to ensure that collisions only occur on active regions around a sprite, and not on empty space around a sprite when it becomes smaller.
    
    case orxANIM_EVENT_CUSTOM_EVENT: {
    			
    	orxOBJECT *droidObj = orxOBJECT(_pstEvent->hRecipient);
    
    	orxANIMPOINTER *animPointer = orxOBJECT_GET_STRUCTURE(droidObj, ANIMPOINTER);
    	orxGRAPHIC *currentFrameGraphic = orxGRAPHIC(orxAnimPointer_GetCurrentAnimData(animPointer));
    	orxVECTOR currentFrameSize;
    	orxGraphic_GetSize(currentFrameGraphic, &currentFrameSize);
    			
    	orxSTRUCTURE *bodyStructure = _orxObject_GetStructure(droidObj, orxSTRUCTURE_ID_BODY);
    
    	orxBODY *body = (orxBODY*)bodyStructure;
    	orxBODY_PART *part = orxBody_GetNextPart(body, orxNULL);
    			
    	orxBODY_PART_DEF partDef;
    	orxMemory_Copy(&partDef, orxBody_GetPartDef(part), sizeof(orxBODY_PART_DEF));
    			
    	orxVECTOR vTL;
    	orxVECTOR vBR;
    	vTL.fX = 0;
    	vTL.fY = 0;
    	vBR.fX = currentFrameSize.fX;
    	vBR.fY = currentFrameSize.fY;
    			
    	orxAABOX box = partDef.stAABox.stBox;
    	partDef.stAABox.stBox.vTL.fX = vTL.fX;
    	partDef.stAABox.stBox.vTL.fY = vTL.fY;
    	partDef.stAABox.stBox.vBR.fX = vBR.fX;
    	partDef.stAABox.stBox.vBR.fY = vBR.fY;
    			
    	orxBody_RemovePart(part);
    	orxBody_AddPart(body, &partDef);
    
    	break;
    }
    
    

    Again, thanks, Iarwain. This was enormously important to achieve for the current project.
  • edited June 2014
    Improvement, taking into account pivot calculation, and moved to a handy function which can be called by the events routine:
    void EventsController::ResizeBodyBox(orxOBJECT* orxObject){
    
    	orxANIMPOINTER *animPointer = orxOBJECT_GET_STRUCTURE(orxObject, ANIMPOINTER);
    	orxGRAPHIC *currentFrameGraphic = orxGRAPHIC(orxAnimPointer_GetCurrentAnimData(animPointer));
    	orxVECTOR currentFrameSize;
    	orxGraphic_GetSize(currentFrameGraphic, &currentFrameSize);
    	
    	orxVECTOR currentFramePivot;
    	orxGraphic_GetPivot (currentFrameGraphic, &currentFramePivot); 
    	
    	orxSTRUCTURE *bodyStructure = _orxObject_GetStructure(orxObject, orxSTRUCTURE_ID_BODY);
    
    	orxBODY *body = (orxBODY*)bodyStructure;
    	orxBODY_PART *part = orxBody_GetNextPart(body, orxNULL);
    	
    	orxBODY_PART_DEF partDef;
    	orxMemory_Copy(&partDef, orxBody_GetPartDef(part), sizeof(orxBODY_PART_DEF));
    		
    	orxVECTOR vTL;
    	orxVECTOR vBR;
    	vTL.fX = - currentFramePivot.fX; 
    	vTL.fY = - currentFramePivot.fY;
    	vBR.fX = currentFrameSize.fX - currentFramePivot.fX;
    	vBR.fY = currentFrameSize.fY - currentFramePivot.fY;
    	
    	orxAABOX box = partDef.stAABox.stBox;
    	partDef.stAABox.stBox.vTL.fX = vTL.fX;
    	partDef.stAABox.stBox.vTL.fY = vTL.fY;
    	partDef.stAABox.stBox.vBR.fX = vBR.fX;
    	partDef.stAABox.stBox.vBR.fY = vBR.fY;
    	
    	orxBody_RemovePart(part);
    	orxBody_AddPart(body, &partDef);
    }
    
    
Sign In or Register to comment.