当前位置: 代码迷 >> JavaScript >> 一个js动画框架的demo,没有封装,仅仅做个演示,跟大家讨论一上
  详细解决方案

一个js动画框架的demo,没有封装,仅仅做个演示,跟大家讨论一上

热度:84   发布时间:2012-11-23 22:54:33.0
一个js动画框架的demo,没有封装,仅仅做个演示,跟大家讨论一下

很久没写东西了,比较懒,真的不太喜欢写东西,也不太擅长写,不过群友们对此颇有微言,说我总说理论,没有实例,于是写点实例吧,堵一堵某些人的嘴,嘿嘿。
  对与写JS动画,很多初学者喜欢让每个运动的物体拥有一个计数器,或者出现让运动的速度与时钟的频率一致,

1.第一种方式很显然不方便对动画的整体控制,并且资源消耗大。
2.第二种方式,是把动画的帧率和速率概念混淆了,会引起不同的浏览器出现不同速率的问题
  我所设计的动画框架是由一个动画引擎来管理所有的动画,每个动画对象在生成的时候,把自己注册到动画引擎中,动画引擎调用每个动画对象的帧方法来实现动画,多说无益,直接上代码吧,懒毛病又翻了......;

希望大家能给一些框架上的意见,方便完善这个框架。嘿嘿

?

