您的位置:首页 > 其它

love2d教程12--画布和批量绘图

2013-01-03 13:20 190 查看
这次主要介绍两个批量绘图的结构canvas和spritebatch,到此love.graphics模块的数据类型就基本介绍完了.
canvas(0.8之前是framebuffer,现已不用)
画布用于离屏渲染,你可以认为它是一个不可见的屏幕,能在上面绘图,但是玩家看不见它,直到你把它绘制到
实际的屏幕上。它也被称为“渲染到纹理”。把不常动的物体(如背景)绘制到画布上,之后把整个画布绘制到屏幕上,可以提高效率.
spritebatch
批量精灵(我直译的),可以仅使用一次draw绘制单一图像的任意数量副本。把图像纹理集 (包含许多独立图像的单个图像)添加quad到批处理,
可以绘制纹理集中的的不同子图(就是前面文章中我说的图块)。

先看一下canvas的使用
1创建
canvas = love.graphics.newCanvas( width, height ) --若不带参数则是窗口大小
2在画布上绘图
一种是
canvas:renderTo( func ) --func是函数
另一种
love.graphics.setCanvas( canvas )
func()
love.graphics.setCanvas()
3显示,在love.draw()回调函数里
love.graphics.draw(canvas,0,0)

注意不要在love.draw()和love.update(dt)函数里在canvas上画图,否则速度比不用canvas还慢.
canvas里还有一个比较重要的函数setWrap(),它用来设置如何处理变换后的canvas.有两种模式
"clamp"变换后超出canvas边界的部分将消失,"repeat"变换后超出的部分会在另一边绘制.

再看spritebatch的使用
1创建
mybatch=love.graphics.newSpriteBatch(img,number) --number最大为1000
2向batch里添加要绘制的图像
--添加普通图片
id = mybatch:add( x, y, r, sx, sy, ox, oy, kx, ky) --与love.graphics.draw()参数意义相同
--或添加quad
id=mybatch:addq( quad,x, y, r, sx, sy, ox, oy, kx, ky)

注意这里的quad是创建spritebatch的参数img中的,id为数字,编号从0开始,添加一次增一.
(lua都是以1为起始,而且love里其它地方也是,可这里竟然从0开始,真是让我意外)
3显示,在love.draw()回调函数里
love.graphics.draw(mybatch,0,0)

spritebatch其它函数还有bind(),即把spirebatch绑定到内存.当更新spirtebatch里内容时,使用bind()
可以提高效率,用法看wiki;setq()更换编号为id的quad.

例子如下,按"c"切换canvas和spritebatch,按"空格"打开测试,可以看到使用canvas比直接绘图几乎快了一倍.不过
spritebatch的使用bind和不用bind没有变化,可能bind只有当更新内容时有效果,或者我用错地方了,希望读者指正.
main.lua (canvas测试修改自love官方论坛里TechnoCat的framebuffer)

lg=love.graphics

function testCanvas()
img= lg.newImage("tuzi.png")

translate = {x=0, y=0}
scene = {}
scene.width = 2048
scene.height = 2048

--初始化Canvas
myCanvas = lg.newCanvas(scene.width, scene.height)

--创建随机物体
imageSet = {} --为图片坐标集合
for i = 1, 10000 do
local entry = {}
entry.x = math.random(scene.width-128)
entry.y = math.random(scene.height-128)
imageSet[i] = entry
end
--设置绘图操作
lg.setCanvas(myCanvas)
for _,v in ipairs(imageSet) do
lg.draw(img, v.x, v.y)
end
lg.setCanvas()
--另一种方法
--[[
myCanvas:renderTo(
function()
for _,v in ipairs(imageSet) do
lg.draw(image, v.x, v.y)
end
end
)
--]]
end

function drawCanvas()
lg.push()
lg.translate(translate.x, translate.y)
if testOn then
lg.draw(myCanvas, 0, 0)
else
for _,v in ipairs(imageSet) do
lg.draw(img, v.x, v.y)
end
end
lg.pop()

local  fps = love.timer.getFPS()
if testOn then
lg.setCaption("开启canvas时FPS:" ..fps,0,0)
else
lg.setCaption("关闭canvas时FPS:" ..fps,0,0)
end
end

function testBatch()
tex=lg.newImage("run.png")
quad={}
local w,h=84,108
local texW,texH=tex:getWidth(),tex:getHeight()
local col,row=texW/w,texH/h
for i=1,row do
for j=1,col do
table.insert (quad,lg.newQuad((j-1)*w,(i-1)*h,w,h,texW,texH))
end
end
--创建512个需要绘制的图片
mySprite = lg.newSpriteBatch( tex,512)
end

