I just finished coding my first iPhone game so now I'm working on artwork. I currently have a simple TileSet and all of the levels are different TileMaps. I would like to be able to allow the user to change the theme and just have the TileSet change instead of storing copies of all of the different levels for each theme. Is this possible?
Changing TileSet on the fly?
(12 posts) (3 voices)-
Posted 1 year ago #
-
Sure everything is possible, although time and difficulty are usually the constraints. I guess that wasn't the answer you were waiting for ;)
On a high level what you should do is
remove the old tilemap texture from the texture cache
load the new texture using the texture cache
save the reference of the new texture
for every CCTMXLayer change the reference to the new texture (layer.textureAtlas.texture)Preferably do this at the beginning or end of a frame, since it could stall the gpu pipeline when doing mid frame.
Posted 1 year ago # -
I'm kinda new to Objective-C and cocos2d so I don't really understand your response but I greatly appreciate it. Hopefully with a little more information you can help me out with some specifics. So I have a game with a bunch of levels saved as tilemaps that currently use a default tileset. I would like to be able to have multiple themes that simply change the tileset reference or possibly just rename one of my resource files during runtime to the default tilesets name so that I don't need to have multiple copies of each level simply with different tileset references. If this is possible I would need some help with what code to use. I appreciate the help!
Posted 1 year ago # -
Before I explain more, I think it would be useful for you to have a better understanding of how a tilemap is processed in cocos. Just set a breakpoint where you initialize the map and step through the code with the debugger to see the methods and classes that are involved. Even though you might not get all the syntax or code involved, just knowing the flow of execution is already helpful for understanding my previous post.
You'll see that the classes involved are CCTMXTiledMap, CCTMXLayer, CCSpriteSheet, CCTextureAtlas, CCTextureCache and CCTexture2D.
Posted 1 year ago # -
It should be a relatively simple matter to override a class and add an "initWithPNG" that loads the texture from a given file rather than from the file given in the .tmx, while retaining the class' functionality.
If no one else looks into it I'll take a look at it later and see if I can cook up a simple solution later this week.
Posted 1 year ago # -
I looked through the debugger and I now understand what you meant with most of it. I'm still having some trouble actually putting it to use though. I found that when CCTMXLayer loads the texture it uses the code:
tex = [[CCTextureCache sharedTextureCache] addImage:tilesetInfo.sourceImage];
I looked into the documentation for CCTextureCache and found the various ways to remove textures but I don't know how to go about doing that without the key name.@cristophersisk - If you could look into that or give me some pointers about that method also I would greatly appreciate it!
Posted 1 year ago # -
Well you don't need the key since you have the CCTexture2D reference in your CCTMXLayer (layer.textureAtlas.texture). A CCTMXLayer inherits from CCSpriteseet, which contains a textureAtlas, which contains a CCTexture2D. So you can use 'removeTexture:(CCTexture2D*) tex' instead.
Now you can load a new image (preferably the async method), which returns a CCTexture2D reference. Replace the old texture reference of your layer with the new one and you're done.
Posted 1 year ago # -
Here is the code I managed to put together and compile after reading everything:
`[[CCTextureCache sharedTextureCache] removeTexture:wallLayer.textureAtlas.texture];
[[CCTextureCache sharedTextureCache] removeTexture:blockLayer.textureAtlas.texture];CCTexture2D *tex2 = [[CCTextureCache sharedTextureCache] addImage:@"tileset2.png"];
wallLayer.textureAtlas.texture = tex2;
blockLayer.textureAtlas.texture = tex2;`The problem now is that I have no tileset at all it seems. I'm possibly placing the code in the wrong spot but when the levels load I can play the game normally but nothing is displayed except my sprite.
Posted 1 year ago # -
What I didn't say, if two layers share the same tileset, then you only have to remove it once.
Could you try it without removing the old texture first?
Just to be sure, the new tileset has the same layout (margin, spacing, number of sprites, placement of sprites), dimensions as the old one?
Posted 1 year ago # -
I commented out the remove code and still got the blank map so the problem must be with the new tileset. The new tileset is the exact same image as the other one with just some colors changed until I get it working and get creative. I really appreciate all of your help with this!
Posted 1 year ago # -
I was getting curious if it would actually work, so I tested it in my project and it works as expected.
After the map is initialized I do
CCTexture2D *tex2; int i =0; for( CCSpriteSheet* child in [map children] ) { if (i==0) { [[CCTextureCache sharedTextureCache] removeTexture:child.textureAtlas.texture]; text2 = [CCTextureCache sharedTextureCache] addImage:@"newAtlas.png"]; } child.textureAtlas.texture=tex2; i++; }Which is the same as your code. To test it out on a more basic level, you could make a copy of your original tileset, save it using another name and try to load that one. If it works as expected, you know for sure that there is something wrong with your new tileset.
Posted 1 year ago # -
EDIT-
So I found my mistake and feel pretty dumb for it. When I was adding the new image I wasn't including the correct path to it so it was loading a blank image. Once I fixed that your solution worked perfectly. Thanks for all of your help with this, I really appreciate it!
Posted 1 year ago #
Reply
You must log in to post.