Javascript Fabric.js-如何从精灵工作表设置动画
JavaScript语法:Javascript Fabric.js-如何从精灵工作表设置动画,javascript,animation,html5-canvas,fabricjs,sprite-sheet,Javascript,Animation,Html5 Canvas,Fabricjs,Sprite Sheet,JavaScript语法: context.drawImage(img,srcX,srcY,srcWidth,srcHeight,x,y,width,height); 在Javascript中,如果我想为下面的spritesheet设置动画,我只需更新srcX和srcY每个动画帧,以捕获图像的片段 这将导致每个帧被剪裁并分别显示在画布上,当以固定帧速率更新时,将生成流体精灵动画,如下所示: 如何使用“Fabric.js”库实现这一点 注意:实现这一点的一种方法是设置canvasSize=f
context.drawImage(img,srcX,srcY,srcWidth,srcHeight,x,y,width,height);
在Javascript中,如果我想为下面的spritesheet设置动画,我只需更新srcX
和srcY
每个动画帧,以捕获图像的片段
这将导致每个帧被剪裁并分别显示在画布上
,当以固定帧速率更新时,将生成流体精灵动画,如下所示:
如何使用“Fabric.js”库实现这一点
注意:实现这一点的一种方法是设置
canvasSize=frameSize
以便在任何给定时间只能看到一个帧。然后通过移动图像,可以在画布内放置不同的帧以模拟动画。但是,对于大画布或可变的帧大小,这将不起作用。看看这个,它也会做同样的事情
行走的人形。
Fabric.js,图像动画。
var URL='1〕http://i.stack.imgur.com/M06El.jpg';
var canvas=newfabric.canvas('canvas');
变量位置={
上步:2,
左步骤:4
};
canWalk(URL、位置);
函数canWalk(URL、位置){
var myImage=新图像();
myImage.src=URL;
myImage.onload=函数(){
var topStep=myImage.naturalHeight/positions.topSteps;
var leftStep=myImage.naturalWidth/positions.leftSteps;
var docCanvas=document.getElementById('canvas');
docCanvas.height=上台阶;
docCanvas.width=leftStep;
fabricImageFromURL(0,0);
var y=0;
var x=0;
setInterval(函数(){
if(x==positions.leftSteps)
{
x=0;
y++;
if(y==位置.上台阶)
{
y=0;
}
}
fabricImageFromURL(-y*上步,-x*左步);
x++;
},100);
};
}
函数fabricImageFromURL(顶部,左侧)
{
控制台日志(顶部,左侧);
fabric.Image.fromURL(URL,函数(oImg){
oImg.set('左',左)。set('顶',顶);
oImg.hasControls=false;
oImg.hasBorders=false;
oImg.selective=false;
canvas.add(oImg);
canvas.renderAll();
},{“左”:0,“上”:0,“scaleX”:1,“scaleY”:1});
}
默认情况下,Fabric不会这样做。您需要在fabric.Image对象和扩展fabric.Image\u呈现方法中呈现“源”属性。原版看起来是这样的:
/**
*@私人
*@param{CanvasRenderingContext2D}要在其上渲染的ctx上下文
*@param{Boolean}nottransform
*/
_呈现:函数(ctx,不转换){
变量x,y,imageMargins=这个。_findMargins(),elementToDraw;
x=(不转换?此.左:-this.宽/2);
y=(不转换?此.top:-this.height/2);
if(this.meetOrSlice==='slice'){
ctx.beginPath();
ctx.rect(x,y,this.width,this.height);
ctx.clip();
}
if(this.isMoving==false&&this.resizeFilters.length&&this.\u需要大小(){
this.\u lastScaleX=this.scaleX;
this.\u lastScaleY=this.scaleY;
elementToDraw=this.applyFilters(null,this.resizeFilters,this.\u filteredEl | this.\u originalElement,true);
}
否则{
elementToDraw=此。\元素;
}
elementToDraw&&ctx.drawImage(elementToDraw,
x+imageMargins.marginX,
y+imageMargins.marginY,
图像边距。宽度,
身高
);
这是一个冲程(ctx);
这是._renderStroke(ctx);
},
您可以在循环中结合使用设置clipTo函数和调用setLeft/setTop。在fabric.Image构造函数的选项中,传递属性clipTo并告诉fabric剪切图像的特定部分。然后,当setTop/setLeft位于循环内时,触发重新绘制,从而调用clipTo,同时重新定位剪切图像,使其始终保持在同一位置
我遇到了同样的问题,并将逻辑提取为两个函数。选项的快速汇总:精灵宽度-精灵的一个动画帧的宽度
精灵高度-精灵的一个动画帧的高度
总宽度-整个精灵图像的宽度
总高度-整个精灵图像的高度
animationFrameDuration-一个精灵帧应显示多长时间
startRandom-如果您不想立即启动动画,而是想在1秒内随机启动动画
左-就像正常的fabric左选项一样。Image
上衣-就像普通面料的上衣一样。图片
同步版本(传递HTMLImageElement): 异步版本(传递图像URL): 请注意,上述函数不会重新渲染画布,您必须自己执行。
您可以使用上述类似的代码并排设置精灵两次动画(一次同步版本,一次异步版本):
您一定要使用fabricsj吗?我的意思是,这可以通过单独使用css3动画来实现@MohitBhardwaj:我不使用CSS动画有几个原因。下面的链接提供了一些解释。。。我正在创建的游戏相对较大,需要良好的性能和灵活性。感谢提供的信息链接:)很好的黑客操作方式;)不幸的金枪鱼
/**
* @param imgObj HTMLImageElement
* @param options {
* spriteWidth: number
* spriteHeight: number
* totalWidth: number
* totalHeight: number
* animationFrameDuration: number
* startRandom: boolean (optional)
* left: number (optional)
* top: number (optional)
* }
* @returns fabric.Image
*/
function animateImg(imgObj, options) {
const left = options.left || 0;
const top = options.top || 0;
let x = 0;
let y = 0;
const image = new fabric.Image(imgObj, {
width: options.totalWidth,
height: options.totalHeight,
left: left,
top: top,
clipTo: ctx => {
ctx.rect(-x - options.totalWidth / 2, -y - options.totalHeight / 2, options.spriteWidth, options.spriteHeight);
}
});
setTimeout(() => {
setInterval(() => {
x = (x - options.spriteWidth) % options.totalWidth;
if (x === 0) {
y = (y - options.spriteHeight) % options.totalHeight;
}
image.setLeft(x + left);
image.setTop(y + top);
}, options.animationFrameDuration)
}, options.startRandom ? Math.random() * 1000 : 0);
return image;
}
/**
* @param imgURL string
* @param options {
* spriteWidth: number
* spriteHeight: number
* totalWidth: number
* totalHeight: number
* animationFrameDuration: number
* startRandom: boolean (optional)
* left: number (optional)
* top: number (optional)
* }
* @param callback (image : fabric.Image) => void
*/
function animateImgFromURL(imgURL, options, callback) {
const left = options.left || 0;
const top = options.top || 0;
let x = 0;
let y = 0;
fabric.Image.fromURL(
imgURL,
image => {
setTimeout(() => {
setInterval(() => {
x = (x - options.spriteWidth) % options.totalWidth;
if (x === 0) {
y = (y - options.spriteHeight) % options.totalHeight;
}
image.setLeft(x);
image.setTop(y);
}, options.animationFrameDuration)
}, options.startRandom ? Math.random() * 1000 : 0);
callback(image);
}, {
width: options.totalWidth,
height: options.totalHeight,
left: 0,
top: 0,
left: left,
top: top,
clipTo: ctx => {
ctx.rect(-x - options.totalWidth / 2, -y - options.totalHeight / 2, options.spriteWidth, options.spriteHeight);
}
});
// Assuming:
// 1. canvas was created
// 2. Sprite is in html with id 'walking'
// 3. Sprite is within folder 'images/walking.jpg'
const img1 = animateImg(document.getElementById('walking'), {
spriteWidth: 125,
spriteHeight: 125,
totalWidth: 500,
totalHeight: 250,
startRandom: true,
animationFrameDuration: 150,
left: 125,
top: 0
});
canvas.add(img1);
animateImgFromURL('images/walking.jpg', {
spriteWidth: 125,
spriteHeight: 125,
totalWidth: 500,
totalHeight: 250,
startRandom: true,
animationFrameDuration: 150
}, image => canvas.add(image));
// hacky way of invoking renderAll in a loop:
setInterval(() => canvas.renderAll(), 10);