/**
* Copyright 2011 The ForPlay Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package forplay.sample.sprites.core.sprite;
import static forplay.core.ForPlay.log;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import forplay.core.Asserts;
import forplay.core.ImageLayer;
import forplay.core.ResourceCallback;
/**
* A Sprite is a collection of {@link SpriteImage}s.
* <p>
* Create a Sprite from an image and json data using
* {@link SpriteLoader#getSprite(String imageUrl, String jsonUrl)}.
* <p>
* Create a Sprite from json data using {@link SpriteLoader#getSprite(String json)}.
* <p>
* To use, add {@link #layer()} to a {@link Layer} in your game. To change sprites, call
* {@link #setSprite(int)}.
*/
public class Sprite {
private ImageLayer layer;
private List<SpriteImage> spriteImages;
private HashMap<String, Integer> spriteIdMap;
private ResourceCallback<Sprite> callback;
private SpriteImage current;
private int currentId = -1;
private boolean imagesDone = false; // true when images have finished loading
private boolean dataDone = false; // true when sprite data has finished loading
/**
* Do not call directly. Create using {@link SpriteLoader#getSprite(String, String)}
*/
Sprite(ImageLayer imageLayer) {
this.layer = imageLayer;
spriteImages = new ArrayList<SpriteImage>(0);
spriteIdMap = new HashMap<String, Integer>();
}
/**
* Set callback that will be called when both the sprite data and sprite image have been loaded.
*/
public void addCallback(ResourceCallback<Sprite> callback) {
this.callback = callback;
if (isReady()) {
callback.done(this);
}
}
/**
* Return the sprite {@link ImageLayer}.
*/
public ImageLayer layer() {
return layer;
}
/**
* Return the number of sprites.
*/
public int numSprites() {
return (spriteImages == null ? 0 : spriteImages.size());
}
/**
* Return the height of the current sprite.
*/
public float height() {
if (current != null) {
return current.height();
} else {
return 1;
}
}
/**
* Return true when both the sprite data and the sprite image have been loaded.
* <p>
* @see #addCallback(ResourceCallback)
*/
public boolean isReady() {
return imagesDone && dataDone;
}
/**
* Set the current sprite via the index.
* <p>
* The index is an integer between 0 and the number of sprites (@see {@link #numSprites()})
*/
public void setSprite(int index) {
Asserts.checkElementIndex(index, spriteImages.size(), "Invalid sprite index");
if (index != currentId) {
current = spriteImages.get(index);
currentId = index;
updateLayer();
}
}
/**
* Set the current sprite via the sprite's id.
*/
public void setSprite(String id) {
setSprite(Asserts.checkNotNull(spriteIdMap.get(id), "Invalid sprite id"));
}
/**
* Return the width of the current sprite.
*/
public float width() {
if (current != null) {
return current.width();
} else {
return 1;
}
}
/**
* Add a {@link SpriteImage} to the sprites.
*/
void addSpriteImage(String key, SpriteImage spriteImage) {
spriteIdMap.put(key, spriteImages.size());
spriteImages.add(spriteImage);
}
/**
* Should be called when the sprite data and sprite image have been loaded. Will handle calling
* the {@link ResourceCallback} of the {@link Sprite}.
*/
void done() {
if (callback != null) {
callback.done(this);
}
}
/**
* Should be called when the sprite image(s) is done loading.
*/
void doneLoadingImages() {
imagesDone = true;
if (isReady()) {
done();
}
}
/**
* Should be called when the sprite data is done loading.
*/
void doneLoadingData() {
dataDone = true;
if (isReady()) {
done();
}
}
/**
* Should be called if an error occurs when loading the sprite image or data. Will handle calling
* the {@link ResourceCallback} of the {@link Sprite}.
*/
void error(Throwable err) {
if (callback != null) {
callback.error(err);
} else {
// don't let the error fall on deaf ears
log().error("Error loading sprite", err);
}
}
/**
* Returns the {@link SpriteImage}s associated with this Sprite.
*/
List<SpriteImage> spriteImages() {
return spriteImages;
}
/**
* Update the Sprite layer.
*/
private void updateLayer() {
if (current != null) {
layer.setImage(current.image());
layer.setWidth(current.width());
layer.setHeight(current.height());
layer.setSourceRect(current.x(), current.y(), current.width(), current.height());
}
}
}