package com.junerking.skeleton; import java.util.ArrayList; import com.badlogic.gdx.math.MathUtils; import com.junerking.skeleton.DataDef.FrameData; import com.junerking.skeleton.DataDef.MovementBoneData; import com.junerking.skeleton.DataDef.NodeData; public class Tween extends ProcessBase { private static final float HALF_PI = MathUtils.PI * 0.5f; protected FrameData node; private FrameData _from; private FrameData _between; private MovementBoneData movement_bone_data; private int _between_duration; private int _total_duration; private int _frame_tween_easing = -2; private Bone _bone; public Tween(Bone bone) { this._bone = bone; _from = new FrameData(); _between = new FrameData(); node = new FrameData(); } //duration_to:其他动作切换到现在动作需要的frame数目 //duration_tween:当前动作的所有总共frame数目,和上层的movementdata中的frame数一致 @Override public void gotoAndPlay(Object movement_bone_data, int duration_to, int duration_tween, boolean loop, int tween_easing) { this.movement_bone_data = (MovementBoneData) movement_bone_data; if (this.movement_bone_data == null) return; super.gotoAndPlay(null, duration_to, duration_tween, loop, tween_easing); _total_duration = 0; _between_duration = 0; _from_index = 0; _to_index = 0; int frame_list_size = this.movement_bone_data.getFrameDataList().size(); FrameData _next_key_frame = this.movement_bone_data.getFrameData(0); _duration = this.movement_bone_data.duration; if (frame_list_size == 1) { _loop = SINGLE; if (duration_to == 0) { setBetween(_next_key_frame, _next_key_frame); } else { setBetween(node, _next_key_frame); } _frame_tween_easing = 1; } else if (frame_list_size > 1) { if (loop) { _loop = LIST_LOOP_START; } else { _loop = LIST_START; --_duration; } _duration_tween = (int) (duration_tween * this.movement_bone_data.scale); if (loop && this.movement_bone_data.delay != 0) { setBetween(node, tweenNodeTo(updateFrameData(1 - this.movement_bone_data.delay), _between)); } else { if (duration_to == 0) { setBetween(_next_key_frame, _next_key_frame); } else { setBetween(node, _next_key_frame); } } } tweenNodeTo(0, null); } @Override protected void updateHandler() { if (_current_percent >= 1) { //TODO:更多的loop类型 switch (_loop) { case SINGLE: { _current_percent = 1; _is_complete = true; } break; case LIST_START: { _loop = LIST; if (_duration_tween <= 0) { _current_percent = 1; } else { _current_percent = (_current_percent - 1) * _total_frames / _duration_tween; } if (_current_percent >= 1) { _current_percent = 1; _is_complete = true; break; } _total_frames = _duration_tween; _total_duration = 0; _to_index = 0; _from_index = 0; } break; case LIST: { _current_percent = 1; _is_complete = true; } break; case LIST_LOOP_START: { _loop = 0; _total_frames = _duration_tween > 0 ? _duration_tween : 1; if (movement_bone_data.delay != 0) { _current_frame = (1 - movement_bone_data.delay) * _total_frames; _current_percent += _current_frame / _total_frames; } _current_percent %= 1; } break; default: { _loop += _current_percent; _current_percent %= 1; _total_duration = 0; _between_duration = 0; _to_index = _from_index = 0; } break; } } else if (_loop < LIST) { _current_percent = (float) Math.sin(_current_percent * HALF_PI); } //上面的percent表示整个总的序列帧的百分比 //下面的percent意义已经不再是总体的百分比了,而是当前帧的百分比 if (_loop >= LIST) { _current_percent = updateFrameData(_current_percent); } if (_frame_tween_easing != -2) { tweenNodeTo(_current_percent, null); } } private float updateFrameData(float current_percent) { float played = current_percent * _duration; //played表示当前对于总体的进度 //_total_duration表示当前的最大帧,比如现在正处于关键帧1和5之间,那么此值就是5; //_between_duration表示当前的进度,比如现在正处于关键帧1和5之间,那么此值就是 5-1 = 4; //如果played超过5,表示要进入下一个关键帧,可能是5-x,这个时候就需要更新between的值 if (played >= _total_duration || played < _total_duration + _between_duration) { FrameData from = null, to = null; ArrayList<FrameData> frame_list = movement_bone_data.getFrameDataList(); int length = frame_list.size(); if (played < frame_list.get(0).frame_index) { from = to = frame_list.get(0); setBetween(from, to); return current_percent; } else if (played >= frame_list.get(length - 1).frame_index) { from = to = frame_list.get(length - 1); setBetween(from, to); return current_percent; } do { from = frame_list.get(_from_index); _total_duration = from.frame_index; if (++_to_index >= length) { _to_index = 0; } _from_index = _to_index; to = frame_list.get(_to_index); if (played == from.frame_index) { break; } } while (played < from.frame_index || played >= to.frame_index); _between_duration = to.frame_index - from.frame_index; _frame_tween_easing = from.tween_easing; setBetween(from, to); } current_percent = _between_duration == 0 ? 0 : (played - _total_duration) / _between_duration; if (_frame_tween_easing != -2) { int tween_easing = _tween_easing == -2 ? _frame_tween_easing : _tween_easing; if (tween_easing != 0) { current_percent = getEaseValue(current_percent, tween_easing); } } if (current_percent < 0) { current_percent %= 1; current_percent += 1; } return current_percent; } private void setBetween(FrameData from, FrameData to) { _from.copy(from); if (to instanceof FrameData) { if (((FrameData) to).display_index < 0) { _between.subtract(from, from); return; } } _between.subtract(_from, to); arriveKeyFrame(_from); } private void arriveKeyFrame(NodeData from) { if (from != null && from instanceof FrameData) { FrameData frame = (FrameData) from; if (_bone != null) { _bone.changeDisplay(frame.display_index); _bone.updateZOrder(frame.z_order); } } } private FrameData tweenNodeTo(float percent, FrameData node) { if (node == null) { node = this.node; } node.x = _from.x + percent * _between.x; node.y = _from.y + percent * _between.y; node.skew_x = _from.skew_x + percent * _between.skew_x; node.skew_y = _from.skew_y + percent * _between.skew_y; node.scale_x = _from.scale_x + percent * _between.scale_x; node.scale_y = _from.scale_y + percent * _between.scale_y; if (_between.using_color && _bone != null) { tweenColorTo(percent, node); } return node; } private void tweenColorTo(float percent, NodeData node) { node.r = _from.r + percent * _between.r; node.g = _from.g + percent * _between.g; node.b = _from.b + percent * _between.b; node.a = _from.a + percent * _between.a; _bone.setColor(node.r, node.g, node.b, node.a); } //TODO:更多的ease类型 private float getEaseValue(float percent, int ease_type) { if (ease_type > 1) { percent = (float) (0.5f * (1 - Math.cos(percent * Math.PI))); ease_type -= 1; } else if (ease_type > 0) { percent = (float) Math.sin(percent * HALF_PI); } else { percent = (float) (1 - Math.cos(percent * HALF_PI)); ease_type = -ease_type; } return percent * ease_type + (1 - ease_type); } }