Java-Gaming.org    
Featured games (81)
games approved by the League of Dukes
Games in Showcase (497)
Games in Android Showcase (114)
games submitted by our members
Games in WIP (563)
games currently in development
News: Read the Java Gaming Resources, or peek at the official Java tutorials
 
    Home     Help   Search   Login   Register   
Pages: [1]
  ignore  |  Print  
  Spritesheet animator!  (Read 7062 times)
0 Members and 1 Guest are viewing this topic.
Offline darkFunction

Senior Newbie


Medals: 4



« Posted 2011-06-15 19:53:44 »

Hello to the JGo community!

I have written an application for creating sprites and animations and outputting XML which can be imported into a game engine.

I'm just looking for a bit of feedback on what sort of features you feel would help you in your day to day life as a game developer so I can incorporate the most useful features into the tool!

Cheers!

http://www.darkfunction.com
Offline zoto

Senior Member


Medals: 4



« Reply #1 - Posted 2011-06-15 20:57:38 »

Coloring in grayscale images, this is very useful if you allow a way for the player to pick a hair color or recoloring clothes etc.
Offline aazimon
« Reply #2 - Posted 2011-06-17 00:58:40 »

Impressive. I like it. I'm going to start using it. Thanks.
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline ra4king

JGO Kernel


Medals: 345
Projects: 3
Exp: 5 years


I'm the King!


« Reply #3 - Posted 2011-06-17 01:39:28 »

Did you make it using Swing, TWL, or some other GUI app?
Very impressive though. I'm also gonna start using it. I like apps that make my life easier Smiley

Offline darkFunction

Senior Newbie


Medals: 4



« Reply #4 - Posted 2011-06-17 07:29:18 »

It's made in Swing. 

If you find any bugs or issues please let me know and they will be fixed quickly.  Thanks!
Offline divxdede

Junior Member





« Reply #5 - Posted 2011-06-17 09:45:58 »

Hi,
This editor is very interresting.
Do you provide in the other side any lib implementation that can handle your output format ? (like a Slick one, Swing, ...) that can be used inside our games ?

Offline darkFunction

Senior Newbie


Medals: 4



« Reply #6 - Posted 2011-06-17 11:10:25 »

I will start work on library implementations soon, but I'm only one person and have a day job. I'm thinking of doing one for AndEngine first but haven't made my mind up yet!
Offline gouessej
« Reply #7 - Posted 2011-06-17 11:17:30 »

Hi!

What do you use to encode/decode XML? It is a free of charge software but will it become open source?

Anyway, creating such a tool is a good idea as there is a real lack of WYSIWYG editor for Java environment.

Offline darkFunction

Senior Newbie


Medals: 4



« Reply #8 - Posted 2011-06-17 13:07:17 »

Hi gouessej

I use xmlenc for the XML.

The tool is free of charge but will not be made open source.  It will remain free and continue to be supported with updates in line with user feedback. However, in time I hope to launch an advanced professional version with specialist features suited for large game studios, which will be a paid app. So I don't want to release the source code.

All libraries that I write to support various engines will be open sourced and available on the website.
Offline darkFunction

Senior Newbie


Medals: 4



« Reply #9 - Posted 2011-08-31 07:45:56 »

Version 1.2 available now Cheesy

Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline ReBirth
« Reply #10 - Posted 2011-08-31 11:37:04 »

Nice tool Smiley (although I havent jump into animated sprites)

Offline arielsan
« Reply #11 - Posted 2011-08-31 15:17:28 »

Great tool, something I wanting to have (and I wanted to do) from a long time.

Some suggestions and/or questions:

* is it possible to define the sprite center? to rotate the sprite over that center instead the default center, it is useful when defining an animation for a character and you want the center of the arm is on the shoulder. Not sure if the center should be defined when editing the animation or when editing the sprite sheet.
* is it possible to rotate using the mouse directly instead having to put the angle in the input field?
* which units is the cell delay using? doesn't seem to be milliseconds nor seconds.
* do you prefer I make suggestions/questions here or in your page?
* is it open source?
* some future suggestions: defining restrictions between sprites could be great to "simulate" a skeleton, or making a hierarchy even, like this weapon is always attached to the arm. I saw you have a hierarchy to the left for the sprites but didn't see if you already have this kind of restrictions.

