
org.flixel.FlxSprite Maven / Gradle / Ivy
The newest version!
package org.flixel;
import org.flixel.event.IFlxAnim;
import org.flixel.system.FlxAnim;
import org.flixel.system.gdx.ManagedTextureData;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.Pixmap;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.TextureData;
import com.badlogic.gdx.graphics.g2d.Sprite;
import com.badlogic.gdx.graphics.g2d.TextureAtlas.AtlasRegion;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.graphics.glutils.ShaderProgram;
import com.badlogic.gdx.utils.Array;
import flash.display.BlendMode;
/**
* The main "game object" class, the sprite is a FlxObject
* with a bunch of graphics options and abilities, like animation and stamping.
*
* @author Ka Wing Chin
* @author Thomas Weston
*/
public class FlxSprite extends FlxObject
{
protected static String ImgDefault = "org/flixel/data/pack:default";
/**
* Internal tracker for the current GLES10 blend mode that is used.
*/
protected static String currentBlend;
/**
* Internal tracker for the current shader that is used. NOTE: Requires
* GLES20.
*/
protected static ShaderProgram currentShader;
/**
* WARNING: The origin of the sprite will default to its center.
* If you change this, the visuals and the collisions will likely be
* pretty out-of-sync if you do any rotation.
*/
public FlxPoint origin;
/**
* If you changed the size of your sprite object after loading or making the graphic,
* you might need to offset the graphic away from the bound box to center it the way you want.
*/
public FlxPoint offset;
/**
* Change the size of your sprite's graphic.
* NOTE: Scale doesn't currently affect collisions automatically,
* you will need to adjust the width, height and offset manually.
*/
public FlxPoint scale;
/**
* Blending modes, just like Photoshop or whatever.
* E.g. "multiply", "screen", etc.
* @default null
*/
public String blend;
/**
* GLES20 Blending modes, just like Photoshop or whatever.
* Use BlendModeGL20.blend()
to create a blend. NOTE: Requires GLES20.
* @default null
*/
public ShaderProgram blendGL20;
/**
* The sprite that will be blended with the base.
* Only used with blendGL20
. NOTE: Requires GLES20.
* @default null
*/
public Texture blendTexture;
/**
* The shader program the object is using.
*/
public ShaderProgram shader;
/**
* Ignores the shader that is used by the SpriteBatch
.
* @default false;
*/
public boolean ignoreBatchShader;
/**
* Controls whether the object is smoothed when rotated, affects performance.
* @default false
*/
public boolean antialiasing;
/**
* Whether the current animation has finished its first (or only) loop.
*/
public boolean finished;
/**
* The width of the actual graphic or image being displayed (not necessarily the game object/bounding box).
* NOTE: Edit at your own risk!! This is intended to be read-only.
*/
public int frameWidth;
/**
* The height of the actual graphic or image being displayed (not necessarily the game object/bounding box).
* NOTE: Edit at your own risk!! This is intended to be read-only.
*/
public int frameHeight;
/**
* The Sprite
object representing the current display state of the sprite.
*/
public Sprite framePixels;
/**
* Set this flag to true to force the sprite to update during the draw() call.
* NOTE: Rarely if ever necessary, most sprite operations will flip this flag automatically.
*/
public boolean dirty;
/**
* Internal, stores all the animations that were added to this sprite.
*/
protected Array _animations;
/**
* Internal, keeps track of whether the sprite was loaded with support for automatic reverse/mirroring.
*/
protected int _flipped;
/**
* Internal, keeps track of the current animation being played.
*/
protected FlxAnim _curAnim;
/**
* Internal, keeps track of the current frame of animation.
* This is NOT an index into the tile sheet, but the frame number in the animation object.
*/
protected int _curFrame;
/**
* Internal, keeps track of the current index into the tile sheet based on animation or rotation.
*/
protected int _curIndex;
/**
* Internal, tracker for the maximum number of frames that can fit on the tile sheet, used with read-only getter.
* WARNING: assumes each row in the sprite sheet is full!
*/
protected int _maxFrames;
/**
* Internal, tracker for the number of frames on the tile sheet, used with
* Flash getter/setter.
*/
protected int _numFrames;
/**
* Internal, used to time each frame of animation.
*/
protected float _frameTimer;
/**
* Internal tracker for the animation callback. Default is null.
* If assigned, will be called each time the current frame changes.
* A function that has 3 parameters: a string name, a uint frame number, and a uint frame index.
*/
protected IFlxAnim _callback;
/**
* Internal tracker for what direction the sprite is currently facing, used with Flash getter/setter.
*/
protected int _facing;
/**
* Internal tracker for opacity, used with Flash getter/setter.
*/
protected float _alpha;
/**
* Internal tracker for color tint, used with Flash getter/setter.
*/
protected int _color;
/**
* Internal tracker for how many frames of "baked" rotation there are (if any).
*/
protected float _bakedRotation;
/**
* Internal, stores the entire source graphic (not the current displayed animation frame), used with getter/setter.
*/
protected AtlasRegion _pixels;
/**
* Internal tracker for reloading the texture if its pixmap has been modified.
*/
protected ManagedTextureData _newTextureData;
/**
* Creates a white 8x8 square FlxSprite
at the specified position.
* Optionally can load a simple, one-frame graphic instead.
*
* @param X The initial X position of the sprite.
* @param Y The initial Y position of the sprite.
* @param SimpleGraphic The graphic you want to display (OPTIONAL - for simple stuff only, do NOT use for animated images!).
*/
public FlxSprite(float X,float Y,String SimpleGraphic)
{
super(X,Y);
offset = new FlxPoint();
origin = new FlxPoint();
scale = new FlxPoint(1.0f,1.0f);
_alpha = 1f;
_color = 0x00ffffff;
blend = null;
ignoreBatchShader = false;
antialiasing = false;
cameras = null;
finished = false;
_facing = RIGHT;
_animations = new Array();
_flipped = 0;
_curAnim = null;
_curFrame = 0;
_curIndex = 0;
_numFrames = 0;
_maxFrames = 0;
_frameTimer = 0;
_callback = null;
_newTextureData = null;
if(SimpleGraphic == null)
SimpleGraphic = ImgDefault;
loadGraphic(SimpleGraphic);
}
/**
* Creates a white 8x8 square FlxSprite
at the specified position.
* Optionally can load a simple, one-frame graphic instead.
*
* @param X The initial X position of the sprite.
* @param Y The initial Y position of the sprite.
*/
public FlxSprite(float X,float Y)
{
this(X,Y,null);
}
/**
* Creates a white 8x8 square FlxSprite
at the specified position.
* Optionally can load a simple, one-frame graphic instead.
*
* @param X The initial X position of the sprite.
*/
public FlxSprite(float X)
{
this(X,0,null);
}
/**
* Creates a white 8x8 square FlxSprite
at the specified position.
* Optionally can load a simple, one-frame graphic instead.
*/
public FlxSprite()
{
this(0,0,null);
}
/**
* Clean up memory.
*/
@Override
public void destroy()
{
if(_animations != null)
{
FlxAnim a;
int i = 0;
int l = _animations.size;
while(i < l)
{
a = _animations.get(i++);
if(a != null)
a.destroy();
}
_animations = null;
}
offset = null;
origin = null;
scale = null;
_curAnim = null;
_callback = null;
_newTextureData = null;
framePixels = null;
currentBlend = null;
shader = null;
currentShader = null;
blendGL20 = null;
if(blendTexture != null)
blendTexture.dispose();
blendTexture = null;
super.destroy();
}
/**
* Load an image from an embedded graphic file.
*
* @param Graphic The image you want to use.
* @param Animated Whether the Graphic parameter is a single sprite or a row of sprites.
* @param Reverse Whether you need this class to generate horizontally flipped versions of the animation frames.
* @param Width Optional, specify the width of your sprite (helps FlxSprite figure out what to do with non-square sprites or sprite sheets).
* @param Height Optional, specify the height of your sprite (helps FlxSprite figure out what to do with non-square sprites or sprite sheets).
* @param Unique Optional, whether the graphic should be a unique instance in the graphics cache. Default is false.
*
* @return This FlxSprite instance (nice for chaining stuff together, if you're into that).
*/
public FlxSprite loadGraphic(String Graphic,boolean Animated,boolean Reverse,int Width,int Height,boolean Unique)
{
_bakedRotation = 0;
_pixels = FlxG.addBitmap(Graphic,Reverse,Unique);
if(Reverse)
_flipped = _pixels.getRegionWidth()>>1;
else
_flipped = 0;
if(Width == 0)
{
if(Animated)
Width = _pixels.rotate?_pixels.getRegionWidth():_pixels.getRegionHeight();
else
Width = _pixels.rotate?_pixels.getRegionHeight():_pixels.getRegionWidth();
}
width = frameWidth = Width;
if(Height == 0)
{
if(Animated)
Height = (int)width;
else
Height = _pixels.rotate?_pixels.getRegionWidth():_pixels.getRegionHeight();
}
height = frameHeight = Height;
resetHelpers();
return this;
}
/**
* Load an image from an embedded graphic file.
*
* @param Graphic The image you want to use.
* @param Animated Whether the Graphic parameter is a single sprite or a row of sprites.
* @param Reverse Whether you need this class to generate horizontally flipped versions of the animation frames.
* @param Width Optional, specify the width of your sprite (helps FlxSprite figure out what to do with non-square sprites or sprite sheets).
* @param Height Optional, specify the height of your sprite (helps FlxSprite figure out what to do with non-square sprites or sprite sheets).
*
* @return This FlxSprite instance (nice for chaining stuff together, if you're into that).
*/
public FlxSprite loadGraphic(String Graphic,boolean Animated,boolean Reverse,int Width,int Height)
{
return loadGraphic(Graphic,Animated,Reverse,Width,Height,false);
}
/**
* Load an image from an embedded graphic file.
*
* @param Graphic The image you want to use.
* @param Animated Whether the Graphic parameter is a single sprite or a row of sprites.
* @param Reverse Whether you need this class to generate horizontally flipped versions of the animation frames.
* @param Width Optional, specify the width of your sprite (helps FlxSprite figure out what to do with non-square sprites or sprite sheets).
*
* @return This FlxSprite instance (nice for chaining stuff together, if you're into that).
*/
public FlxSprite loadGraphic(String Graphic,boolean Animated,boolean Reverse,int Width)
{
return loadGraphic(Graphic,Animated,Reverse,Width,0,false);
}
/**
* Load an image from an embedded graphic file.
*
* @param Graphic The image you want to use.
* @param Animated Whether the Graphic parameter is a single sprite or a row of sprites.
* @param Reverse Whether you need this class to generate horizontally flipped versions of the animation frames.
*
* @return This FlxSprite instance (nice for chaining stuff together, if you're into that).
*/
public FlxSprite loadGraphic(String Graphic,boolean Animated,boolean Reverse)
{
return loadGraphic(Graphic,Animated,Reverse,0,0,false);
}
/**
* Load an image from an embedded graphic file.
*
* @param Graphic The image you want to use.
* @param Animated Whether the Graphic parameter is a single sprite or a row of sprites.
*
* @return This FlxSprite instance (nice for chaining stuff together, if you're into that).
*/
public FlxSprite loadGraphic(String Graphic,boolean Animated)
{
return loadGraphic(Graphic,Animated,false,0,0,false);
}
/**
* Load an image from an embedded graphic file.
*
* @param Graphic The image you want to use.
*
* @return This FlxSprite instance (nice for chaining stuff together, if you're into that).
*/
public FlxSprite loadGraphic(String Graphic)
{
return loadGraphic(Graphic,false,false,0,0,false);
}
/**
* Create a pre-rotated sprite sheet from a simple sprite.
* This can make a huge difference in graphical performance!
*
* @param Graphic The image you want to rotate and stamp.
* @param Rotations The number of rotation frames the final sprite should have. For small sprites this can be quite a large number (360 even) without any problems.
* @param Frame If the Graphic has a single row of square animation frames on it, you can specify which of the frames you want to use here. Default is -1, or "use whole graphic."
* @param AntiAliasing Whether to use high quality rotations when creating the graphic. Default is false.
* @param AutoBuffer Whether to automatically increase the image size to accommodate rotated corners. Default is false. Will create frames that are 150% larger on each axis than the original frame or graphic.
*
* @return This FlxSprite instance (nice for chaining stuff together, if you're into that).
*/
public FlxSprite loadRotatedGraphic(String Graphic, int Rotations, int Frame, boolean AntiAliasing, boolean AutoBuffer)
{
_bakedRotation = 0;
_pixels = FlxG.addBitmap(Graphic);
if(Frame >= 0)
{
width = frameWidth = _pixels.getRegionHeight();
int rx = (int)(Frame*width);
int ry = 0;
int fw = _pixels.getRegionWidth();
if(rx >= fw)
{
ry = (int)((rx/fw)*width);
rx %= fw;
}
_pixels.setRegion(rx + _pixels.getRegionX(), ry + _pixels.getRegionY(), (int) width, (int) width);
}
else
width = frameWidth = _pixels.getRegionWidth();
height = frameHeight = _pixels.getRegionHeight();
resetHelpers();
return this;
}
/**
* Create a pre-rotated sprite sheet from a simple sprite.
* This can make a huge difference in graphical performance!
*
* @param Graphic The image you want to rotate and stamp.
* @param Rotations The number of rotation frames the final sprite should have. For small sprites this can be quite a large number (360 even) without any problems.
* @param Frame If the Graphic has a single row of square animation frames on it, you can specify which of the frames you want to use here. Default is -1, or "use whole graphic."
* @param AntiAliasing Whether to use high quality rotations when creating the graphic. Default is false.
*
* @return This FlxSprite instance (nice for chaining stuff together, if you're into that).
*/
public FlxSprite loadRotatedGraphic(String Graphic, int Rotations, int Frame, boolean AntiAliasing)
{
return loadRotatedGraphic(Graphic, Rotations, Frame, AntiAliasing, false);
}
/**
* Create a pre-rotated sprite sheet from a simple sprite.
* This can make a huge difference in graphical performance!
*
* @param Graphic The image you want to rotate and stamp.
* @param Rotations The number of rotation frames the final sprite should have. For small sprites this can be quite a large number (360 even) without any problems.
* @param Frame If the Graphic has a single row of square animation frames on it, you can specify which of the frames you want to use here. Default is -1, or "use whole graphic."
*
* @return This FlxSprite instance (nice for chaining stuff together, if you're into that).
*/
public FlxSprite loadRotatedGraphic(String Graphic, int Rotations, int Frame)
{
return loadRotatedGraphic(Graphic, Rotations, Frame, false, false);
}
/**
* Create a pre-rotated sprite sheet from a simple sprite.
* This can make a huge difference in graphical performance!
*
* @param Graphic The image you want to rotate and stamp.
* @param Rotations The number of rotation frames the final sprite should have. For small sprites this can be quite a large number (360 even) without any problems.
*
* @return This FlxSprite instance (nice for chaining stuff together, if you're into that).
*/
public FlxSprite loadRotatedGraphic(String Graphic, int Rotations)
{
return loadRotatedGraphic(Graphic, Rotations, -1, false, false);
}
/**
* Create a pre-rotated sprite sheet from a simple sprite.
* This can make a huge difference in graphical performance!
*
* @param Graphic The image you want to rotate and stamp.
* @param Rotations The number of rotation frames the final sprite should have. For small sprites this can be quite a large number (360 even) without any problems.
* @param Frame If the Graphic has a single row of square animation frames on it, you can specify which of the frames you want to use here. Default is -1, or "use whole graphic."
* @param AntiAliasing Whether to use high quality rotations when creating the graphic. Default is false.
* @param AutoBuffer Whether to automatically increase the image size to accommodate rotated corners. Default is false. Will create frames that are 150% larger on each axis than the original frame or graphic.
*
* @return This FlxSprite instance (nice for chaining stuff together, if you're into that).
*/
public FlxSprite loadRotatedGraphic(String Graphic)
{
return loadRotatedGraphic(Graphic, 16, -1, false, false);
}
/**
* This function creates a flat colored square image dynamically.
*
* @param Width The width of the sprite you want to generate.
* @param Height The height of the sprite you want to generate.
* @param Color Specifies the color of the generated block.
* @param Unique Whether the graphic should be a unique instance in the graphics cache. Default is false.
* @param Key Optional parameter - specify a string key to identify this graphic in the cache. Trumps Unique flag.
*
* @return This FlxSprite instance (nice for chaining stuff together, if you're into that).
*/
public FlxSprite makeGraphic(int Width,int Height,int Color,boolean Unique,String Key)
{
_bakedRotation = 0;
_pixels = FlxG.createBitmap(Width,Height,Color,Unique,Key);
width = frameWidth = Width;
height = frameHeight = Height;
resetHelpers();
return this;
}
/**
* This function creates a flat colored square image dynamically.
*
* @param Width The width of the sprite you want to generate.
* @param Height The height of the sprite you want to generate.
* @param Color Specifies the color of the generated block.
* @param Unique Whether the graphic should be a unique instance in the graphics cache. Default is false.
*
* @return This FlxSprite instance (nice for chaining stuff together, if you're into that).
*/
public FlxSprite makeGraphic(int Width,int Height,int Color,boolean Unique)
{
return makeGraphic(Width,Height,Color,Unique,null);
}
/**
* This function creates a flat colored square image dynamically.
*
* @param Width The width of the sprite you want to generate.
* @param Height The height of the sprite you want to generate.
* @param Color Specifies the color of the generated block.
*
* @return This FlxSprite instance (nice for chaining stuff together, if you're into that).
*/
public FlxSprite makeGraphic(int Width,int Height,int Color)
{
return makeGraphic(Width,Height,Color,false,null);
}
/**
* This function creates a flat colored square image dynamically.
*
* @param Width The width of the sprite you want to generate.
* @param Height The height of the sprite you want to generate.
*
* @return This FlxSprite instance (nice for chaining stuff together, if you're into that).
*/
public FlxSprite makeGraphic(int Width,int Height)
{
return makeGraphic(Width,Height,0xffffffff,false,null);
}
/**
* Resets some important variables for sprite optimization and rendering.
*/
protected void resetHelpers()
{
if(framePixels == null)
framePixels = new Sprite(_pixels);
framePixels.setRegion(_pixels,0,0,frameWidth,frameHeight);
framePixels.setSize(frameWidth,frameHeight);
framePixels.flip(false, true);
origin.make(frameWidth*0.5f,frameHeight*0.5f);
_curIndex = 0;
_numFrames = 0;
int widthHelper = _pixels.rotate?_pixels.getRegionHeight():_pixels.getRegionWidth();
int maxFramesX = FlxU.floor(widthHelper/frameWidth);
int maxFramesY = FlxU.floor((_pixels.rotate?_pixels.getRegionWidth():_pixels.getRegionHeight()) / frameHeight);
_maxFrames = maxFramesX*maxFramesY;
//rotated texture region.
if(_pixels.rotate)
{
framePixels.setRegion(_pixels.getRegionX(),_pixels.getRegionY(), frameHeight, frameWidth);
framePixels.flip(false,true);
dirty = true;
}
}
/**
* Automatically called after update() by the game loop,
* this function just calls updateAnimation().
*/
@Override
public void postUpdate()
{
super.postUpdate();
updateAnimation();
}
/**
* Called by game loop, updates then blits or renders current frame of animation to the screen
*/
@Override
public void draw()
{
if(_flicker)
return;
if(dirty) //rarely
calcFrame();
if(_newTextureData != null) //even more rarely
{
_pixels.getTexture().load(_newTextureData);
_newTextureData = null;
}
FlxCamera camera = FlxG._activeCamera;
if(cameras == null)
cameras = FlxG.cameras;
if(!cameras.contains(camera, true))
return;
if(!onScreen(camera))
return;
_point.x = x - (camera.scroll.x*scrollFactor.x) - offset.x;
_point.y = y - (camera.scroll.y*scrollFactor.y) - offset.y;
_point.x += (_point.x > 0)?0.0000001f:-0.0000001f;
_point.y += (_point.y > 0)?0.0000001f:-0.0000001f;
//tinting
int tintColor = FlxU.multiplyColors(_color, camera.getColor());
framePixels.setColor(((tintColor >> 16) & 0xff) * 0.00392f, ((tintColor >> 8) & 0xff) * 0.00392f, (tintColor & 0xff) * 0.00392f, _alpha);
//rotate
if(_pixels.rotate)
framePixels.rotate90(false);
if(isSimpleRender())
{
//Simple render
framePixels.setPosition(_point.x,_point.y);
renderSprite();
}
else
{
//Advanced render
framePixels.setOrigin(origin.x,origin.y);
framePixels.setScale(scale.x,scale.y);
if((angle != 0) && (_bakedRotation <= 0))
framePixels.setRotation(angle);
framePixels.setPosition(_point.x,_point.y);
if(blend != null && currentBlend != blend)
{
currentBlend = blend;
int[] blendFunc = BlendMode.getOpenGLBlendMode(blend);
FlxG.batch.setBlendFunction(blendFunc[0], blendFunc[1]);
}
else if(FlxG.batchShader == null || ignoreBatchShader)
{
//OpenGL ES 2.0 shader render
renderShader();
//OpenGL ES 2.0 blend mode render
renderBlend();
}
renderSprite();
}
//re-rotate
if(_pixels.rotate)
framePixels.rotate90(true);
_VISIBLECOUNT++;
if(FlxG.visualDebug && !ignoreDrawDebug)
drawDebug(camera);
}
/**
* Override this method to customize the rendering before it gets drawn on screen.
*/
public void renderSprite()
{
framePixels.draw(FlxG.batch);
}
/**
* Override this method to customize the texture and shader bindings.
*/
public void renderShader()
{
if((shader != null && currentShader != shader))
FlxG.batch.setShader(currentShader = shader);
else if(shader == null && currentShader != null)
FlxG.batch.setShader(currentShader = null);
}
/**
* Override this method to customize the blending.
*/
public void renderBlend()
{
if(blendGL20 != null && blendTexture != null)
{
FlxG.batch.setShader(blendGL20);
getTexture().bind(1);
blendTexture.bind(2);
Gdx.gl.glActiveTexture(GL20.GL_TEXTURE0);
}
}
/**
* This function draws or stamps one FlxSprite
onto another.
* This function is NOT intended to replace draw()
!
*
* @param Brush The image you want to use as a brush or stamp or pen or whatever.
* @param X The X coordinate of the brush's top left corner on this sprite.
* @param Y The Y coordinate of the brush's top left corner on this sprite.
*/
public void stamp(FlxSprite Brush,int X,int Y)
{
Brush.drawFrame();
TextureData brushTextureData = Brush.framePixels.getTexture().getTextureData();
if(!brushTextureData.isPrepared())
brushTextureData.prepare();
Pixmap brushPixmap = brushTextureData.consumePixmap();
stamp(brushPixmap, Brush.framePixels.getRegionX(), Brush.framePixels.getRegionY() - Brush.frameHeight, Brush.frameWidth, Brush.frameHeight, X + _pixels.getRegionX(), Y + _pixels.getRegionY());
if(brushTextureData.disposePixmap())
brushPixmap.dispose();
}
/**
* This function draws or stamps one FlxSprite
onto another.
* This function is NOT intended to replace draw()
!
*
* @param Brush The image you want to use as a brush or stamp or pen or whatever.
* @param X The X coordinate of the brush's top left corner on this sprite.
*/
public void stamp(FlxSprite Brush,int X)
{
stamp(Brush,X,0);
}
/**
* This function draws or stamps one FlxSprite
onto another.
* This function is NOT intended to replace draw()
!
*
* @param Brush The image you want to use as a brush or stamp or pen or whatever.
*/
public void stamp(FlxSprite Brush)
{
stamp(Brush,0,0);
}
/**
* This function draws or stamps one FlxSprite
onto another.
* This function is NOT intended to replace draw()
!
*
* @param Brush The image you want to use as a brush or stamp or pen or whatever.
* @param SourceX The X coordinate of the brush's top left corner.
* @param SourceY They Y coordinate of the brush's top left corner.
* @param SourceWidth The brush's width.
* @param SourceHeight The brush's height.
* @param DestinationX The X coordinate of the brush's top left corner on this sprite.
* @param DestinationY The Y coordinate of the brush's top right corner on this sprite.
*/
public void stamp(Pixmap Brush,int SourceX,int SourceY,int SourceWidth,int SourceHeight,int DestinationX,int DestinationY)
{
TextureData textureData = null;
if(_newTextureData != null)
textureData = _newTextureData;
else
textureData = _pixels.getTexture().getTextureData();
if(!textureData.isPrepared())
textureData.prepare();
Pixmap pixmap = textureData.consumePixmap();
pixmap.setFilter(Pixmap.Filter.NearestNeighbour);
pixmap.drawPixmap(Brush, SourceX, SourceY, SourceWidth, SourceHeight, DestinationX, DestinationY, SourceWidth, SourceHeight);
_newTextureData = new ManagedTextureData(pixmap);
}
/**
* This function draws a line on this sprite from position X1,Y1
* to position X2,Y2 with the specified color.
*
* @param StartX X coordinate of the line's start point.
* @param StartY Y coordinate of the line's start point.
* @param EndX X coordinate of the line's end point.
* @param EndY Y coordinate of the line's end point.
* @param Color The line's color.
* @param Thickness How thick the line is in pixels (default value is 1). Note - unimplemented.
*/
public void drawLine(float StartX,float StartY,float EndX,float EndY,int Color,int Thickness)
{
TextureData textureData = null;
if(_newTextureData != null)
textureData = _newTextureData;
else
textureData = _pixels.getTexture().getTextureData();
if(!textureData.isPrepared())
textureData.prepare();
int rx = _pixels.getRegionX();
int ry = _pixels.getRegionY();
Pixmap pixmap = textureData.consumePixmap();
pixmap.setBlending(Pixmap.Blending.SourceOver);
pixmap.setFilter(Pixmap.Filter.NearestNeighbour);
pixmap.setColor(FlxU.argbToRgba(Color));
pixmap.drawLine((int) (rx + StartX), (int) (ry + StartY), (int) (rx + EndX), (int) (ry + EndY));
_newTextureData = new ManagedTextureData(pixmap);
}
/**
* This function draws a line on this sprite from position X1,Y1
* to position X2,Y2 with the specified color.
*
* @param StartX X coordinate of the line's start point.
* @param StartY Y coordinate of the line's start point.
* @param EndX X coordinate of the line's end point.
* @param EndY Y coordinate of the line's end point.
* @param Color The line's color.
*/
public void drawLine(float StartX,float StartY,float EndX,float EndY,int Color)
{
drawLine(StartX,StartY,EndX,EndY,Color,1);
}
/**
* Fills this sprite's graphic with a specific color.
*
* @param Color The color with which to fill the graphic, format 0xAARRGGBB.
*/
public void fill(int Color)
{
TextureData textureData = null;
if(_newTextureData != null)
textureData = _newTextureData;
else
textureData = _pixels.getTexture().getTextureData();
if(!textureData.isPrepared())
textureData.prepare();
Pixmap pixmap = textureData.consumePixmap();
pixmap.setBlending(Pixmap.Blending.None);
pixmap.setFilter(Pixmap.Filter.NearestNeighbour);
pixmap.setColor(FlxU.argbToRgba(Color));
pixmap.fillRectangle(_pixels.getRegionX(), _pixels.getRegionY(), _pixels.getRegionWidth(), _pixels.getRegionHeight());
_newTextureData = new ManagedTextureData(pixmap);
}
/**
* Internal function for updating the sprite's animation.
* Useful for cases when you need to update this but are buried down in too many supers.
* This function is called automatically by FlxSprite.postUpdate()
.
*/
protected void updateAnimation()
{
if(_bakedRotation > 0)
{
int oldIndex = _curIndex;
int angleHelper = (int)(angle%360);
if(angleHelper < 0)
angleHelper += 360;
_curIndex = (int)(angleHelper/_bakedRotation + 0.5f);
if(oldIndex != _curIndex)
dirty = true;
}
else if((_curAnim != null) && (_curAnim.delay > 0) && (_curAnim.looped || !finished))
{
_frameTimer += FlxG.elapsed;
while(_frameTimer > _curAnim.delay)
{
_frameTimer = _frameTimer - _curAnim.delay;
if(_curFrame == _curAnim.frames.size-1)
{
if(_curAnim.looped)
_curFrame = 0;
finished = true;
}
else
_curFrame++;
trySetIndex(_curAnim.frames.get(_curFrame));
}
}
if(dirty)
calcFrame();
}
/**
* Request (or force) that the sprite update the frame before rendering.
* Useful if you are doing procedural generation or other weirdness!
*
* @param Force Force the frame to redraw, even if its not flagged as necessary.
*/
public void drawFrame(boolean Force)
{
if(Force || dirty)
calcFrame();
}
/**
* Request (or force) that the sprite update the frame before rendering.
* Useful if you are doing procedural generation or other weirdness!
*/
public void drawFrame()
{
drawFrame(false);
}
/**
* Adds a new animation to the sprite.
*
* @param Name What this animation should be called (e.g. "run").
* @param Frames An array of numbers indicating what frames to play in what order (e.g. 1, 2, 3).
* @param FrameRate The speed in frames per second that the animation should play at (e.g. 40 fps).
* @param Looped Whether or not the animation is looped or just plays once.
*/
public void addAnimation(String Name, int[] Frames, int FrameRate, boolean Looped)
{
_animations.add(new FlxAnim(Name,Frames,FrameRate,Looped));
}
/**
* Adds a new animation to the sprite.
*
* @param Name What this animation should be called (e.g. "run").
* @param Frames An array of numbers indicating what frames to play in what order (e.g. 1, 2, 3).
* @param FrameRate The speed in frames per second that the animation should play at (e.g. 40 fps).
*/
public void addAnimation(String Name, int[] Frames, int FrameRate)
{
addAnimation(Name, Frames, FrameRate, true);
}
/**
* Adds a new animation to the sprite.
*
* @param Name What this animation should be called (e.g. "run").
* @param Frames An array of numbers indicating what frames to play in what order (e.g. 1, 2, 3).
*/
public void addAnimation(String Name, int[] Frames)
{
addAnimation(Name, Frames, 0, true);
}
/**
* Pass in a function to be called whenever this sprite's animation changes.
*
* @param AnimationCallback A function that has 3 parameters: a string name, a uint frame number, and a uint frame index.
*/
public void addAnimationCallback(IFlxAnim AnimationCallback)
{
_callback = AnimationCallback;
}
/**
* Plays an existing animation (e.g. "run").
* If you call an animation that is already playing it will be ignored.
*
* @param AnimName The string name of the animation you want to play.
* @param Force Whether to force the animation to restart.
* @param StartFrame Which frame of the animation to start from if possible.
*/
public void play(String AnimName,boolean Force,int StartFrame)
{
if(!Force && (_curAnim != null) && (AnimName.equals(_curAnim.name)) && (_curAnim.looped || !finished)) return;
if(StartFrame <= _animations.size)
_curFrame = StartFrame;
else
_curFrame = 0;
_curIndex = 0;
_frameTimer = 0;
int i = 0;
int l = _animations.size;
while(i < l)
{
if(_animations.get(i).name.equals(AnimName))
{
_curAnim = _animations.get(i);
if(_curAnim.delay <= 0)
finished = true;
else
finished = false;
trySetIndex(_curAnim.frames.get(_curFrame));
return;
}
i++;
}
FlxG.log("FlxSprite", "WARNING: No animation called \"" + AnimName + "\"");
}
/**
* Plays an existing animation (e.g. "run").
* If you call an animation that is already playing it will be ignored.
*
* @param AnimName The string name of the animation you want to play.
* @param Force Whether to force the animation to restart.
*/
public void play(String AnimName,boolean Force)
{
play(AnimName,Force,0);
}
/**
* Plays an existing animation (e.g. "run").
* If you call an animation that is already playing it will be ignored.
*
* @param AnimName The string name of the animation you want to play.
*/
public void play(String AnimName)
{
play(AnimName,false,0);
}
/**
* Tell the sprite to change to a random frame of animation
* Useful for instantiating particles or other weird things.
*/
public void randomFrame()
{
_curAnim = null;
trySetIndex((int)(FlxG.random()*getNumFrames()));
}
/**
* Helper function that just sets origin to (0,0)
*/
public void setOriginToCorner()
{
origin.x = origin.y = 0;
}
/**
* Helper function that adjusts the offset automatically to center the bounding box within the graphic.
*
* @param AdjustPosition Adjusts the actual X and Y position just once to match the offset change. Default is false.
*/
public void centerOffsets(boolean AdjustPosition)
{
offset.x = (frameWidth-width)*0.5f;
offset.y = (frameHeight-height)*0.5f;
if(AdjustPosition)
{
x += offset.x;
y += offset.y;
}
}
/**
* Helper function that adjusts the offset automatically to center the bounding box within the graphic.
*/
public void centerOffsets()
{
centerOffsets(false);
}
public Array replaceColor(int Color,int NewColor,boolean FetchPositions)
{
Array positions = null;
if(FetchPositions)
positions = new Array();
Color = FlxU.argbToRgba(Color);
NewColor = FlxU.argbToRgba(NewColor);
int row = _pixels.getRegionY();
int column;
int rows = _pixels.getRegionHeight() + row;
int columns = _pixels.getRegionWidth() + _pixels.getRegionX();
TextureData textureData = null;
if(_newTextureData != null)
textureData = _newTextureData;
else
textureData = _pixels.getTexture().getTextureData();
if(!textureData.isPrepared())
textureData.prepare();
Pixmap pixmap = textureData.consumePixmap();
pixmap.setBlending(Pixmap.Blending.None);
pixmap.setFilter(Pixmap.Filter.NearestNeighbour);
while(row < rows)
{
column = _pixels.getRegionX();
while(column < columns)
{
if(pixmap.getPixel(column, row) == Color)
{
pixmap.drawPixel(column, row, NewColor);
if(FetchPositions)
positions.add(new FlxPoint(column - _pixels.getRegionX(), row - _pixels.getRegionY()));
}
column++;
}
row++;
}
_newTextureData = new ManagedTextureData(pixmap);
return positions;
}
public void replaceColor(int Color,int NewColor)
{
replaceColor(Color,NewColor,false);
}
/**
* Set pixels
to any TextureRegion
object.
* Automatically adjust graphic size and render helpers.
*/
public TextureRegion getPixels()
{
if(_newTextureData != null)
{
_pixels.getTexture().load(_newTextureData);
}
return _pixels;
}
/**
* Set pixels
to any AtlasRegion
object.
* Automatically adjust graphic size and render helpers.
*/
public void setPixels(AtlasRegion Pixels)
{
_pixels = Pixels;
width = frameWidth = _pixels.getRegionWidth();
height = frameHeight = _pixels.getRegionHeight();
resetHelpers();
}
/**
* Set pixels
to any TextureRegion
object.
* Automatically adjust graphic size and render helpers.
*/
public void setPixels(TextureRegion Pixels)
{
width = frameWidth = Pixels.getRegionWidth();
height = frameHeight = Pixels.getRegionHeight();
_pixels.setRegion(Pixels, 0, 0, (int) width, (int) height);
resetHelpers();
}
/**
* Set facing
using FlxSprite.LEFT
, RIGHT
,
* UP
, and DOWN
to take advantage of
* flipped sprites and/or just track player orientation more easily.
*/
public int getFacing()
{
return _facing;
}
/**
* Set facing
using FlxSprite.LEFT
, RIGHT
,
* UP
, and DOWN
to take advantage of
* flipped sprites and/or just track player orientation more easily.
*/
public void setFacing(int Direction)
{
if(_facing != Direction)
dirty = true;
_facing = Direction;
}
/**
* Set alpha
to a number between 0 and 1 to change the opacity of the sprite.
*/
public float getAlpha()
{
return _alpha;
}
/**
* Set alpha
to a number between 0 and 1 to change the opacity of the sprite.
*/
public void setAlpha(float Alpha)
{
if(Alpha > 1)
Alpha = 1;
if(Alpha < 0)
Alpha = 0;
if(Alpha == _alpha)
return;
_alpha = Alpha;
dirty = true;
}
/**
* Set color
to a number in this format: 0xRRGGBB.
* color
IGNORES ALPHA. To change the opacity use alpha
.
* Tints the whole sprite to be this color (similar to OpenGL vertex colors).
*/
public int getColor()
{
return _color;
}
/**
* Set color
to a number in this format: 0xRRGGBB.
* color
IGNORES ALPHA. To change the opacity use alpha
.
* Tints the whole sprite to be this color (similar to OpenGL vertex colors).
*/
public void setColor(int Color)
{
Color &= 0x00ffffff;
_color = Color;
}
/**
* Tell the sprite to change to a specific frame of animation.
*/
public int getFrame()
{
return _curIndex;
}
/**
* Tell the sprite to change to a specific frame of animation.
*
* @param Frame The frame you want to display.
*/
public void setFrame(int Frame)
{
if(Frame >= getNumFrames())
{
FlxG.log("WARNING: The frame number of a " + this + " must be less than its `numFrames` value.");
Frame = getNumFrames() - 1;
}
_curAnim = null;
_curIndex = Frame;
dirty = true;
}
/**
* Try setting the `_curIndex` value to the specified value, extracted out
* to avoid duplicate code. If it is outside of the allowed bounds, it will
* still set the variable to the nearest possible value, but will return
* false, allowing internal code to throw its own error messages (if
* necessary). Will re-draw even if the frame hasn't changed (Adam had it
* that way, I'll just assume he did that on purpose).
*/
private boolean trySetIndex(int Value)
{
_curIndex = Value;
dirty = true;
if(_curIndex >= getNumFrames())
{
_curIndex = getNumFrames();
FlxG.log("WARNING: A " + this + " animation is trying to set the frame number of its FlxSprite out of bounds.");
return false;
}
return true;
}
/**
* The maximum number of frames that can fit on the sprite sheet, calculated
* based on the size of the each frame and the
*/
public int getMaxFrames()
{
return _maxFrames;
}
/**
* The number of frames that are on the sprite sheet. Defaults to
* maxFrames
if no value is set.
*
* @param NumFrames The number of frames on the sprite sheet. Has to be a value between 1
and maxFrames
.
*/
public int getNumFrames()
{
return (_numFrames == 0) ? getMaxFrames() : _numFrames;
}
/**
* @private
*/
public void setNumFrames(int NumFrames)
{
if(NumFrames < 1)
{
FlxG.log("ERROR: Cannot set the number of frames on a " + this + " to less than 1.");
_numFrames = 1;
return;
}
if(NumFrames > _maxFrames)
{
FlxG.log("ERROR: Cannot set the number of frames on a " + this + " higher than its `maxFrames` value (" + _maxFrames + ").");
_numFrames = _maxFrames;
return;
}
//Will only re-render if the current frame number has changed
if(_curIndex >= _numFrames)
{
_curIndex = _numFrames - 1;
}
}
/**
* Check and see if this object is currently on screen.
* Differs from FlxObject
's implementation
* in that it takes the actual graphic into account,
* not just the hitbox or bounding box or whatever.
*
* @param Camera Specify which game camera you want. If null getScreenXY() will just grab the first global camera.
*
* @return Whether the object is on screen or not.
*/
@Override
public boolean onScreen(FlxCamera Camera)
{
if(Camera == null)
Camera = FlxG.camera;
getScreenXY(_point,Camera);
_point.x = _point.x - offset.x;
_point.y = _point.y - offset.y;
if(((angle == 0) || (_bakedRotation > 0)) && (scale.x == 1) && (scale.y == 1))
return ((_point.x + frameWidth > 0) && (_point.x < Camera.width) && (_point.y + frameHeight > 0) && (_point.y < Camera.height));
float halfWidth = frameWidth/2f;
float halfHeight = frameHeight/2f;
float absScaleX = (scale.x>0)?scale.x:-scale.x;
float absScaleY = (scale.y>0)?scale.y:-scale.y;
float radius = (float)(Math.sqrt(halfWidth*halfWidth+halfHeight*halfHeight)*((absScaleX >= absScaleY)?absScaleX:absScaleY));
_point.x += halfWidth;
_point.y += halfHeight;
return ((_point.x + radius > 0) && (_point.x - radius < Camera.width) && (_point.y + radius > 0) && (_point.y - radius < Camera.height));
}
/**
* Check and see if this object is currently on screen.
* Differs from FlxObject
's implementation
* in that it takes the actual graphic into account,
* not just the hitbox or bounding box or whatever.
*
* @return Whether the object is on screen or not.
*/
@Override
public boolean onScreen()
{
return onScreen(null);
}
/**
* Checks to see if a point in 2D world space overlaps this FlxSprite
object's current displayed pixels.
* This check is ALWAYS made in screen space, and always takes scroll factors into account.
*
* @param Point The point in world space you want to check.
* @param Mask Used in the pixel hit test to determine what counts as solid.
* @param Camera Specify which game camera you want. If null getScreenXY() will just grab the first global camera.
*
* @return Whether or not the point overlaps this object.
*/
// TODO: pixel hittest. Loading the pixmap will be too slow to be usable, is
// there another way?
public boolean pixelsOverlapPoint(FlxPoint Point,int Mask,FlxCamera Camera)
{
if(Camera == null)
Camera = FlxG.camera;
getScreenXY(_point,Camera);
_point.x = _point.x - offset.x;
_point.y = _point.y - offset.y;
// _flashPoint.x = (int) ((Point.x - Camera.scroll.x) - _point.x);
// _flashPoint.y = (int) ((Point.y - Camera.scroll.y) - _point.y);
return false;// framePixels.hitTest(_flashPointZero,Mask,_flashPoint);
}
/**
* Checks to see if a point in 2D world space overlaps this FlxSprite
object's current displayed pixels.
* This check is ALWAYS made in screen space, and always takes scroll factors into account.
*
* @param Point The point in world space you want to check.
* @param Mask Used in the pixel hit test to determine what counts as solid.
*
* @return Whether or not the point overlaps this object.
*/
public boolean pixelsOverlapPoint(FlxPoint Point,int Mask)
{
return pixelsOverlapPoint(Point, Mask, null);
}
/**
* Checks to see if a point in 2D world space overlaps this FlxSprite
object's current displayed pixels.
* This check is ALWAYS made in screen space, and always takes scroll factors into account.
*
* @param Point The point in world space you want to check.
*
* @return Whether or not the point overlaps this object.
*/
public boolean pixelsOverlapPoint(FlxPoint Point)
{
return pixelsOverlapPoint(Point,0xFF,null);
}
@Override
public boolean isSimpleRender()
{
if(((angle == 0) || (_bakedRotation > 0)) && (scale.x == 1) && (scale.y == 1) && (blend == null)
&& ((shader == null) && (blendGL20 == null) || (FlxG.batchShader != null && !ignoreBatchShader)))
{
if(currentBlend != null)
{
currentBlend = null;
FlxG.batch.setBlendFunction(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA);
}
if(FlxG.batchShader != null && !ignoreBatchShader)
FlxG.batch.setShader(FlxG.batchShader);
else
{
if(currentShader != null)
FlxG.batch.setShader(currentShader = null);
if(blendGL20 == null)
FlxG.batch.setShader(null);
}
return true;
}
return false;
}
public Texture getTexture()
{
return _pixels.getTexture();
}
/**
* Internal function to update the current animation frame.
*/
protected void calcFrame()
{
int indexY;
int indexX;
//Handle sprite sheets
int widthHelper = _pixels.getRegionWidth();
int heightHelper = _pixels.getRegionHeight();
if(!_pixels.rotate)
{
indexX = _curIndex * frameWidth;
indexY = 0;
}
else
{
indexY = (heightHelper - frameWidth) - (_curIndex * frameWidth);
indexX = 0;
}
if(indexX >= widthHelper)
{
indexY = (int) (indexX / widthHelper) * frameHeight;
indexX %= widthHelper;
}
if(indexY >= heightHelper)
{
indexY = heightHelper - frameHeight;
indexX = widthHelper - frameWidth;
}
//Update display bitmap
if(!_pixels.rotate)
framePixels.setRegion(indexX + _pixels.getRegionX(), indexY + _pixels.getRegionY(), frameWidth, frameHeight);
else
framePixels.setRegion(indexX + _pixels.getRegionX(), indexY + _pixels.getRegionY(), frameHeight, frameWidth);
//handle reversed sprites.
if(_flipped > 0 && _facing == LEFT && _pixels.rotate)
framePixels.flip(false, false);
else if(_flipped > 0 && _facing == LEFT)
framePixels.flip(true, true);
else
framePixels.flip(false, true);
if(_callback != null)
_callback.callback(((_curAnim != null) ? (_curAnim.name) : null), _curFrame, _curIndex);
dirty = false;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy