In my LibGDX game I have some Actors in the Scene2d framework that walks around and picks up other Actors. In general it works fine, but I cannot get the scaling to work properly; I want the item picked up to be equally large as an Actor and as a SkeletonAttachment. I have tried lots things, but I am currently at a loss. Here is what it looks like:
First, all my Actors are scaled on construction:
/**Scales the SpineActor in accordance with its physical height (in meters) and
* the height of the screen (in meters).*/
public void animatableScale() {
skeleton.setToSetupPose();
skeleton.updateWorldTransform();
skeletonBounds.update(skeleton, true);
float heightInPixels = ViewportParameters.PPM * parameters.height;
float scalingFactor = heightInPixels / skeletonBounds.getHeight();
this.setScale(scalingFactor);
}
The setScale method looks like this:
/**Overrides setScale to set scale of root bone instead of Actor bounds. Also updates
* the skeleton world transform and the skeleton bounds.*/
@Override
public void setScale(float scale){
skeleton.getRootBone().setScaleX(scale);
skeleton.getRootBone().setScaleY(scale);
skeleton.updateWorldTransform();
skeletonBounds.update(skeleton, true);
}
Hence, both type of Actors receive a little bit of scaling so that I can easier set my heights in meters. These methods are called at construction, both for the walking Actor and for the Actor being picked up. For the Actor being picked up I also create a SkeletonAttachment at construction:
skeletonAttachment = new SkeletonAttachment(GameParameters.SockParameters.NAME_OF_SOCK_ATTACHMENT);
skeletonAttachment.setSkeleton(skeleton);
When the walking Actor reaches an item to pick up, in this case a Sock, I do the following in the Actor that picks it up:
/**Sets the current Sock to the argument Sock. Also sets the owner of the Sock to this.*/
public void setSock(Sock sock){
this.sock = sock;
sock.setOwner(this);
this.skeleton.findSlot(FigureData.NAME_OF_SOCK_SLOT).setAttachment(sock.getSkeletonAttachment());
}
The Sock.setOwner method looks like this:
/**Sets the owner of the Sock and notifies all Figures that this has happened. The scaling is updated
* so that it also takes the owner's scaling into account.*/
public void setOwner(FigureBaseClass owner){
this.owner = owner;
updateScaling();
}
where my updateScaling method currently looks like the following. It is here I cannot figure out what's happening, so I'll leave stuff I have commented out as well.
/**Updates the scaling of the {@link Attachment}. Takes the owner's scaling into account if
* appropriate at the time of calling.*/
private void updateAttachmentScaling(){
// skeleton.setToSetupPose();
// skeleton.updateWorldTransform();
// skeletonBounds.update(skeleton, true);
float heightInPixels = ViewportParameters.PPM * this.parameters.height;
// float scalingFactor = heightInPixels / (skeletonBounds.getHeight() * owner.getRootBone().getScaleY());
// skeletonAttachment.getSkeleton().getRootBone().setScaleX(scalingFactor);
// skeletonAttachment.getSkeleton().getRootBone().setScaleY(scalingFactor);
if (owner == null){
float scalingFactor = heightInPixels / skeletonBounds.getHeight();
// this.setScale(scalingFactor);
skeletonAttachment.getSkeleton().getRootBone().setScaleX(scalingFactor);
skeletonAttachment.getSkeleton().getRootBone().setScaleY(scalingFactor);
}
else{
float scalingFactor = heightInPixels / skeletonBounds.getHeight() * owner.getScaleY();
// this.setScale(scalingFactor);
skeletonAttachment.getSkeleton().getRootBone().setScaleX(scalingFactor);
skeletonAttachment.getSkeleton().getRootBone().setScaleY(scalingFactor);
}
}
Since the owner of the SkeletonAttachment also has a scaling of its own, set to the RootBone, I try to take that into consideration as well, but without any luck. What am I missing here?
As a side note, here is my act method:
@Override
public void act(float delta) {
/*Computes the world SRT from the local SRT for each bone (SRT = Scale, Rotation, Translation).*/
skeleton.updateWorldTransform();
/*Increments the skeleton’s time field.*/
skeleton.update(delta * game.getHandlerContainer().getBuffHandler().getSpeedModifier());
/*Updates the AnimationState and calculates new mixing and related stuff*/
animationState.update(delta * game.getHandlerContainer().getBuffHandler().getSpeedModifier());
/*Applies the current animation in animationState including possible mixing to the given skeleton*/
animationState.apply(skeleton);
/*Set to false so that it is known that skeletonBounds must be updated later.*/
skeletonBoundsIsUpdated = false;
super.act(delta);
}
Any comments are highly appreciated. I actually just did this (on the table) :bang:
I think I figured out a solution, but I am not really sure that it is the best one. UpdateAttachmentScaling now looks like this:
private void updateAttachmentScaling(){
/*If owner is null, the Sock has been dropped. Return to normal scaling.*/
if (owner == null)
animatableScale();
/*If there is an owner, scale to the sock Bone scale.*/
else{
skeleton.setToSetupPose();
skeleton.updateWorldTransform();
skeletonBounds.update(skeleton, true);
float heightInPixels = ViewportParameters.PPM * this.parameters.height;
float scalingFactor = heightInPixels / (skeletonBounds.getHeight() * owner.getRootBone().getScaleY());
owner.getSockBone().setScaleX(scalingFactor);
owner.getSockBone().setScaleY(scalingFactor);
}
}
Is this the only way to achieve this? What if I don't want to go back to the setup pose every time? Is it ok to scale the bone that the SkeletonAttachment will be put on, or is there any better way of doing this scaling?