Thanks for sharing your tool.


Offline arielsan
« Reply #12 - Posted 2011-08-31 16:47:55 »

Another suggestion:

* export current animation (or all animation) in one or more .gif files, to share with someone for example (my case) or to use it to create animated gifs

Offline Eli Delventhal

JGO Kernel


Medals: 42
Projects: 11
Exp: 10 years


Game Engineer


« Reply #13 - Posted 2011-08-31 18:27:34 »

Pretty cool. Allow me to contribute some source code:

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
40  
41  
42  
43  
44  
45  
46  
47  
48  
49  
50  
51  
52  
53  
54  
55  
56  
57  
58  
59  
60  
61  
62  
63  
64  
65  
66  
67  
68  
69  
70  
71  
72  
73  
74  
75  
76  
77  
78  
79  
80  
81  
82  
83  
84  
85  
86  
87  
88  
89  
90  
91  
92  
93  
94  
95  
96  
97  
98  
99  
100  
101  
102  
103  
104  
105  
106  
107  
108  
109  
110  
111  
112  
113  
114  
115  
116  
117  
118  
119  
120  
121  
122  
123  
124  
125  
126  
127  
128  
129  
130  
131  
132  
133  
134  
135  
136  
137  
138  
139  
140  
141  
142  
143  
144  
145  
146  
147  
148  
149  
150  
151  
152  
153  
154  
155  
156  
157  
158  
159  
160  
161  
162  
163  
164  
165  
166  
167  
168  
169  
170  
171  
172  
173  
174  
175  
176  
177  
178  
179  
180  
181  
182  
183  
184  
185  
186  
187  
188  
189  
190  
191  
192  
193  
194  
195  
196  
197  
198  
199  
200  
201  
202  
203  
204  
205  
206  
207  
208  
209  
210  
211  
212  
213  
214  
215  
216  
217  
218  
219  
220  
221  
222  
223  
224  
225  
226  
227  
228  
229  
230  
231  
232  
233  
234  
235  
236  
237  
238  
239  
240  
241  
242  
243  
244  
245  
246  
247  
248  
249  
250  
251  
252  
253  
254  
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Color;
import java.awt.image.BufferedImage;
import java.io.File;
import java.util.ArrayList;
import javax.imageio.ImageIO;
import javax.swing.JFileChooser;

public class AutoRipper
{
   private static BufferedImage spriteSheet;
   private static Color color;
   private static ArrayList<BufferedImage> sprites;
   private static int tolerance = 75;
   
   public static void main(String[] args)
   {
      sprites = new ArrayList<BufferedImage>();
      spriteSheet = open();
      scanAutomaticallyIteratively();
      saveSprites();
   }
   
   private static BufferedImage open()
   {
      JFileChooser fc = new JFileChooser();
     
      fc.setCurrentDirectory(new File("/Users/Will/Desktop"));
      fc.setAcceptAllFileFilterUsed(false);
      fc.setFileFilter(new ImageFileFilter());
      fc.setDialogTitle("Choose a Sprite Sheet");
     
      int returnVal = fc.showDialog(null, "Choose a Sprite Sheet");
     
      if (returnVal == JFileChooser.APPROVE_OPTION)
      {
              File file = fc.getSelectedFile();
         try
         {
            //Read the sprite sheet, then translate it to ARGB so I know how it is formatted
           BufferedImage im = ImageIO.read(file);
            BufferedImage ret = new BufferedImage(im.getWidth(),im.getHeight(),BufferedImage.TYPE_INT_ARGB);
            Graphics2D g = ret.createGraphics();
            g.drawImage(im,0,0,null);
            g.dispose();
            int[] c = ret.getRaster().getPixel(0,0,new int[4]);
            color = new Color(c[0],c[1],c[2],c[3]);
            return ret;
         }
         catch(Exception e) {e.printStackTrace();}
        }
      return null;
   }
   