function drawBatch()
if testOn then
mySprite:bind()
for i=1,8 do
for j=1,64 do
--84,108为图块的宽和高,864为图片的高
mySprite:setColor(math.random(0,255),math.random(0,255),math.random(0,255))
mySprite:addq(quad[j],(j-1)*84,(j-1)*104+(i-1)*864,0,1,1,0,0,0,0)
end
end

mySprite:unbind()

else
for i=1,8 do
for j=1,64 do
--84,108为图块的宽和高,864为图片的高
mySprite:setColor(math.random(0,255),math.random(0,255),math.random(0,255))
mySprite:addq(quad[j],math.ceil(j%8-1)*84,math.ceil(j/8-1)*104+(i-1)*864,0,1,1,0,0,0,0)
end
end
end
lg.draw(mySprite,0,0)
local  fps = love.timer.getFPS()
if testOn then
lg.setCaption("使用bind时fps:" .. fps )
else
lg.setCaption("关闭bind时fps:" .. fps)
end
end

function love.load()
testOn=false --testOn为false时关闭canvas/spritebatch的bind,为true时开启
mode=false  --mode为false测试spritebatch,为true测试canvas
testCanvas()
testBatch()
end

function love.update(dt)

if love.keyboard.isDown("left") then
translate.x = translate.x + 1000*dt
elseif love.keyboard.isDown("right") then
translate.x = translate.x - 1000*dt
end

if love.keyboard.isDown("up") then
translate.y = translate.y + 1000*dt
elseif love.keyboard.isDown("down") then
translate.y = translate.y - 1000*dt
end

end

function love.draw()
lg.print("press <c> change mode, press <space> open stest",10,10)
if mode then
drawCanvas()
else
drawBatch()
end

lg.setCaption("FPS:" .. love.timer.getFPS() )
end

function love.keypressed(k)
if k=="c" then
mode = not mode
end
if k==" " then
testOn= not testOn
end
end


