package com.lfk.justweengine.drawable.Sprite;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.renderscript.Float2;
import com.lfk.justweengine.anim.BaseAnim;
import com.lfk.justweengine.anim.DoAfterAnimation;
import com.lfk.justweengine.engine.Engine;
import com.lfk.justweengine.engine.GameTexture;
import com.lfk.justweengine.info.UIdefaultData;
import com.lfk.justweengine.utils.tools.DisplayUtils;
import java.util.LinkedList;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
/**
* 精灵基类
* 包含基础的加载图片和位置
*
* @author liufengkai
* Created by liufengkai on 15/11/27.
*/
public class BaseSprite extends BaseSub {
// 死或生
private boolean s_alive;
// 是否可碰撞 / 是否检测过
private boolean s_collidable, s_collided;
private BaseSub e_offender;
private int e_identifier;
private FrameType frameType;
private Canvas s_canvas;
// 图片
private GameTexture s_texture;
// 画笔
private Paint s_paint;
// 宽度高度
private int s_width, s_height;
// 帧动画的列
private int s_columns;
// 透明度
private int s_alpha;
// 帧数
private int s_frame;
// 缩放
private Float2 s_scale;
// 旋转
private float s_rotation;
// 固定动画
private ConcurrentHashMap<String, BaseAnim> animMap;
// 流式动画
private CopyOnWriteArrayList<BaseAnim> animList;
// 动画结束的回调
private DoAfterAnimation afterAnimation = null;
private LinkedList<Rect> s_frame_rect;
private Rect s_dst;
private Rect src;
private Matrix s_matrix, s_mat_scale, s_mat_rotate, s_mat_translation;
private Bitmap s_frameBitmap;
private Canvas s_frameCanvas;
/**
* easy init
*
* @param engine
*/
public BaseSprite(Engine engine) {
this(engine, 0, 0, 1);
this.frameType = FrameType.SIMPLE;
}
/**
* init with type
*
* @param engine
* @param w
* @param h
* @param type
*/
public BaseSprite(Engine engine, int w, int h, FrameType type) {
switch (type) {
case SIMPLE:
frameType = FrameType.SIMPLE;
break;
case COMMON:
frameType = FrameType.COMMON;
break;
}
this.s_engine = engine;
this.s_width = w;
this.s_height = h;
init();
}
/**
* init with long pic
*
* @param engine
* @param w
* @param h
* @param columns
*/
public BaseSprite(Engine engine, int w, int h, int columns) {
this.s_engine = engine;
this.s_width = w;
this.s_height = h;
this.s_columns = columns;
this.frameType = FrameType.FIXED;
init();
}
private void init() {
s_alpha = 255;
s_canvas = null;
s_texture = new GameTexture(s_engine);
s_paint = new Paint();
s_position = new Float2(0, 0);
s_frame = 0;
animMap = new ConcurrentHashMap<>();
animList = new CopyOnWriteArrayList<>();
s_scale = new Float2(1.0f, 1.0f);
s_rotation = 0.0f;
s_collidable = true;
s_collided = false;
s_alive = true;
if (frameType == FrameType.COMMON) {
s_frame_rect = new LinkedList<>();
} else if (frameType == FrameType.SIMPLE) {
this.s_columns = 1;
}
s_dst = new Rect();
src = new Rect();
s_mat_translation = new Matrix();
s_mat_scale = new Matrix();
s_mat_rotate = new Matrix();
s_matrix = new Matrix();
s_paint.setColor(UIdefaultData.sprite_default_color_paint);
}
public void setColor(int color) {
s_paint.setColor(color);
}
/**
* draw
*/
public void drawWithFixedFrame() {
// init width and height
if (s_width == 0 || s_height == 0) {
s_width = s_texture.getBitmap().getWidth();
s_height = s_texture.getBitmap().getHeight();
}
// scratch bitmap
if (s_frameBitmap == null) {
s_frameBitmap = Bitmap.createBitmap(s_width, s_height, Bitmap.Config.ARGB_8888);
s_frameCanvas = new Canvas(s_frameBitmap);
}
// calculate w/h in each frame
int u = (s_frame % s_columns) * s_width;
int v = (s_frame / s_columns) * s_height;
// set rect
src.set(u, v, u + s_width, v + s_height);
// scale
int w = s_width;//* s_scale.x
int h = s_height;
s_dst.set(0, 0, w, h);
// draw the frame
s_paint.setAlpha(s_alpha);
s_frameBitmap.eraseColor(Color.TRANSPARENT);
s_frameCanvas.drawBitmap(s_texture.getBitmap(), src, s_dst, s_paint);
s_matrix.reset();
s_mat_scale.reset();
s_mat_rotate.reset();
s_mat_translation.reset();
s_mat_scale.setScale((float) Math.sqrt(s_scale.x), (float) Math.sqrt(s_scale.y));
s_mat_rotate.setRotate((float) Math.toDegrees(s_rotation));
s_mat_translation.setTranslate(s_position.x, s_position.y);
s_matrix.postConcat(s_mat_scale);
s_matrix.postConcat(s_mat_rotate);
s_matrix.postConcat(s_mat_translation);
// update transform
s_canvas.drawBitmap(s_frameBitmap, s_matrix, s_paint);
}
/**
* draw
*/
@Override
public void draw() {
s_canvas = s_engine.getCanvas();
switch (frameType) {
case FIXED:
case SIMPLE:
drawWithFixedFrame();
break;
case COMMON:
drawWithFrame();
break;
}
debugDraw();
}
/**
* 绘制debug模式下的轮廓线
*/
public void debugDraw() {
s_engine.debugDraw(getBounds());
}
public void drawWithFrame() {
if (s_width == 0 || s_height == 0) {
s_width = s_frame_rect.getFirst().width();
s_height = s_frame_rect.getFirst().height();
}
if (!s_frame_rect.isEmpty()) {
int x = (int) s_position.x;
int y = (int) s_position.y;
int w = (int) (s_width * s_scale.x);
int h = (int) (s_height * s_scale.y);
s_dst.set(x, y, x + w, y + h);
s_paint.setAlpha(s_alpha);
s_canvas.drawBitmap(s_texture.getBitmap(),
s_frame_rect.get(s_frame),
s_dst, s_paint);
}
}
/**
* set / get alive
*/
@Override
public boolean getAlive() {
return s_alive;
}
public void setAlive(boolean s_alive) {
this.s_alive = s_alive;
}
/**
* set paint
*
* @param paint
*/
public void setPaint(Paint paint) {
s_paint = paint;
}
/**
* set texture
*
* @param s_texture
*/
public void setTexture(GameTexture s_texture) {
this.s_texture = s_texture;
}
/**
* get texture
*
* @return
*/
public GameTexture getTexture() {
return s_texture;
}
/**
* set position
*
* @param x
* @param y
*/
public void setPosition(float x, float y) {
s_position.x = x;
s_position.y = y;
}
/**
* set position with dip
*
* @param x
* @param y
*/
public void setDipPosition(int x, int y) {
s_position.x = DisplayUtils.dip2px(x);
s_position.y = DisplayUtils.dip2px(y);
}
/**
* get position
*
* @return
*/
public Float2 getPosition() {
return s_position;
}
/**
* set frame
*
* @param s_frame
*/
public void setFrame(int s_frame) {
this.s_frame = s_frame;
}
/**
* get frame
*
* @return
*/
public int getFrame() {
return s_frame;
}
/**
* set alpha
*
* @param s_alpha
*/
public void setAlpha(int s_alpha) {
this.s_alpha = s_alpha;
}
/**
* get alpha
*
* @return
*/
public int getAlpha() {
return s_alpha;
}
/**
* get height
*
* @return
*/
public int getHeight() {
return s_height;
}
/**
* get width
*
* @return
*/
public int getWidth() {
return s_width;
}
public int getWidthWithScale() {
return (int) (s_width * s_scale.x);
}
public int getHeightWidthScale() {
return (int) (s_height * s_scale.y);
}
/**
* set height
*
* @param h
*/
public void setHeight(int h) {
s_height = h;
}
/**
* set width
*
* @param w
*/
public void setWidth(int w) {
s_width = w;
}
/**
* get size
*
* @return
*/
public Float2 getSize() {
return new Float2(s_width, s_height);
}
/**
* get scale
*
* @return
*/
public Float2 getScale() {
return s_scale;
}
/**
* set scale
*
* @param scale
*/
public void setScale(Float2 scale) {
s_scale = scale;
}
public void setScale(float scale) {
s_scale = new Float2(scale, scale);
}
/**
* get / set rotation
*
* @return
*/
public float getRotation() {
return s_rotation;
}
public void setRotation(float s_rotation) {
this.s_rotation = s_rotation;
}
/**
* is collidable ?
*
* @return
*/
public boolean isCollidable() {
return s_collidable;
}
/**
* is collided ?
*
* @return
*/
public boolean isCollided() {
return s_collided;
}
/**
* set collidable
*
* @param s_collidable
*/
public void setCollidable(boolean s_collidable) {
this.s_collidable = s_collidable;
}
/**
* set collided
*
* @param s_collided
*/
public void setCollided(boolean s_collided) {
this.s_collided = s_collided;
}
/**
* get offender
*
* @return
*/
public BaseSub getOffender() {
return e_offender;
}
/**
* stop / clear / replace Animation
*/
public void clearAllAnimation() {
if (animList != null)
animList.clear();
}
public void clearAllFixedAnimation() {
if (animMap != null)
animMap.clear();
}
public void clearAnimation(int position) {
if (animList != null)
animList.remove(position);
}
public void clearFixedAnimation(String name) {
if (animMap != null)
animMap.remove(name);
}
public void removeAnimFromList(int index) {
if (animList != null && !animList.isEmpty())
animList.remove(index);
}
public void removeFixedAnimFromMap(String name) {
if (animMap != null && !animMap.isEmpty())
animMap.remove(name);
}
public void replaceFixedAnimFromMap(String name, BaseAnim anim) {
if (animMap != null && !animMap.isEmpty())
animMap.replace(name, anim);
}
/**
* set offender
*
* @param e_offender
*/
@Override
public void setOffender(BaseSub e_offender) {
this.e_offender = e_offender;
}
/**
* get Bounds
* 获取区域大小
*
* @return
*/
public RectF getBounds() {
// scaled
return new RectF((int) s_position.x, (int) s_position.y,
(int) (s_position.x + s_width * Math.sqrt(s_scale.x)),
(int) (s_position.y + s_height * Math.sqrt(s_scale.y)));//这里取平方根,不然假设scale=2,算出来就变成了放大4倍。
}
/**
* get / set Id
*
* @return
*/
@Override
public int getIdentifier() {
return e_identifier;
}
public void setIdentifier(int e_identifier) {
this.e_identifier = e_identifier;
}
/**
* get / set Name
*
* @return
*/
public String getName() {
return s_name;
}
public void setName(String s_name) {
this.s_name = s_name;
}
/**
* get / set FrameType
*
* @return
*/
public FrameType getFrameType() {
return frameType;
}
public void setFrameType(FrameType frameType) {
this.frameType = frameType;
}
/**
* add anim to list
*
* @param anim
*/
public void addAnimation(BaseAnim anim) {
animList.add(anim);
}
/**
* add fixed to Map
*
* @param name
* @param anim
*/
public void addfixedAnimation(String name, BaseAnim anim) {
animMap.put(name, anim);
}
/**
* do fixed anim
*
* @param name
*/
public void fixedAnimation(String name) {
if (animMap.isEmpty()) return;
BaseAnim anim = animMap.get(name);
// anim.animating = true;
if (anim.animating)
doAnimation(anim);
}
/**
* add rect frame for the common type
*
* @param x
* @param y
* @param w
* @param h
*/
public void addRectFrame(int x, int y, int w, int h) {
if (s_frame_rect != null) {
s_frame_rect.add(new Rect(x, y, x + w, y + h));
}
}
/**
* do the anim
*
* @param anim
*/
protected void doAnimation(BaseAnim anim) {
switch (anim.animType) {
case FRAME:
s_frame = anim.adjustFrame(s_frame);
break;
case ALPHA:
s_alpha = anim.adjustAlpha(s_alpha);
break;
case SCALE:
s_scale = anim.adjustScale(s_scale);
break;
case ROTATION:
s_rotation = anim.adjustRotation(s_rotation);
break;
case POSITION:
s_position = anim.adjustPosition(s_position);
break;
case ALIVE:
s_alive = anim.adjustAlive(s_alive);
break;
case SHOOT:
s_position = anim.adjustPosition(s_position);
s_alive = anim.adjustAlive(s_alive);
break;
case ZOOM:
s_scale = anim.adjustScale(s_scale);
break;
}
// listener
if (afterAnimation != null)
afterAnimation.afterAnimation();
}
/**
* list animation
*/
public void animation() {
if (animList.isEmpty()) return;
for (BaseAnim anim : animList) {
if (anim.animating) {
doAnimation(anim);
} else {
animList.remove(anim);
return;
}
}
}
/**
* 设定放大值,相当于设置dp宽高
*
* @param dp
*/
public void setDipWidth(int dp) {
s_scale.x = DisplayUtils.dip2px(dp) / s_width;
}
public void setDipHeight(int dp) {
s_scale.y = DisplayUtils.dip2px(dp) / s_height;
}
public void setDipScale(int dipWidth, int dipHeight) {
if (s_width == 0 || s_height == 0) {
s_width = s_texture.getBitmap().getWidth();
s_height = s_texture.getBitmap().getHeight();
}
setScale(new Float2(DisplayUtils.dip2px(dipWidth) / s_width,
DisplayUtils.dip2px(dipHeight) / s_height));
}
/**
* 动画后的接口回调
*
* @param afterAnimation
*/
public void setAfterAnimation(DoAfterAnimation afterAnimation) {
this.afterAnimation = afterAnimation;
}
/**
* 获取固定动画动作
*
* @param name
* @return
*/
public BaseAnim getFixedAnimation(String name) {
return animMap.get(name);
}
}