   private static String chooseSaveDirectory()
   {
      JFileChooser fc = new JFileChooser();
     
      fc.setCurrentDirectory(new File(System.getProperty("user.dir")));
      fc.setAcceptAllFileFilterUsed(false);
      fc.setFileFilter(new DirectoryFileFilter());
      fc.setDialogTitle("Choose a Folder");
      fc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
     
      int returnVal = fc.showDialog(null, "Save Results in Folder...");
     
      if (returnVal == JFileChooser.APPROVE_OPTION)
      {
           return fc.getSelectedFile().getAbsolutePath();
        }
      return null;
   }
   
   private static class ImageFileFilter extends javax.swing.filechooser.FileFilter
   {
      public boolean accept(File f)
      {
         if (f.isDirectory())
              return true;

         String e = "";
              String s = f.getName();
              int i = s.lastIndexOf('.');
              if (i > 0 &&  i < s.length() - 1)
               e = s.substring(i+1).toLowerCase();
             
              String[] types = {"jpg","gif","tif","bmp","png","tiff","jpeg"};
             
              for (int j = 0; j < types.length; j++)
                 if (e.equals(types[j]))
                    return true;
          return false;
      }
     
      public String getDescription()
      {
         return ".jpg .gif .tif .bmp .png";
      }
   }
   
   private static class DirectoryFileFilter extends javax.swing.filechooser.FileFilter
   {
      public boolean accept(File f)
      {
         if (f.isDirectory())
              return true;
          return false;
      }
     
      public String getDescription()
      {
         return "Directories";
      }
   }
   
   public static void scanAutomaticallyIteratively()
   {
      if (spriteSheet == null)
         return;
     
      int minSize = 50;
     
      //A 2D array of booleans that tells whether a pixel has already been factored or not
     boolean[][] scanned = new boolean[spriteSheet.getWidth()][spriteSheet.getHeight()];
      //An ArrayList of all pixels that are connected. Is refreshed automatically per scan
     ArrayList<Point> connectedPixels = new ArrayList<Point>();
     
      for (int y = 0; y < spriteSheet.getHeight(); y++)
      {
         for (int x = 0; x < spriteSheet.getWidth(); x++)
         {
            //If a pixel is found that is within bounds, hasn't been scanned and
           //is not transparent, we need to search its connected pixels
           if (inBounds(x,y) && !scanned[x][y] && !pixelIsTransparent(x,y))
            {
               //Add the point to the list of connected pixels
              connectedPixels.add(new Point(x,y));
               scanned[x][y] = true;
               
               //Keep searching every pixel within the list until all the
              //pixels within the list's adjacent pixels have been scanned,
              //are transparent, or are not in bounds.
              int search = 0;
               while (search < connectedPixels.size())
               {
                  Point p = (Point) connectedPixels.get(search);
                  //Search the surrounding pixels. If any of them are not scanned, not transparent,
                 //and within bounds (inside the image), call this method recursively with new x and y.
                 for (int i = -1; i <= 1; i++)
                  {
                     for (int j = -1; j <= 1; j++)
                     {
                        if (inBounds(i+p.x,j+p.y) && !scanned[p.x+i][p.y+j] && !pixelIsTransparent(i+p.x,j+p.y))
                        {
                           connectedPixels.add(new Point(i+p.x,j+p.y));
                           scanned[i+p.x][j+p.y] = true;
                        }
                     }
                  }
                  search++;
               }
               
               //There should now be a completed sprite in the list
              addSpriteFromPixelList(connectedPixels,minSize);
               connectedPixels.clear();
            }
         }
      }
   }
   
   public static boolean inBounds(int x, int y)
   {
      return (x >= 0 && x < spriteSheet.getWidth() && y >= 0 && y < spriteSheet.getHeight());
   }
   
   public static boolean pixelIsTransparent(int x, int y)
   {
      int[] sprite = spriteSheet.getRaster().getPixel(x,y,new int[4]);
      int[] transColor = {color.getRed(),color.getBlue(),color.getGreen(),color.getAlpha()};
      int total = 0;
     
      for (int i = 0; i < sprite.length; i++)
      {
         total += Math.abs(sprite[i]-transColor[i]);
         if (total > tolerance)
            return false;
      }
      return true;
   }
   