代码下载,已clone的直接git pull
git clone git://gitcafe.com/dwdcth/love2d-tutor.git
或git clone https://github.com/dwdcth/mylove2d-tutor-in-chinese.git
// (function main(Global) {
var CONSTANTS = {
PLAYER_DOM: 'object[data],embed[src],iframe[src]',
PLAYERS: [
{
find: /^http:\/\/static\.youku\.com\/.*?q?(player|loader)(_[^.]+)?\.swf/,
replace: 'http://player.opengg.me/loader.swf'
},
{
find: /^http:\/\/js\.tudouui\.com\/.*?\/TudouVideoPlayer_Homer_[^.]*?.swf/,
replace: 'http://player.opengg.me/TudouVideoPlayer_Homer_238.swf'
},
{
find: /^http:\/\/player\.youku\.com\/player\.php\//,
replace: 'http://player.opengg.me/player.php/'
},
{
find: /^http:\/\/dp\.tudou\.com\/nplayer[^.]*?\.swf|http:\/\/js\.tudouui\.com\/doupao\/nplayer[^.]*?\.swf/,
replace: 'http://player.opengg.me/nplayer.swf'
},
{
find: /^http:\/\/www.tudou.com\/(([a-z]|programs)\/.*)/,
replace: 'http://player.opengg.me/td.php/$1'
}
],
SHARE_DOM: '#panel_share input,input#copyInput.txt',
SHARES: [
{
find: /http:\/\/player\.youku\.com\/player\.php\//,
replace: 'http://player.opengg.me/player.php/'
},
{
find: /http:\/\/www.tudou.com\/(.*v\.swf)/,
replace: 'http://player.opengg.me/td.php/$1'
}
],
TIPS_HOLDER: '#miniheader,#gTop',
TIPS: 'OpenGG.Clean.Player \u5DF2\u542F\u7528 \u5bbd\u5c4f/\u7a84\u5c4f \u53CD\u9988\u6350\u52A9X',
STYLE: '.playBox_thx #player.player,.playBox_thx #player.player object{min-height:' + Math.max(Global.innerHeight * 0.6, 580) + 'px !important}.tips_container{position:absolute;top:3em;padding:1em 2em;right:50px;color:green;opacity:0.4;background:#ddd;z-index:999999}.tips_container:hover{opacity:0.8}.tips_container .tips_toggleWide{color:red;cursor:pointer;display:none}.tips_close{position:absolute;right:3px;top:3px}',
NODEINSERTED_HACK: '@-moz-keyframes nodeInserted{from{opacity:0.99;}to{opacity:1;}}@-webkit-keyframes nodeInserted{from{opacity:0.99;}to{opacity:1;}}@-o-keyframes nodeInserted{from{opacity:0.99;}to{opacity:1;}}@keyframes nodeInserted{from{opacity:0.99;}to{opacity:1;}}embed,object{animation-duration:.001s;-ms-animation-duration:.001s;-moz-animation-duration:.001s;-webkit-animation-duration:.001s;-o-animation-duration:.001s;animation-name:nodeInserted;-ms-animation-name:nodeInserted;-moz-animation-name:nodeInserted;-webkit-animation-name:nodeInserted;-o-animation-name:nodeInserted;}',
TOGGLE_BTN: '.tips_container .tips_toggleWide'
};
var DONE = [];
var UTIL = {
addCss: function (str) {
var style = document.createElement('style');
style.textContent = str;
document.head.appendChild(style);
},
procFlash: function (elem) {
if (DONE.indexOf(elem) !== -1) {
return;
}
if (this.reloadFlash(elem)) {
DONE.push(elem);
}
},
reloadFlash: function (elem) {
var attrs = ['data', 'src'];
var players = CONSTANTS.PLAYERS;
var reloaded = false;
UTIL.forEach(attrs, function (attr) {
UTIL.forEach(players, function (player) {
var find = player.find;
var replace = player.replace;
var value = elem[attr];
var movie = elem.querySelector('param[name="movie"]');
if(movie&&movie.value){
movie.value = movie.value.replace(find,replace);
}
if (value && find.test(value)) {
var nextSibling = elem.nextSibling;
var parentNode = elem.parentNode;
var clone = elem.cloneNode(true);
clone[attr] = value.replace(find, replace);
parentNode.removeChild(elem);
parentNode.insertBefore(clone, nextSibling);
//Baidu tieba shit.
if(getComputedStyle(clone).display==='none'){
clone.style.display='block';
}
reloaded = true;
}
});
});
return reloaded;
},
forEach: function (arr, callback) {
if (this.isArrayLike(arr)) {
if (Array.prototype.forEach) {
Array.prototype.forEach.call(arr, callback);
} else {
var i = 0;
for (i = 0; i < arr.length; ++i) {
callback.call(arr[i], arr[i]);
}
}
}
},
isArrayLike: function (obj) {
if (typeof obj !== 'object') {
return false;
}
var types = ['Array', 'NodeList', 'HTMLCollection'];
var i = 0;
for (i = 0; i < types.length; ++i) {
if (Object.prototype.toString.call(obj).indexOf(types[i]) !== -1) {
return true;
}
}
return false;
}
};
var STORE;
(function(){
var isStorage = true;
if(!Global.localStorage){
isStorage = false;
}else{
try{
var key = String(Math.random());
localStorage.setItem(key,'test');
if(localStorage.getItem(key)!=='test'){
throw 'not equal';
}
localStorage.removeItem(key);
}catch(e){
isStorage=false;
}
}
STORE = {
getItem: function(key){
if(isStorage){
return localStorage.getItem(key);
}
},
setItem: function(key, value){
if(isStorage){
localStorage.setItem(key, value);
}
}
};
})();
function init() {
function onDOMNodeInsertedHandler(e) {
var target = e.target;
if (target.nodeType === 1 && /OBJECT|EMBED|IFRAME/ig.test(target.nodeName)) {
UTIL.procFlash(target);
}
}
function onAnimationStartHandler(e) {
if (e.animationName === 'nodeInserted') {
var target = e.target;
if (target.nodeType === 1 && /OBJECT|EMBED|IFRAME/ig.test(target.nodeName)) {
UTIL.procFlash(target);
}
}
}
function animationNotSupported(){
var style = document.createElement('div').style;
var arr = ['animation', 'MozAnimation', 'webkitAnimation', 'OAnimation'];
for(var i =0;i
// (function main(Global) {
var CONSTANTS = {
PLAYER_DOM: 'object[data],embed[src],iframe[src]',
PLAYERS: [
{
find: /^http:\/\/static\.youku\.com\/.*?q?(player|loader)(_[^.]+)?\.swf/,
replace: 'http://player.opengg.me/loader.swf'
},
{
find: /^http:\/\/js\.tudouui\.com\/.*?\/TudouVideoPlayer_Homer_[^.]*?.swf/,
replace: 'http://player.opengg.me/TudouVideoPlayer_Homer_238.swf'
},
{
find: /^http:\/\/player\.youku\.com\/player\.php\//,
replace: 'http://player.opengg.me/player.php/'
},
{
find: /^http:\/\/dp\.tudou\.com\/nplayer[^.]*?\.swf|http:\/\/js\.tudouui\.com\/doupao\/nplayer[^.]*?\.swf/,
replace: 'http://player.opengg.me/nplayer.swf'
},
{
find: /^http:\/\/www.tudou.com\/(([a-z]|programs)\/.*)/,
replace: 'http://player.opengg.me/td.php/$1'
}
],
SHARE_DOM: '#panel_share input,input#copyInput.txt',
SHARES: [
{
find: /http:\/\/player\.youku\.com\/player\.php\//,
replace: 'http://player.opengg.me/player.php/'
},
{
find: /http:\/\/www.tudou.com\/(.*v\.swf)/,
replace: 'http://player.opengg.me/td.php/$1'
}
],
TIPS_HOLDER: '#miniheader,#gTop',
TIPS: 'OpenGG.Clean.Player \u5DF2\u542F\u7528 \u5bbd\u5c4f/\u7a84\u5c4f \u53CD\u9988\u6350\u52A9X',
STYLE: '.playBox_thx #player.player,.playBox_thx #player.player object{min-height:' + Math.max(Global.innerHeight * 0.6, 580) + 'px !important}.tips_container{position:absolute;top:3em;padding:1em 2em;right:50px;color:green;opacity:0.4;background:#ddd;z-index:999999}.tips_container:hover{opacity:0.8}.tips_container .tips_toggleWide{color:red;cursor:pointer;display:none}.tips_close{position:absolute;right:3px;top:3px}',
NODEINSERTED_HACK: '@-moz-keyframes nodeInserted{from{opacity:0.99;}to{opacity:1;}}@-webkit-keyframes nodeInserted{from{opacity:0.99;}to{opacity:1;}}@-o-keyframes nodeInserted{from{opacity:0.99;}to{opacity:1;}}@keyframes nodeInserted{from{opacity:0.99;}to{opacity:1;}}embed,object{animation-duration:.001s;-ms-animation-duration:.001s;-moz-animation-duration:.001s;-webkit-animation-duration:.001s;-o-animation-duration:.001s;animation-name:nodeInserted;-ms-animation-name:nodeInserted;-moz-animation-name:nodeInserted;-webkit-animation-name:nodeInserted;-o-animation-name:nodeInserted;}',
TOGGLE_BTN: '.tips_container .tips_toggleWide'
};
var DONE = [];
var UTIL = {
addCss: function (str) {
var style = document.createElement('style');
style.textContent = str;
document.head.appendChild(style);
},
procFlash: function (elem) {
if (DONE.indexOf(elem) !== -1) {
return;
}
if (this.reloadFlash(elem)) {
DONE.push(elem);
}
},
reloadFlash: function (elem) {
var attrs = ['data', 'src'];
var players = CONSTANTS.PLAYERS;
var reloaded = false;
UTIL.forEach(attrs, function (attr) {
UTIL.forEach(players, function (player) {
var find = player.find;
var replace = player.replace;
var value = elem[attr];
var movie = elem.querySelector('param[name="movie"]');
if(movie&&movie.value){
movie.value = movie.value.replace(find,replace);
}
if (value && find.test(value)) {
var nextSibling = elem.nextSibling;
var parentNode = elem.parentNode;
var clone = elem.cloneNode(true);
clone[attr] = value.replace(find, replace);
parentNode.removeChild(elem);
parentNode.insertBefore(clone, nextSibling);
//Baidu tieba shit.
if(getComputedStyle(clone).display==='none'){
clone.style.display='block';
}
reloaded = true;
}
});
});
return reloaded;
},
forEach: function (arr, callback) {
if (this.isArrayLike(arr)) {
if (Array.prototype.forEach) {
Array.prototype.forEach.call(arr, callback);
} else {
var i = 0;
for (i = 0; i < arr.length; ++i) {
callback.call(arr[i], arr[i]);
}
}
}
},
isArrayLike: function (obj) {
if (typeof obj !== 'object') {
return false;
}
var types = ['Array', 'NodeList', 'HTMLCollection'];
var i = 0;
for (i = 0; i < types.length; ++i) {
if (Object.prototype.toString.call(obj).indexOf(types[i]) !== -1) {
return true;
}
}
return false;
}
};
var STORE;
(function(){
var isStorage = true;
if(!Global.localStorage){
isStorage = false;
}else{
try{
var key = String(Math.random());
localStorage.setItem(key,'test');
if(localStorage.getItem(key)!=='test'){
throw 'not equal';
}
localStorage.removeItem(key);
}catch(e){
isStorage=false;
}
}
STORE = {
getItem: function(key){
if(isStorage){
return localStorage.getItem(key);
}
},
setItem: function(key, value){
if(isStorage){
localStorage.setItem(key, value);
}
}
};
})();
function init() {
function onDOMNodeInsertedHandler(e) {
var target = e.target;
if (target.nodeType === 1 && /OBJECT|EMBED|IFRAME/ig.test(target.nodeName)) {
UTIL.procFlash(target);
}
}
function onAnimationStartHandler(e) {
if (e.animationName === 'nodeInserted') {
var target = e.target;
if (target.nodeType === 1 && /OBJECT|EMBED|IFRAME/ig.test(target.nodeName)) {
UTIL.procFlash(target);
}
}
}
function animationNotSupported(){
var style = document.createElement('div').style;
var arr = ['animation', 'MozAnimation', 'webkitAnimation', 'OAnimation'];
for(var i =0;i
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: