I know there are some other solutions to this problem, and I haven’t looked around to compare performance… the below example uses some Zelda textures nicked off the web. The sprite sheet is loaded to the mesh and the mesh is a simple rectangle at the sprite size, then you can tell it to draw any tile off the sprite sheet by x,y being 0,0 from the bottom left. The example runs 15fps on my ipad 2 and it’s doing 676 sprites per frame, all sprites addressed on sprite sheets.
(It’s supposed to look rubbish )
--# Main
-- SpriteSheet
function didGetBackImage(image)
landTiles = SpriteSheet(image, vec2(32,32), vec2(30,16))
--30x16 tiles
asynchLoadStatus = asynchLoadStatus + 1
print("got backgrounds")
end
function didGetPeopleImage(image)
peopleTiles = SpriteSheet(image, vec2(48,64), vec2(12,8))
--12x8 tiles
asynchLoadStatus = asynchLoadStatus + 1
print("got people")
end
-- Use this function to perform your initial setup
function setup()
asynchLoadStatus = 0
--create a mesh
http.request("http://ssvcs.s3.amazonaws.com/ZeldaBackgroundSS.png", didGetBackImage)
http.request("http://ssvcs.s3.amazonaws.com/ZeldaSS.png", didGetPeopleImage)
--let's set up a world
world = {}
for x=1,24 do
for y = 1,24 do
table.insert(world, {location = vec2(x*32, y*32), tile = vec2(math.random(30)-1, math.random(16)-1)})
end
end
--let's add some people
people = {}
for i=1, 100 do
table.insert(people, {char = vec2(math.random(4)-1, math.random(2)-1), direction = math.random(4)-1, location = vec2(math.random(WIDTH), math.random(HEIGHT))})
end
frame = 0
end
-- This function gets called once every frame
function draw()
if asynchLoadStatus < 2 then
print("not yet")
return
end
print(1/DeltaTime)
-- This sets a dark background color
background(40, 40, 50)
--draw the world
for k,v in ipairs(world) do
resetMatrix()
translate(v.location.x, v.location.y)
landTiles:draw(v.tile)
end
for k,v in ipairs(people) do
resetMatrix()
translate(v.location.x, v.location.y)
peopleTiles:draw(vec2(v.char.x*3+frame, v.char.y*4+v.direction))
end
frame = (frame + 1) % 3
end
--# SpriteSheet
SpriteSheet = class()
function SpriteSheet:init(sheetImage, size, tiles)
self.m = mesh()
self.m.texture = sheetImage
self.m:addRect(-size.x/2, -size.y/2, size.x, size.y)
self.m.shader = shader(SpriteSheetShader.vertexShader, SpriteSheetShader.fragmentShader)
self.m.shader.tiles = tiles
end
function SpriteSheet:draw(tile, location, angle, resize)
self.m.shader.tile = tile
self.m:draw()
end
SpriteSheetShader = {
vertexShader = [[
//
// A basic vertex shader
//
//This is the current model * view * projection matrix
// Codea sets it automatically
uniform mat4 modelViewProjection;
uniform highp vec2 tiles;
uniform highp vec2 tile;
//This is the current mesh vertex position, color and tex coord
// Set automatically
attribute vec4 position;
attribute vec4 color;
attribute vec2 texCoord;
//This is an output variable that will be passed to the fragment shader
varying lowp vec4 vColor;
varying highp vec2 vTexCoord;
const float c_one = 1.0;
void main()
{
//Pass the mesh color to the fragment shader
vColor = color;
vTexCoord.x = texCoord.x / tiles.x + (c_one / tiles.x * tile.x);
vTexCoord.y = texCoord.y / tiles.y + (c_one / tiles.y * tile.y);
//Multiply the vertex position by our combined transform
gl_Position = modelViewProjection * position;
}
]],
fragmentShader = [[
//
// A basic fragment shader
//
//Default precision qualifier
precision highp float;
//This represents the current texture on the mesh
uniform lowp sampler2D texture;
//The interpolated vertex color for this fragment
varying lowp vec4 vColor;
//The interpolated texture coordinate for this fragment
varying highp vec2 vTexCoord;
void main()
{
lowp vec4 col = texture2D( texture, vTexCoord ) * vColor;
//Set the output color to the texture color
gl_FragColor = col;
}
]]
}