- Home /
How do 2D RPG Games customize avatar sprites with different items and armor.
Background:
I am using sprite sheets (https://github.com/makrohn/Universal-LPC-spritesheet)
There is a Body Sheet and then lots of hair, eyes, clothings, weapons sheets
I do NOT want to manually overlay the sheets in Gimp, save lots of spritesheets (Goblin_Unarmed, Goblin_WithSword) and then attach those sheets to gameObjects in the editor.
I DO want to (during runtime) build a character using those sheets.
What I am trying (and failing)
In C# I can load the sprite sheets I want (Body_1, Eyes_1,Armor_12,etc..) and merge then all together as a new PNG file. I can manage the alpha transparency as well as layering them correctly. This gives me a new spritesheet that is exactly what I want.
I TRIED to load the PNG as a new texture, splice it into 64x64 array and then change the Player GameObject Animators to use the new sprite[].
I simply can't get it to work, I can load the texture, but I can't figure out the Texture Importer on the newly created file (remember its new, so its not in Resources)
Even if I got that working, I am not sure how to update the Sprites in memory loaded into the Player and the Players Animators.
Question: How do other game creators do this? Imagine I have 1000's of combinations of items and I want to let people customize their avatars. I want to lets mobs pick up weapons off the ground and equip armor. I don't want 10000's of variants of characters in the Resources and then load them when needed?
Ideas?
Update 2
Damn, the code below works great, BUT, it requires UnityEditor which means no making builds :( Sigh back to the drawing board.
Update
I stumbled onto one key bit of the puzzle.
I figured out a (poor performance way) of changing a sliced sprite on the disk and updating it runtime.
Steps
[UnityEditor] Add a SpritePage.PNG to a Resouces Folder
[UnityEditor] Set the SpriteMod to Multiple and Splice it however you want.
[FileSystem] Notice you now have the original PNG and a new .meta file.
[UnityEditor] Drag one of the Sprite[] items onto your Scene (make sure you can see it) and rename to Player.
[UnityEditor] Add a new script to that Player Object in the Scene
[Script] Paste in the update() method below
[GAME] Run the game
[FileSystem] Copy and Replace the PNG on the filesystem with a new PNG that is a differnt spritesheet (obviously same dimensions)
[GAME] Press the Space Bar (that's the key that triggers the change)
[SUCCESS] Notice that there is a game pause while the texture is updated, the Sprite automatically changes on the Player Object.
Animation Sprite Change Verified
I verified that this works with Animator using the sprites on the Player Objects. Look at this guys sprite animation tutorial. I am using his method to animate, then my method to swap avatar. https://www.youtube.com/watch?v=XZDjkQ8wEd0
What this means
Imaging that we simply add ONE sprite sheet (called PCAppearance) for the player (naked). Each time the player changes their appearance, we use C# to take 15 PNGs (not referenced inside Unity) and merge them together (bosy, hair, eyes, shoes, weapons, armor) and save that 'over the top of' of the current PCAppearence.png. Then run the script below to update it all across the game.
void Update () {
if (Input.GetKeyDown ("space"))
{
Debug.Log("[SPACE] Reload Texture");
Texture2D myTexture = (Texture2D)AssetDatabase.LoadAssetAtPath<Texture2D>("Assets/Resources/Sprites/PCAppearance.png");
string path = AssetDatabase.GetAssetPath(myTexture);
TextureImporter ti = AssetImporter.GetAtPath(path) as TextureImporter;
ti.isReadable = true;
EditorUtility.SetDirty(ti);
ti.SaveAndReimport();
}
}
You could also create a simple "body reference point" system where you store the positions of certain body parts, like head, right hand etc., and use those to overlay clothing and equipped items over the naked character sprite. The positions would have to be set for each frame, of course, but only once.
@mcowan hello i was wondering if you have succeeded in building this dynamic item system and i tryed to use your code but there is lot of undefined variables and i dont know what type they are (i am really new in this) so if you could leave the rest of the code... or explain some other method i would be really tankful :)
It's an old post, but if anyone still needs something to go off of.. I was able to get the LPC characters to animate dynamically.
Code/Demo https://github.com/jmvogt/Unity-LPC-Character-Animator
The animation vs movement speed is a bit off, but my focus has been on dynamic rendering rather than the animation/movement being in sync.. you can tweak that.
I'm new to Unity and Game Development in general, so hopefully I did things correctly, but I took the following approach:
Structure spritesheets in folders using a format of /DNAType/gender/model where the DNAType can be anything from body, head, hands, to feet, etc.. (You define these in the DNABlockType script and everything else happens like magic. (Well, sprites need to be in the right folder structure, and AT$$anonymous$$ this only supports the giant walk, hurt, shoot, slash spreadsheet)
Used an editor script to load all frames from all spritesheets into a List. This created a sprite Atlas automatically, which I could access at runtime. I set the name of each sprite to something I could parse later to build out into dictionaries/lookups. I modified this script to label the sprites on import: https://bitcula.com/universal-lpc-spritesheet-unity-importer/
At the start of a scene, load all possible sprites into AnimationDNABlock objects, where each block represents a $$anonymous$$odel / Direction / Action as well as all associated sprites. For example, the right male platemail "shoot" action could be stored in a single block, with a list of body_male_platemail_sh_r_0 - body_male_platemail_sh_r_7 sprites. Preload all AnimationDNABlocks into caches.
After the animations are loaded, I populate a "CharacterDNA" object that is made up CharacterDNABlocks. These blocks simply hold the "model key" and the color configuration of the character. Update their values at the beginning of your scene and let the PlayerController handle the rest. This is different from the AnimationDNA/Blocks mentioned in step 3. Those are used to render the actual animation. The CharacterDNA simply represents the race/equipment/hair/etc. of a character.
In the playerController, check if the last action has changed OR if one of the Character DNA blocks is dirty. If so, use the model/color settings from the Character DNA Blocks to update the AnimationDNA. Fetch the AnimationDNABlocks that have changed from the cache built in step 3. Finally, update the AnimationRenderer to use the updated AnimationDNA.
The AnimationRenderer will look through each each AnimationDNABlock.. check if it's enabled, and if so, update it's associated GameObject's SpriteRenderer component with the AnimationDNABlock sprite (using the current frame for the index!). Additionally, update the SpriteRenderer's material color.
I probably explained too much, but the biggest issue I see going forward is that I have 21 DNATypes and I'd like to add more. I just don't know how that will scale if I were to add.. 50 characters onto the screen..
Answer by zach-r-d · Jun 12, 2015 at 05:34 PM
Instead of manually combining textures on the fly, it would probably be easier to have several sprites overlaid on top of each other that animate in sync; with z-order controlling which ones go on top of each other. Looking at the spritesheets you're using, I'm fairly certain this is how they are meant to be used.
For example, when the player has nothing equipped, it would just be their naked sprite with z-depth 0 (for example). If they equipped a chestplate, a new GameObject with the chestplate sprite would be attached as a child that has z-depth .2 or so. If the player then equipped regular clothing that goes under the chestplate, a new sprite with the clothing sprite would be attached at z-depth .1. Unequipping an object just means deleting the GameObject with the appropriate sprite.
I thought of this, but wouldn't you have to know all the sprite sheets ahead of time? The problem is there will be thousands of sprite sheet and I plan to let players customize and upload their own avatars, weapons etc.. as long as they fit into the LPC module.
I would also worry about memory and CPU usage of all those layers. $$anonymous$$y vision is of a persistent world, where items never decay. When a player dies, their equipment is picked up by monsters and equipped or tossed into chests.
Imagine having enough ingame money to create a custom sword. You can use your editor to modify they sword icon. Then you die and your next character runs across a goblin chief with it :)
Take a look at this online avatar generator: http://gaurav.munjal.us/Universal-LPC-Spritesheet-Character-Generator/
Thanks for clarifying; I think I understand what you're going for a little better now.
You wouldn't have to know the sprite sheets ahead of time; they could be created dynamically given a texture/image file and a desired z-order (which sounds like it is defined by LPC convention).
(Quick aside by the way: some of the classes you use in the code posted above (AssetDatabase, EditorUtility, probably TextureImporter) are editor-only and will not compile when making a build. You'll need to use the WWW class with the file:// protocol ins$$anonymous$$d)
If you're concerned about memory usage, I can guarantee that more memory will be used if each character has an individual, custom spritesheet texture ins$$anonymous$$d of sharing many spritesheets that are then referenced by a few extra child GameObjects. While a little bit of CPU usage would be saved per frame due to fewer draw calls, it probably isn't worth it, especially since rebuilding a texture every time a character equips or unequips something is going to be CPU-intensive.
Oh man zach.r.d - I did not know that the UnityEditor could not be built :( I had it working exactly as I wanted. Thanks for taking the time you answer so much!
I will investigate your method with GameObjects for each 'slot'. $$anonymous$$y only question is how do you animate the player then? I am using Animators as shown here: https://www.youtube.com/watch?v=XZDjkQ8wEd0. Its a flipbook of sprites. Not sure how to use layered Gameobjects?
I would LOVE to stay with that simple animtation scheme .. but it seems I might need to investigate something else .. maybe "unity 2d mecanim" ??
Thoughts?
Using Animator is using $$anonymous$$ecanim, it already works with 2d. :)
Assu$$anonymous$$g the character is one GameObject, and each of its sprite "layers" are on separate GameObjects parented under the character, there are two strategies. One is to have one Animator on the Player that controls all of the sprites underneath it, but I'm not actually sure how feasible that is. The other is to have each child GameObject have its own animator, and then have a script on the character's GameObject that calls all of them whenever you do SetBool, SetFloat, etc.
$$anonymous$$ultiple animators seems like the way to go. I will try that!
I am not 100% ready to abandon dynamic loading if sprites. At least I understand how builds and asset packaging works now. Thanks for your help.
I am going to try building chained animators that have their sprites updated automatically from disk.
When I get home I will mark you as answering the question. Thanks.
Answer by J0hn4n · Aug 24, 2017 at 02:44 AM
I know this post its old but , i think you need learn some basics patterns if u are using c# there is a System.Drawing also there is imagicpick or something like that. But i think thats its dumbsome if all the images have the same size why not just overlay them for some reason there is sprite order and Z Axis??? i think its also a lot better because you can use tint and do something like terraria. But anyway another alternative can be create your custom animator like i did, and just update the sprite array set pivot points and anchor in a custom file format etc.
Your answer
Follow this Question
Related Questions
2D in Unity3D 2 Answers
Sprite Shading 1 Answer
Adding a Sprite 1 Answer
Unity Adds Antialiasing to Texture 2 Answers
How To Do This? 0 Answers