avg-core-ts
Version:
Develop Adventure Game (or ADV, Visual Novel, Galgame, etc.) on your own!
332 lines (290 loc) • 10.2 kB
JavaScript
/**
* @file Sprite manager
* @author MicroMatrix <yangpan.1985@bytedance.com>
* @copyright 2012-2020 bytedance
* @link git@code.byted.org:yangpan.1985/avg.git
*/
/* eslint-disable */
const PIXI = require('pixi.js');
import Sprite from './Sprite';
import Animation from './Animation';
import TextSprite from './TextSprite';
import TextWindow from './TextWindow';
import { attachToSprite } from './EventManager';
import { TransitionPlugin } from './Transition/TransitionPlugin';
import { TransitionFilter } from './Transition/TransitionFilter';
import core from 'core/core';
const logger = core.getLogger('SpriteManager');
const Sprites = new Map();
let Renderer = null;
let Stage = null;
const textWindowOptions = {
currentIndex: -2
};
export function init() {
Renderer = new PIXI.WebGLRenderer(1280, 720);
Stage = new PIXI.Container();
attachToSprite(Stage);
// Stage.buttonMode = true;
insert(-1, Stage);
// Transition Support
Stage.filters = [new TransitionFilter()];
TransitionPlugin(Stage);
return Renderer.view;
}
export function getStage() {
return Stage;
}
export function getRenderer() {
return Renderer;
}
/**
* create a normal sprite
* argument `rect` there is different from this in BKEngine,
* for it default to `null`, instead of [0,0,0,0] in BKEngine.
* @method create
* @param {Number} index [description]
* @param {String} file [description]
* @param {Rectangle} rect [description]
*/
export function create(index, file, rect) {
// 判断index是否已存在
const sp = new Sprite();
sp.setFile(file).setIndex(index).setRect(rect).execSync();
attachToSprite(sp);
insert(index, sp);
}
export function createText(index, text, options) {
options = {
color: 0xffffff,
size: 24,
font: 'sans-serif',
width: -1,
height: -1,
xinterval: 0,
yinterval: 3,
extrachar: '...',
bold: false,
italic: false,
strike: false,
under: false,
shadow: false,
shadowcolor: 0x0,
stroke: false,
strokecolor: 0x0,
...options
};
const textsprite = new TextSprite();
textsprite.setIndex(index).setText(text).setColor(options.color).setSize(options.size).setFont(options.font)
.setTextWidth(options.width).setTextHeight(options.height).setXInterval(options.xinterval).setYInterval(options.yinterval)
.setExtraChar(options.extrachar).setBold(options.bold).setItalic(options.italic)/* .setStrike(strike).setUnder(under)*/
.setShadow(options.shadow).setShadowColor(options.shadowcolor).setStroke(options.stroke).setStrokeColor(options.strokecolor)
.exec();
attachToSprite(textsprite);
insert(index, textsprite);
}
/**
* create a frame animation.
* @method createAnimation
* @param {String} direction horizontal or vertical, leave it null if using multifiles.
* @param {Number} index [description]
* @param {String} file file for horizontal or vertical mode
* @param {Array} files files for multifiles mode
* @param {Number} frame number of frames in a row (horizontal mode) or column (vertical mode)
* @param {Number} row number of rows (for horizontal mode)
* @param {Number} column number of rows (for vertical mode)
* @param {Number} interval time between each frame (ms)
* @param {String} loopType `forward` or 'bouncing', take effects when loop is true.
* @param {Boolean} loop whether loop or not
* @param {Number} delay interval between each loop
*/
export function createAnimation({ direction, index, file, files, frame, row = 1, column = 1, interval = 33, loopType = 'forward', loop = true, delay = 0 }) {
const ani = new Animation();
if (files) {
ani.setType('multifiles').setIndex(index).setFile(files)
.setInterval(interval).setLoop(loop).setDelay(delay)
.exec();
} else if (direction === 'horizontal') {
ani.setType('horizontal').setIndex(index).setFile(file)
.setFrame(frame).setRow(row).setInterval(interval)
.setLoopType(loop).setDelay(delay)
.exec();
} else { // vertical
ani.setType('vertical').setIndex(index).setFile(file)
.setFrame(frame).setColumn(column).setInterval(interval)
.setLoopType(loop).setDelay(delay)
.exec();
}
attachToSprite(ani);
insert(index, ani);
}
/**
* set a sprite as another sprite's child
* @method addto
* @param {Number} sourceIndex the sprite will be add to parent
* @param {Number} targetIndex the parent sprite
* @param {Number} zorder greater will be above, default to 0
* @param {Point} pos coordinate relative to parent sprite, default to [0,0]
* @param {Number} alpha range 0~1, default to 1.0
*/
export function addto(sourceIndex, targetIndex, zorder = 0, pos = [0, 0], alpha = 1) {
const source = fromIndex(sourceIndex);
const target = fromIndex(targetIndex);
if (!source || !target) { return logger.warn('source or target does not exist, ignored.'); }
source.x = pos[0];
source.y = pos[1];
source.alpha = alpha;
target.addChild(source);
setZorder(sourceIndex, zorder);
}
/**
* get a sprite from index
* @method fromIndex
* @param {Number} index
* @return {Sprite}
*/
export function fromIndex(index) {
return Sprites.get(index);
}
/**
* get current active TextWindow.
* @method currentTextWindow
* @return {Sprite} TextWindow Sprite
*/
export function currentTextWindow() {
return Sprite[textWindowOptions.currentIndex];
}
/**
* insert a sprite
* @method insert
* @param {String} index
* @param {Sprite} sprite
*/
export function insert(index, sprite) {
sprite.index = index;
Sprites.set(index, sprite);
}
/**
* remove a sprite from its parent (and screen).
* @method remove
* @param {Number} index
*/
export function remove(index, isDelete = true) {
const sp = fromIndex(index);
if (!sp || !sp.parent) { return logger.warn(`Sprite<${index}> does not exist, or it hasn't been added to screen, ignored.`); }
sp.parent.removeChild(sp);
if (isDelete) { Sprites.remove(index); }
}
/**
* remove all children from a sprite
* @method removeAll
* @param {Number} index
* @param {Boolean} isDelete if true, the texture of the sprite will be deleted from memory, default to true
* @param {Boolean} isRecursive whether remove all children of each child, default to true.
*/
export function removeAll(index, isDelete = true, isRecursive = true) {
const parent = fromIndex(index);
if (!parent) { return logger.warn(`Sprite<${index}> does not exist, ignored.`); }
removeRecursive(parent, isDelete);
}
function removeRecursive(children, isDelete, isRecursive) {
for (const child of children) {
remove(child, isDelete);
if (isRecursive && child.children.length) { removeRecursive(child.children); }
}
}
/**
* prepare a transition of a sprite, any change of the sprite will not take effect until `.applyTransition()` is called.
* @method prepareTransition
* @param {[type]} index [description]
* @return {[type]} [description]
*/
export function prepareTransition(index) {
const sprite = fromIndex(index);
if (!sprite) { return logger.warn(`Sprite<${index}> does not exist, ignored.`); }
sprite.prepareTransition(Renderer);
}
/**
* apply a transition of a sprite.
* @method applyTransition
* @param {Number} index
* @param {AbstractFilter} filter filter instance.
* @return {Promise}
*/
export function applyTransition(index, filter) {
const sprite = fromIndex(index);
if (!sprite) { return logger.warn(`Sprite<${index}> does not exist, ignored.`); }
return sprite.startTransition(Renderer, filter);
}
/**
* set z-order of sprites, greater will be above.
* @method setZorder
* @param {Number} index
* @param {Number} value
*/
export function setZorder(index, zorder) {
const sprite = Sprites.get(index);
if (!sprite) { logger.warn(`Sprite<${index}> does not exist, ignored.`); } else {
if (sprite.zorder != 0 && sprite.zorder === zorder) { return; }
sprite.zorder = zorder;
if (sprite.parent) {
sprite.parent.children.sort(function (a, b) {
a.zorder = a.zorder || 0;
b.zorder = b.zorder || 0;
return a.zorder - b.zorder;
});
}
}
}
export function setAnchor(index, anchor) {
const sprite = fromIndex(index);
if (typeof anchor === 'string') {
switch (anchor) {
case 'center': anchor = [0.5, 0.5]; break;
case 'topleft': anchor = [0, 0]; break;
case 'topright': anchor = [1, 0]; break;
case 'topcenter': anchor = [0.5, 0]; break;
case 'leftcenter': anchor = [0, 0.5]; break;
case 'rightcenter': anchor = [1, 0.5]; break;
case 'bottomcenter': anchor = [0.5, 1]; break;
case 'bottomleft': anchor = [0, 1]; break;
case 'bottomright': anchor = [1, 1]; break;
default: anchor = [0, 0]; break;
}
}
sprite.anchor = new PIXI.Point(set[0], set[1]);
}
/**
* playing a animation sprite.
* @method animationCell
* @param {Number} index
*/
export function animationStart(index) {
const sprite = fromIndex(index);
if (!sprite) { logger.warn(`Sprite<${index}> does not exist, ignored.`); } else {
sp.start();
}
}
/**
* stop playing a animation sprite.
* @method animationCell
* @param {Number} index
*/
export function animationStop(index) {
const sprite = fromIndex(index);
if (!sprite) { logger.warn(`Sprite<${index}> does not exist, ignored.`); } else {
sp.stop();
}
}
/**
* force a animation sprite in specific frame. This will stop the animation, if it is playing.
* @method animationCell
* @param {Number} index
* @param {Number} frame the number of frame cell, start from 0.
*/
export function animationCell(index, frame) {
const sprite = fromIndex(index);
if (!sprite) { logger.warn(`Sprite<${index}> does not exist, ignored.`); } else {
sp.cell(frame);
}
}