   public static void addSpriteFromPixelList(ArrayList<Point> connectedPixels, int minSize)
   {
      //Don't add if there are not minmum size pixels in the sprite
     if (connectedPixels.size() < minSize)
         return;
      //Theoretically, a new sprite has now been created and all of its points
     //are within the connectedPixels list. Now we need translate a list of
     //pixels into a BufferedImage, first finding its min/max coordinates.
     int minX, minY, maxX, maxY;
      minX = maxX = ((Point)connectedPixels.get(0)).x;
      minY = maxY = ((Point)connectedPixels.get(0)).y;
      for (int i = 1; i < connectedPixels.size(); i++)
      {
         Point p = (Point) connectedPixels.get(i);
         if (p.x < minX)
            minX = p.x;
         if (p.x > maxX)
            maxX = p.x;
         if (p.y < minY)
            minY = p.y;
         if (p.y > maxY)
            maxY = p.y;
      }
      //Now that we have the bounds of the image, we can add the sprite and clear the pixels
     addSprite(minX,minY,maxX-minX+1,maxY-minY+1);
   }
   
   public static void addSprite(int x, int y, int width, int height)
   {
      if (width > 0 && height > 0)
      {
         BufferedImage sprite = new BufferedImage(width,height,BufferedImage.TYPE_INT_ARGB);
         Graphics2D g = sprite.createGraphics();
         g.drawImage(spriteSheet,-x,-y,null);
         g.dispose();
         
         //Turn the specified color transparent
        for (int i = 0; i < sprite.getWidth(); i++)
            for (int j = 0; j < sprite.getHeight(); j++)
               if(pixelIsTransparent(i+x,j+y))
                  sprite.getRaster().setPixel(i,j,new int[]{255,255,255,255});
         
         if (sprite.getWidth() > 0 && sprite.getHeight() > 0)
            sprites.add(sprite);
      }
   }
   public static void saveSprites()
   {
      String saveFolder = chooseSaveDirectory();
     
      if (saveFolder != null)
      {
         for (int i = 0; i < sprites.size(); i++)
         {
            try
            {
               ImageIO.write((BufferedImage)sprites.get(i), "png", new java.io.File(saveFolder + "/" + i + ".png"));
            }
            catch (Exception ex) {ex.printStackTrace();}
         }
      }
   }
}


This code automatically takes a sprite sheet and splits it into individual images. You can modify it a bit to give you the rects for each sprite, then allow the player to correct them as desired. That would be a lot better than having to do it all manually, as this tool is 99% correct (except in sheets where stuff overlaps rects, which is bad anyway).

See my work:
OTC Software
Offline darkFunction

Senior Newbie


Medals: 4



« Reply #14 - Posted 2011-09-01 09:04:01 »

@Arielsan

* is it possible to define the sprite center?
   - no but a great suggestion, thanks!

* is it possible to rotate using the mouse directly instead having to put the angle in the input field?
  - no, something I wanted to do but wanted to get a release out quickly. It's on the TODO list already as an enhancement

* which units is the cell delay using? doesn't seem to be milliseconds nor seconds.
  - frames.  It's intended so you can call animation.tick() in your game every frame or multiple of frames. I have had a lot of questions about this actually. I think it makes more sense to use frames so it has easier engine integration however an option to set the FPS for the preview should be made available.

* do you prefer I make suggestions/questions here or in your page?
 - wherever you like! I will check back here regularly

* is it open source?
 - no. See comments below

* some future suggestions: defining restrictions between sprites could be great to "simulate" a skeleton, or making a hierarchy even, like this weapon is always attached to the arm. I saw you have a hierarchy to the left for the sprites but didn't see if you already have this kind of restrictions.
  - cool idea! As you say, something for the future maybe

* export current animation (or all animation) in one or more .gif files, to share with someone for example (my case) or to use it to create animated gifs
  - I *really* like this idea, in fact I'm quite excited to start implementing it straight away! haha