<html>
<head>
<meta http-equiv="content-type" content="text/html;charset=UTF-8"> 
<style>
div{width:20px;height:20px;border:1px solid #000;position:absolute}
</style>
<script>
var $ = function(o){ return document.getElementById(o)};
var SpriteEngine = {//动画引擎,由动画引擎调度所有的动画对象
					sprites : {},//动画对象字典
					frame : 30,//每秒30帧
					timer : null ,//动画计时器
					register: function(spriteObj){//注册动画对象
						if(spriteObj.id && ! this.sprites[spriteObj.id]){
							this.sprites[spriteObj.id] = spriteObj;
						}
					},
					unRegister:function(spriteObj){//删除动画对象
						if(spriteObj.id){
							delete this.sprites[spriteObj.id];
						}
					},
					startFrame : function(){//开始动画
						this.timer = setInterval(this.enterFrameFunction, 1000 / this.frame);
					},
					stopFrame : function(){//暂停动画
						if(this.timer)
							clearInterval(this.timer);
					},
					enterFrameFunction : function(){//内部启动方法
						var sprites = SpriteEngine.sprites;
						for(var key in sprites){
							var sprite = sprites[key];
							//$("debug").innerHTML += sprite.id;
							if(sprite.id && sprite.enterFrame){//检查是否是Sprite的接口实例
								sprite.enterFrame(1000 / SpriteEngine.frame);
							}
						}
					}
				};
/**
 * 动画对象
 * 设定内部接口为
 *		id 动画对象的标识
 *		enterFrame 由动画引擎调用
 * 外部接口为
 *		addEnterFrameFunction 设定动画对象的运动函数
 */
var Sprite = function(id,speed,direction){
	this.id = id;//接口,必须有ID,内部接口
	this.x = 0;
	this.y = 0;
	this.dom  = $(id);
	this.speed = speed;//运动的速度,每毫秒多少像素
	this.direction = direction;//运动的角度,单位弧度
	this.enterFrameFun = [];//动画方程列表
	SpriteEngine.register(this);
	if(this.dom){//初始化位置
		this.dom.style.top = 0;
		this.dom.style.left = 0;
	}
};
Sprite.prototype.setXY = function(x, y){//设置内部dom位置,这个仅仅是演示用的,不算Sprite的接口
	this.x = x;
	this.y = y;
	if(this.dom){
		this.dom.style.top = y + 'px';
		this.dom.style.left = x + 'px';
	}
}
Sprite.prototype.addEnterFrameFunction = function(fun){//添加动画的方法接口,外部接口
	this.enterFrameFun.push(fun);
};
Sprite.prototype.enterFrame = function(stepTime){//引擎调用的接口,内部接口
	for(var i = this.enterFrameFun.length; i--; ){
		this.enterFrameFun[i].call(this,stepTime);
	}
};
var movefun1 = function(stepTime){//demo 直线运动
	var move = this.speed * stepTime
	var _x = move * Math.cos(this.direction);
	var _y = move * Math.sin(this.direction);
	this.setXY(this.x + _x, this.y + _y);
}
var movefun2 = function(stepTime){//demo 给定一个角速度
	this.direction += 0.1;
}
var movefun3 = function(stepTime){//demo 往复运动
	if (this.x > 500){
		this.direction =  Math.PI;
	}
	if(this.x < 50){
		this.direction = 0;
	}
}
function init(){
	var a = new Sprite("demo1", 0.5, 0);
	var b = new Sprite("demo2", 0.3, 30);
	a.setXY(20,100);//直线运动,叠加往复运动
	a.addEnterFrameFunction(movefun1);
	a.addEnterFrameFunction(movefun3);
	b.setXY(100,200);//直线运动,叠加角速度
	b.addEnterFrameFunction(movefun1);
	b.addEnterFrameFunction(movefun2);
}
function pauseOrStart(o){
	if(o.value == '暂停'){
		o.value = '开始'
		SpriteEngine.stopFrame();
	}else{
		o.value = '暂停';
		SpriteEngine.startFrame();
	}
}
</script>
</head>
<body onload="init()">
	<div id="demo1"></div>
	<div id="demo2"></div>
	<input type="button" value="开始" onclick="pauseOrStart(this)" />
</body>
</html>

?

?

1 楼 nomandia 2011-02-15  
如果SpriteEngine的frame改变的话,角度运动轨迹会发生变化。
比如:
var b = new Sprite("demo2", 0.3, 30);
当frame增大时其半径减少,反之亦然。
2 楼 tangjikey 2011-02-16  
敢问楼主哪个群?
3 楼 rainsilence 2011-02-16  
你这个设计思想,已经给无数人用过了。虽然想法很好,如果你的时间间隔设的很短,setInterval会在句柄未执行完的情况下直接执行下一次。如果你的sprite很多,而间隔很短,就会容易出现跳帧的情况。虽然gpu加速可以在一定程度上缓解这个问题,但是问题仍然是存在的。这个时候你怎么解决这个性能问题?
4 楼 soft_xiaohui 2011-02-16  
谢谢lz分享,测试一下。
5 楼 xiaotot 2011-02-16  
rainsilence 写道
你这个设计思想,已经给无数人用过了。虽然想法很好,如果你的时间间隔设的很短,setInterval会在句柄未执行完的情况下直接执行下一次。如果你的sprite很多,而间隔很短,就会容易出现跳帧的情况。虽然gpu加速可以在一定程度上缓解这个问题,但是问题仍然是存在的。这个时候你怎么解决这个性能问题?


感谢您提出的这个问题,这个问题比较严重,让我考虑一下
当前的框架是讨论的最初雏形,还没有设计场景视口等等元素,但是您提的这个是很严重的效率问题,我会考虑的,谢谢您
6 楼 xiaotot 2011-02-16  
nomandia 写道
如果SpriteEngine的frame改变的话,角度运动轨迹会发生变化。
比如:
var b = new Sprite("demo2", 0.3, 30);
当frame增大时其半径减少,反之亦然。


这个函数仅仅是演示函数,角速度是每一帧多少度,肯定跟帧率相关,呵呵,运动函数您可以自己随便修改增加的
7 楼 fins 2011-02-17  
我个人还是倾向于把速度分解成 speedX, speedY 分别计算.
8 楼 weilingfeng98 2011-02-18  
js写的动画真不错
9 楼 satanultra 2011-02-22  
rainsilence 写道
你这个设计思想,已经给无数人用过了。虽然想法很好,如果你的时间间隔设的很短,setInterval会在句柄未执行完的情况下直接执行下一次。如果你的sprite很多,而间隔很短,就会容易出现跳帧的情况。虽然gpu加速可以在一定程度上缓解这个问题,但是问题仍然是存在的。这个时候你怎么解决这个性能问题?

可以考虑用setTimeout
10 楼 rainsilence 2011-03-02  
satanultra 写道
rainsilence 写道
你这个设计思想,已经给无数人用过了。虽然想法很好,如果你的时间间隔设的很短,setInterval会在句柄未执行完的情况下直接执行下一次。如果你的sprite很多,而间隔很短,就会容易出现跳帧的情况。虽然gpu加速可以在一定程度上缓解这个问题,但是问题仍然是存在的。这个时候你怎么解决这个性能问题?

可以考虑用setTimeout

setTimeout是可以解决这个问题,但是会带来新问题。随着精灵数的增加,会导致每一帧的执行速度不一样。而且帧的间隔会变得不可预测。
11 楼 shichuanliujie 2011-03-14  
跑不动啊,怎么我发现很多东西都要用firefox,好像大家对IE无爱啊
  相关解决方案