Questions regarding Open Source
I won't be Open Sourcing unfortunately (for now) as I hope to release a 'Pro' version in the future with some advanced features which will require a *small* payment.  I'm hoping to make something of a microISV from this project, but feel strongly that indy developers should be allowed free access to time saving tools like this.  So I have decided to make the essential functionality (everything so far) free for everybody but charge for game studios or professionals that require more advanced features and are willing to pay for them. I hope you understand!

When I say advanced features, this probably means
 - Collision polygons
 - Multiple sheet support
 - Customisable output formats
 - etc

@Eli Delventhal
.. with that said, I would graciously accept your code and include it in this free version. Let me know if you are not happy with this!

Offline Cero
« Reply #15 - Posted 2011-09-01 11:40:19 »

I guess Eli's code would be good. You current trim function doesnt seem to do anything useful for my sprites.

Offline darkFunction

Senior Newbie


Medals: 4



« Reply #16 - Posted 2011-09-01 13:47:41 »

Trim should just tighten the box around any non-transparent pixels  Wink
Offline Cero
« Reply #17 - Posted 2011-09-01 15:40:05 »

yeah no, at least not for me, it like quaters them and seems to just start at the left top, and the image is than cropped somewhere arbitrary

Offline Eli Delventhal

JGO Kernel


Medals: 42
Projects: 11
Exp: 10 years


Game Engineer


« Reply #18 - Posted 2011-09-01 17:15:59 »

Eli Delventhal
.. with that said, I would graciously accept your code and include it in this free version. Let me know if you are not happy with this!
That's fine with me, it's free code, and not rocket science or anything.

See my work:
OTC Software
Offline Nate

JGO Kernel


Medals: 147
Projects: 4
Exp: 14 years


Esoteric Software


« Reply #19 - Posted 2011-09-01 19:09:58 »

Skeletal animations?

Offline darkFunction

Senior Newbie


Medals: 4



« Reply #20 - Posted 2011-09-12 08:53:41 »

@Cero - you're right, it was broken but now it is fixed. Cheers for the heads up
Offline R.D.

Senior Member


Medals: 2
Projects: 1


"For the last time, Hats ARE Awesome"


« Reply #21 - Posted 2011-09-14 12:33:06 »

Whenever  I want to load a spritesheet for an animation i get a "error loading file" Sad
Pages: [1]
  ignore  |  Print  
 
 
You cannot reply to this message, because it is very, very old.

 

Add your game by posting it in the WIP section,
or publish it in Showcase.

The first screenshot will be displayed as a thumbnail.

BurntPizza (21 views)
2014-09-19 03:14:18

Dwinin (35 views)
2014-09-12 09:08:26

Norakomi (62 views)
2014-09-10 13:57:51

TehJavaDev (87 views)
2014-09-10 06:39:09

Tekkerue (42 views)
2014-09-09 02:24:56

mitcheeb (65 views)
2014-09-08 06:06:29

BurntPizza (47 views)
2014-09-07 01:13:42

Longarmx (35 views)
2014-09-07 01:12:14

Longarmx (40 views)
2014-09-07 01:11:22

Longarmx (36 views)
2014-09-07 01:10:19
List of Learning Resources
by Longor1996
2014-08-16 10:40:00

List of Learning Resources
by SilverTiger
2014-08-05 19:33:27

Resources for WIP games
by CogWheelz
2014-08-01 16:20:17

Resources for WIP games
by CogWheelz
2014-08-01 16:19:50

List of Learning Resources
by SilverTiger
2014-07-31 16:29:50

List of Learning Resources
by SilverTiger
2014-07-31 16:26:06

List of Learning Resources
by SilverTiger
2014-07-31 11:54:12

HotSpot Options
by dleskov
2014-07-08 01:59:08
java-gaming.org is not responsible for the content posted by its members, including references to external websites, and other references that may or may not have a relation with our primarily gaming and game production oriented community. inquiries and complaints can be sent via email to the info‑account of the company managing the website of java‑gaming.org
Powered by MySQL Powered by PHP Powered by SMF 1.1.18 | SMF © 2013, Simple Machines | Managed by Enhanced Four Valid XHTML 1.0! Valid CSS!