Show posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.

Messages - DarknessSurrounds

1
Development Tools / Re: RPG Scan Tool - Beta Testers
August 19, 2013, 09:10:26 pm
Yeah I know :| I was just curious if a version of this app (beta or otherwise) had been circulated in any fashion.
2
Development Tools / Re: RPG Scan Tool - Beta Testers
August 18, 2013, 01:00:45 pm
Sorry to necropost, but did this app ever get finished?  I know this topic hasn't been posted in for a year but this sounds like it would be an extremely cool and useful tool.
3
Are you allowed to use switch statements?  They're very nice for situations such as this.

http://www.cprogramming.com/tutorial/lesson5.html
4
ARC Welder / Re: ATTN: F0
November 19, 2012, 04:11:08 pm
Damn that really sucks.  He just dropped off the face of the earth.

Well Ryex, looks like You're The Man Now Dog.
5
ARC Welder / Re: ATTN: F0
November 18, 2012, 06:00:24 pm
Alright, so when I first found out about ARC, I was sophomore in college, eagerly awaiting a release.

I'm literally graduating university next month.  Just trying to put things in perspective  ;)
6
ARC Welder / Re: ATTN: F0
October 22, 2012, 04:33:54 am
Dear F0,

I have been religiously following the development of ARC for almost a year and a half.  Shortly after I found out about your wondrous project, I realized that doing much more work in RMXP would just lead to more problems.  I didn't want to have to reinvent the wheel, then have all that work be redundant, as there are MANY features in ARC that I want to eventually take advantage of.  There are also other core features, like the improved Window class, that I really want to use and build my systems on top of.  It would be a waste of time to get all that stuff working with XP's crappy Window class and then later have to port EVERYTHING over to ARC's Window class.

Basically, my project has been mostly on hiatus (except for some map design and resource creation) for a 1 and 1/2 years while I've waited for ARC.  I personally know how sometimes the HARDEST part of a project is that last little bit you need to finish to make it all worth it.  Keep up the great work, but hurry it up, will ya???  :^_^':
7
I just updated to the latest graphics driver, which was released on 6/21.  Same problems  :uhm:
8
Alright, I just repeated the tests on my desktop.  It has a XFX Radeon 6870 1GB (256 bit) Graphics card, purchased last year.

There are no problems.  Everything works as it should, the 3 builds are indistinguishable.  I guess this card supports pixel shaders no problem.  It's kind of weird, because my laptop is actually newer than my PC graphics card, but apparently doesn't support pixel shaders.
9
On that note, I should probably post my experiences with the last few dev builds.

0.9.8.652: Everything seems to be working properly

Spoiler: ShowHide


0.9.8.666: Major problems.  Namely the transparent parts around the enemies, and what looks like some random texture issues.  Also I'm getting the misplaced tiles problem.  What's strange is that it seems to change every time I go between one map and the next.  This might be a problem with the tile buffers.

Spoiler: ShowHide




Beta Build: Same as above

I should note that I did not experience any problems with the pixel shaders used in the fog layers.  This laptop is a Lenovo x220 Tablet hybrid with an Intel HD Graphics 3000 (GT2+) GPU.

I'll repeat these tests in a few days on my Desktop, which has an XFX Radeon 6870 1GB (256 bit) graphics card.
10
ARC Welder / Re: ARCed.NET
July 15, 2012, 03:08:54 am
This is great news!  I'm eagerly awaiting this.  Great job guys!
11
That sounds awesome!  I take it this functionality is going to wait until the full version?
12
Hey, are you guys going to release how you implement the Window class?  I want to eventually extend it to function like a better RMVX window class (basically multiple stretched/tiled background layers at different opacities).  I think I remember you saying something about supporting about the ability to do this eventually.  Am I just getting way ahead of myself here?
13
Ok thanks for the replies guys!  I did get it working!  I think the error might have been caused by the fact that I had non UTF-8 characters in my script names (the filenames).  specifically these:

« »


Anyways removing those characters from all the filenames and adding the encoding comment at the top of all the scripts did the trick.  You may want to have non UTF-8 characters stripped from the script names when they're converted.

Also one other thing of note that has caused a couple problems: the array method nitems was removed in Ruby 1.9.  Some of my scripts used that and so it was causing problems.  It can be fixed by redefining the method for class Array:

class Array
def nitems
count{|x| !x.nil?}
end
end


I'll make a post if I find any other issues.
14
I wasn't sure where I should post this, here or in the topic for the RMXP project converter.

I've been playing around with the project converter and the beta engine the past couple days, trying to convert projects, and I wanted to post my experiences and report a few bugs I've found.

A few of the projects I've converted simply hung at a black screen or immediately crashed.  Reviewing the log files, it seems that the projects I tried were mostly trying to load data from MapInfos.rxdata, which obviously doesn't exist.  Any script that reads the name of a map would do this.  Commenting that line out usually allowed the project to run.

The first problem I found was, when using switch statements, at some places in my code I had something like:


case a
when 1..5:
  puts "It's between 1 and 5"
when 6:
  puts "It's 6"
when String:
  puts "You passed a string"
else
  puts "You gave me #{a} -- I have no idea what to do with that."
end


Notice the colons after the case statements.  ARC doesn't like these and crashes when it encounters them.  RMXP however would run them just fine.  This is pretty unimportant, but I figure it's worth mentioning.

A massive problem I ran into was trying to convert an old beta build of my project.  This is mostly an ungodly hacked together mess, and I'm eventually going to refactor the whole thing and build it off the base ATOA 3 battle system, but I wanted to try and convert it anyway.

It kept crashing with weird errors, but I eventually figured it out.  The problem was that I had used an old version of ForeverZer0's Gemini script editor to edit the Scripts.rxdata.  It was a long time ago, and I remember there being a bug where it would improperly inflate/deflate certain characters, namely Japanese characters.  It would replace them with a bunch of garbage data, and when reloaded and saved again, it would replace that garbage data with even more garbage.  Reviewing the individual script files, I found that many of them were HUGE, like 5-6 MB's each.  Most of these were just filled with that garbage data, it was mostly characters like: ƒ¼Ã

Anyways some of these 6 MB files, after I manually removed all the garbage data, were only 40-50 KB, so there was an obscene amount of junk that Gemini had inserted in there.  Not hating of Gemini or ForeverZer0, it's an awesome app, but anyone who had used Gemini on their project should beware of this bug.

Anyway, after many hours, I finally got the project to run!  However it would crash with a Runtime Error when I tried to pause/bring up the menu.  This may have been due to the use of several external scripts and libraries I was using, but I really don't know.  I'm not too concerned with getting this particular project working, I'm more concerned about the next bug I found.

The refactoring of my project is based on ATOA 3.2 (http://save-point.org/thread-2136.html).  RMXP runs this with no problems.  However, when I convert it to ARC, it, as well as a clean ATOA 3.2, it immediately crashes with the error:

code converter not found (ASCII-8BIT to UTF-8)


I thought that one of the files might be in the wrong format, so I used an app to manually convert all the script files to UTF-8.  However I still get the same error.  Any idea why this would be happening?




In any event, great work guys!  Congratulations on releasing the beta version of the engine, keep up the great work!  I'm sure once the editor is done and a default set of ARC scripts have been written for us to build off, we will run into less problems.  But this is progress!
15
I think that would be a great idea!  I'd most definitely be interested in beta testing the engine.

I could play through a few RMXP games that I've been meaning to finish, as well as test my own game.  It's more of a tech demo at the moment, with the basic systems mostly implemented: CBS, CMS, and a map system with platforming elements that dynamically spawns tons of events.  Needless to say the RMXP interpreter gets destroyed by it and frequently locks up or crashes, and the VX interpreter doesn't fare too much better.  I'm interested to see how ARC will handle it.
16
Just checking status, are you still planning on releasing the engine and the editor concurrently?
17
alright alright... i was more concerned with sharing the script than people stealing the charset, but now you've made me paranoid, lol  :ninja:
18
yeah most likely, it still would require a little work though.  Can't let people have it too easy  8)
19
This is a script for Photoshop CS.  I know it will work with CS3 and above, not sure about below.  I didn't know where to post this so feel free to move it if this isn't the right board.

// Written by Eclipse

/*

// BEGIN__HARVEST_EXCEPTION_ZSTRING

<javascriptresource>
<name>Create Spritesheet from Charset animation</name>
<category>Game Development</category>
</javascriptresource>

// END__HARVEST_EXCEPTION_ZSTRING

*/

// enable double clicking from the Macintosh Finder or the Windows Explorer
#target photoshop

// debugging code
// debug level: 0-2 (0:disable, 1:break on error, 2:break at beginning)
/*
debugger;
$.level = 1;
*/



////////////////////////////////////////////////////
// script configuration
////////////////////////////////////////////////////
function configObj()
{
   // document configuration
   this.document = {};
   // link of valid document suffixes
   this.document.suffix = {
       "D" : "D",
       "L" : "L",
       "R" : "R",
       "U" : "U",
       "LR": "LR",
       "_" : "-",
   };
   
   // spritesheet configuration
   this.spritesheet = {};
   this.spritesheet.cols = 4;
   this.spritesheet.rows = 4;
   this.spritesheet.colWidth = 32;
   this.spritesheet.rowHeight = 48;
   this.spritesheet.xOffsetFormula = "Math.ceil( (config.spritesheet.colWidth - {WIDTH})/2 )";
   this.spritesheet.yOffsetFormula = "(config.spritesheet.rowHeight - {HEIGHT})";
   this.spritesheet.animOrder = [this.document.suffix["D"], this.document.suffix["L"], this.document.suffix["R"], this.document.suffix["U"]];
   this.spritesheet.solidBackground = false;
   
   // current animation configuration
   this.current = {};
   // detect the name of the current document
   this.current.docName = app.activeDocument.name.replace(".psd", "");
   for (var i in this.document.suffix) {
       this.current.docName = this.current.docName.replace(this.document.suffix[i], "");
   }
   
   // create a list of the relevant animations
   this.current.rootPath = app.activeDocument.path;
   this.current.tempPath = "Z:/tmp";
   this.current.savePath = this.current.rootPath;
   this.current.docPaths = {};
   for (var sufx in this.document.suffix) {
       this.current.docPaths[this.document.suffix[sufx]] = this.current.rootPath+"/"+this.current.docName+this.document.suffix["_"]+this.document.suffix[sufx]+".psd";
   }
   delete this.current.docPaths[this.document.suffix["_"]];
   
   // create a list of the animations that exist
   this.current.validDocs = {};
   for (var doc in this.current.docPaths) {
       var df = File(this.current.docPaths[doc]);
       if (df.exists) {
           this.current.validDocs[doc] = this.current.docPaths[doc];
       }
   }
}



////////////////////////////////////////////////////
// starting dialog window
//      config  :   the config object (passed by reference)
////////////////////////////////////////////////////
function dialogStart(cfg)
{
   // create new window
   var dlg = new Window("dialog", "Generate RMXP Charset from Photoshop animation files", [100, 100, 700, 500]);

   // add Animation Info panel
   dlg.msgPnl = dlg.add("panel", [15, 15, 580, 220], "Animation File Info:");
   // solid bg?
   dlg.msgPnl.aiSolidBgText = dlg.msgPnl.add("StaticText", [20, 20, 300, 60], "Do the animation files have a solid background?");
   dlg.msgPnl.aiSolidBg = dlg.msgPnl.add("CheckBox", [300, 17, 320, 45], cfg.spritesheet.solidBackground);
   dlg.msgPnl.aiSolidBgWarningText1 = dlg.msgPnl.add("StaticText", [340, 20, 550, 40], "If the animation files have a");
   dlg.msgPnl.aiSolidBgWarningText2 = dlg.msgPnl.add("StaticText", [340, 40, 550, 60], "transparent background, the script");
   dlg.msgPnl.aiSolidBgWarningText3 = dlg.msgPnl.add("StaticText", [340, 60, 550, 80], "will take much longer to execute.");
   // detected files
   dlg.msgPnl.detectedFilesTextPnl = dlg.add("panel", [35, 85, 300, 200], "Files Detected:");
   // list detected files
   var y = 0;
   for (var doc in cfg.current.validDocs) {
       dlg.msgPnl.detectedFilesTextPnl.add( "StaticText", [20, y+20, 100, y+70], cfg.current.validDocs[doc].substr(cfg.current.validDocs[doc].lastIndexOf("/")+1) );
       y += 20;
   }
   
   // add New Spritesheet Info panel
   dlg.ssPnl = dlg.add("panel", [15, 240, 580, 340], "New Spritesheet Info:");
   // num spritesheet columns
   dlg.ssPnl.ssColsText1 = dlg.ssPnl.add("StaticText", [20, 22, 120, 40], "Column Width:");
   dlg.ssPnl.ssCols      = dlg.ssPnl.add("EditText", [125, 20, 160, 40], cfg.spritesheet.colWidth);
   dlg.ssPnl.ssColsText2 = dlg.ssPnl.add("StaticText", [165, 22, 180, 40], "px");
   // num spritesheet rows
   dlg.ssPnl.ssRowsText1 = dlg.ssPnl.add("StaticText", [20, 52, 120, 70], "Row Height:");
   dlg.ssPnl.ssRows      = dlg.ssPnl.add("EditText", [125, 50, 160, 70], cfg.spritesheet.rowHeight);
   dlg.ssPnl.ssRowsText2 = dlg.ssPnl.add("StaticText", [165, 52, 180, 40], "px");
   
   
   
   // add accept button...
   dlg.beginBtn = dlg.add("button", [195, 360, 295, 380], "Begin", {name:"ok"});                    
   // add canel button.
   dlg.cancelBtn = dlg.add("button", [315, 360, 415, 380], "Cancel", {name:"ok"});
   
   
   
   // when BEGIN is clicked
   dlg.beginBtn.onClick = function() {
       config.spritesheet.colWidth = parseInt(dlg.ssPnl.ssCols.text);
       config.spritesheet.rowHeight = parseInt(dlg.ssPnl.ssRows.text);
       alert(dlg.msgPnl.aiSolidBg.value);
       config.spritesheet.solidBackground = (dlg.msgPnl.aiSolidBg.value == "true") ? true : false;
       
       /*// insert author into active documentinfo...
       activeDocument.info.title = dlg.msgPnl.msgAuthor.text;                                                                    
       // insert copyright notice into active documentinfo...
       activeDocument.info.copyrightNotice = dlg.msgPnl.msgCpyVermerk.text;*/
       
       this.ena = true;
       this.parent.close(0);
   }
   
   // when CANCEL is clicked
   dlg.cancelBtn.onClick = function() {
       this.ena = false;
       this.parent.close(0);
       //ObjectCraft();
   }
   
   // show dialog window
   dlg.show();
}



////////////////////////////////////////////////////
// clean up a path name
//      pathStr            :   the path
////////////////////////////////////////////////////
function cleanPathStr(pathStr)
{
   var pth = pathStr;
   while (pth != pth.replace("//", "/")) {
       pth = pth.replace("//", "/");
   }
   return pth;
}



////////////////////////////////////////////////////
// close all open documents
//      save_options    :   file save options
////////////////////////////////////////////////////
function closeAllDocuments(save_options)
{
   if (save_options == null) {
       save_options = SaveOptions.PROMPTTOSAVECHANGES;
   }
   while (app.documents.length) {
       app.activeDocument.close(save_options);
   }
}



////////////////////////////////////////////////////
// export image in bitmap format
//      path            :   the path to the new file
//      filename    :   the new files name
////////////////////////////////////////////////////
function exportImageToBMP(path, filename)
{
   try
   {
       var pth = cleanPathStr(path+"/"+filename);
       imgFile = new File(pth);
       var options = new BMPSaveOptions();
       //options.quality = 100;
       options.depth = BMPDepthType.SIXTEEN;
       options.rleCompression = false;
       //options.alphaChannels = true;
       app.activeDocument.saveAs(imgFile, options, true);
   }
   catch (e)
   {   // display error
       alert("Error encountered when saving the image! \r\r" + e);
       return;     // quit
   }
}



////////////////////////////////////////////////////
// export image in PNG format (24-bit)
//      path            :   the path to the new file
//      filename    :   the new files name
////////////////////////////////////////////////////
function saveForWebPNG(path, filename)
{
   var opts, file, p;
   opts = new ExportOptionsSaveForWeb();
   opts.format = SaveDocumentType.PNG;
   opts.PNG8 = false;
   opts.quality = 100;
   if (filename.length > 27) {
       p = cleanPathStr(path+"/temp.png");
       file = new File(p);
       app.activeDocument.exportDocument(file, ExportType.SAVEFORWEB, opts);
       file.rename(filename + ".png");
   }
   else {
       p = cleanPathStr(path+"/"+filename+".png");
       file = new File(p);
       app.activeDocument.exportDocument(file, ExportType.SAVEFORWEB, opts);
   }
}



////////////////////////////////////////////////////
// transform - flip layer
//      type    :   0 = Horizontal, 1 = Vertical
////////////////////////////////////////////////////
function flipLayer(layer, type)
{
   var x_scl, y_scl;
   switch (type) {
       case 0:
           x_scl = -100;
           y_scl = 100;
           break;
       case 1:
           x_scl = 100;
           y_scl = -100;
           break;
   }
   layer.resize(new UnitValue(x_scl,'%'), new UnitValue(y_scl,'%'));
}



////////////////////////////////////////////////////
// transform - flip layer
//      lyr     :   a layer object
//      x       :   x position (pixels)
//      y       :   y position (pixels)
////////////////////////////////////////////////////
function positionLayer(lyr, x, y)
{
    // if can not move layer return
    if(lyr.iisBackgroundLayer || lyr.positionLocked) return
    // get the layer bounds
    var layerBounds = lyr.bounds;
    // get top left position
    var layerX = layerBounds[0].value;
    var layerY = layerBounds[1].value;
    // the difference between where layer needs to be and is now
    var deltaX = x-layerX;
    var deltaY = y-layerY;
    // move the layer into position
    lyr.translate(deltaX, deltaY);
}



////////////////////////////////////////////////////
// calculate spritesheet frame offsets
//      fh    :     file handle
//      cfg   :     the config object
//      o     :     the offset object (p: x,y)
////////////////////////////////////////////////////
function calculateFrameOffsets(fh, cfg, o)
{
   if (!(o instanceof Object)) {
       var o = {};
       o.x = 0;
       o.y = 0;
   }
   
   // if the animations have a solid background,
   // no offset is needed
   if (cfg.spritesheet.solidBackground === true) {
       o.x = 0;
       o.y = 0;
   } else {
   // if the animations have a transparent background,
   // we must scan every pixel of each frame to determine the pixel offset
       var sampler = fh.colorSamplers.add([0, 0]);
       
       framePixelCheck_X:
       for (var px = 0; px < fh.width; px ++) {
           for (var py = 0; py < fh.height; py++) {
               
               sampler.move([UnitValue(px, "px"), UnitValue(py, "px")]);
               var pColor = undefined;
               
               // try to grab pixel data for   [px,py]
               try {
                   pColor = sampler.color;
               // if there is no pixel at  [px,py] , exception will be thrown
               } catch(err) { }
               
               // if there is a pixel at [px,py]
               if (pColor != undefined) {
                   // a pixel exists
                   o.x = px;
                   break framePixelCheck_X;
               } else { // no pixel at [px,py]
                   continue;
               }
               
           }
       }

       framePixelCheck_Y:
       for (var py = 0; py < fh.height; py++) {
           for (var px = 0; px < fh.width; px ++) {
               
               sampler.move([UnitValue(px, "px"), UnitValue(py, "px")]);
               var pColor = undefined;
               
               // try to grab pixel data for   [px,py]
               try {
                   pColor = sampler.color;
               // if there is no pixel at  [px,py] , exception will be thrown
               } catch(err) { }
               
               // if there is a pixel at [px,py]
               if (pColor != undefined) {
                   // a pixel exists
                   o.y = py;
                   break framePixelCheck_Y;
               } else { // no pixel at [px,py]
                   continue;
               }
               
           }
       }
   
   }

}



////////////////////////////////////////////////////
// main method
////////////////////////////////////////////////////
function main()
{
   // initialize config
   var config = new configObj();
   
   // bring up starting dialog
   dialogStart(config);
   
   
   
   app.displayDialogs = DialogModes.NO;
   closeAllDocuments();
   
   // open only relevant animation files
   var doc;
   for (var idx in config.current.validDocs) {
       doc = File(config.current.validDocs[idx]);
       if (doc.exists) {
           var f = open(doc);
       } else {
           delete config.document.suffix[idx];
       }
   }
   
   // save all files as animated gif's
   var animFiles = [];
   for (var i = 0; i < app.documents.length; i++) {
       // keep track of file properties
       app.activeDocument = app.documents[i];
       var fobj = {};
       fobj.filename = app.documents[i].name.replace(".psd", "");
       fobj.file_ext = ".gif";
       fobj.path = config.current.tempPath+"/"+fobj.filename+fobj.file_ext;
       animFiles.push(fobj);
       
       // delete the file if it already exists
       var aFile = File(fobj.path);
       aFile.remove();
       
       // save for web options
       var options = new ExportOptionsSaveForWeb();
       options.ditherAmount = 0;
       options.dither = Dither.NOISE;
       options.palette = Palette.LOCALADAPTIVE;
       options.format = SaveDocumentType.COMPUSERVEGIF;
       /*options.format = SaveDocumentType.COMPUSERVEGIF;
       options.colors = 256;
       options.dither = Dither.NONE;
       options.ditherAmount = 100;
       options.palette = Palette.LOCALSELECTIVE;
       options.interlaced = true;
       options.lossy = 0;*/

       // export the image
       app.activeDocument.exportDocument(aFile, ExportType.SAVEFORWEB, options);
   }
   
   closeAllDocuments(SaveOptions.DONOTSAVECHANGES);
   
   // open only relevant animation files (open saved animated gifs)
   var animFrameFiles = [];
   for (var i = 0; i < animFiles.length; i++) {
       // for each animation file
       var cur_file = open(File(animFiles[i].path));
       app.activeDocument = cur_file;
       
       // hide all layers first
       var layers = app.activeDocument.layers;
       for (var j = 0; j < layers.length; j++) {
           try {
               layers[j].visible = false;
           } catch(err) { }
       }
       // export each layer as a seperate image
       for (var j = layers.length-1; j >= 0; j--) {
           var flipAndRepeat = false;
           app.activeDocument.activeLayer = layers[j];
           try {
               app.activeDocument.activeLayer.visible = true;
               
               // face direction
               var basefn = animFiles[i].filename.substring(0, animFiles[i].filename.indexOf(config.document.suffix["_"]));
               var face_dir = animFiles[i].filename.substring(animFiles[i].filename.indexOf(config.document.suffix["_"])+1);
               var aframe = (layers.length-1) - j;
               
               // if the animation file is Left/Right, save Left facing frame first
               if (face_dir == config.document.suffix["LR"]) {
                   flipAndRepeat = true;
                   face_dir = config.document.suffix["L"];
               }
               
               // save frame as PNG
               var export_fname = basefn + config.document.suffix["_"] + face_dir + aframe;
               saveForWebPNG(config.current.tempPath, export_fname);
               
               // keep track of saved images
               if (!(animFrameFiles[face_dir] instanceof Array)) {
                   animFrameFiles[face_dir] = [];
               }
               animFrameFiles[face_dir][aframe] = config.current.tempPath+"/"+export_fname+".png";
               
               // if the animation file is Left/Right, save Right facing frame
               if (flipAndRepeat === true) {
                   flipLayer(app.activeDocument.activeLayer, 0);
                   var r_fname = basefn + config.document.suffix["_"] + config.document.suffix["R"] + aframe;
                   saveForWebPNG(config.current.tempPath, r_fname);
                   if (!(animFrameFiles[config.document.suffix["R"]] instanceof Array)) {
                       animFrameFiles[config.document.suffix["R"]] = [];
                   }
                   animFrameFiles[config.document.suffix["R"]][aframe] = config.current.tempPath+"/"+r_fname+".png";
               }
               
               app.activeDocument.activeLayer.visible = false;
           } catch(err) { }
       }
       
       cur_file.close(SaveOptions.DONOTSAVECHANGES);
       
       // export visible layers to seperate files
       //$.evalFile("C:/Program Files/Adobe/Adobe Photoshop CS5 (64 Bit)/Presets/Scripts/Export Layers To Files.jsx");
   }
   
   // create a new document and insert the animation frames
   // create document
   var charsetWidth = config.spritesheet.cols * config.spritesheet.colWidth;
   var charsetHeight = config.spritesheet.rows * config.spritesheet.rowHeight;
   var charsetRef = app.documents.add(charsetWidth, charsetHeight, 300, "newCharset", NewDocumentMode.RGB, DocumentFill.TRANSPARENT);
   
   // loop through animation frames
   for (var i in config.spritesheet.animOrder) {
       var wDirFrames = animFrameFiles[config.spritesheet.animOrder[i]];
       for (var j in wDirFrames) {
           // open frame
           var aFile = open(File(wDirFrames[j]));
           // duplicate layer into the new document
           aFile.layers[0].duplicate(charsetRef);
           
           // calculate frame offsets
           var offset = {};
           calculateFrameOffsets(aFile, config, offset);
           
           // position the new layer properly
           var new_x = j * config.spritesheet.colWidth;
           var new_y = i * config.spritesheet.rowHeight;
           //offset.x = 0;//eval(config.spritesheet.xOffsetFormula.replace("{WIDTH}", aFile.width));
           //offset.y = 0;//eval(config.spritesheet.yOffsetFormula.replace("{HEIGHT}", aFile.height));
           app.activeDocument = charsetRef;
           positionLayer(charsetRef.layers[0], new_x+offset.x, new_y+offset.y);
           
           // close frame
           aFile.close(SaveOptions.DONOTSAVECHANGES);
       }
   }
   
   // save new charset as PNG
   saveForWebPNG(config.current.savePath, config.current.docName);
   
   // cleanup - remove temp files
   for (var i = 0; i < animFiles.length; i++) {
       var f = File(animFiles[i].path);
       f.remove();
   }
   for (var i in config.spritesheet.animOrder) {
       for (var j in animFrameFiles[config.spritesheet.animOrder[i]]) {
           var f = File(animFrameFiles[config.spritesheet.animOrder[i]][j]);
           f.remove();
       }
   }
   
   
   
   // end main method
}










// execute script
main();


To install, place the code in a file with the extension .jsx in your Photoshop scripts directory.
The default should be something like: C:\Program Files\Adobe\Adobe Photoshop CS5\Presets\Scripts



When I do graphic design, I like working at the pixel level, especially when I'm doing custom charsets.  I've always wanted a way to easily make changes at the pixel level to my charsets if something doesn't look right, while keeping each frame separate with layers (for different elements of the character, like jacket, hair, eyes, etc), AND being able to "play" the animation and watch it.  So I started using Photoshop animations.

I have separate files for each walking direction, and I can zoom in as close as I want make sure the animation looks perfect.  I also have each frame broken down into separate components.  Excuse the watermarks on the pics, I don't want anybody heisting this character just yet.



Here are the files I have for this character.  They correspond to the Down, Left/Right and Up walking animations:



Basically the naming convention is as follows: CHARNAME-DIRECTION_LETTER.psd
CHARNAME can be anything
DIRECTION_LETTER can be U, D, L, R, or LR.  If the L and R animations are supposed to be very different, have them in separate files.  Otherwise, use LR as a suffix and the R animation will be assumed to be a mirror image of L.

Keep in mind this is just my naming convention, and the default for the script.  You can change the highlighted part of the script if you want:





So what you do, is have all your properly named PSD files in a directory, and then open one of them and run the script.  It will show up in a separate category as "Create Spritesheet from Charset animation" under File -> Scripts in PS.



This window will appear!  It will show you the other animation files it detected for the current one you have open.  You can change the width/height of a cell if your charset uses a non-standard width/height.

Pay attention to the checkbox at the top.  If your animation has a transparent background, the script will take a couple minutes to run.  This is because photoshop has no way of copying empty space from one document to another, so the script must scan each frame of the image to determine how many pixels the sprite must be offset in its cell.  Unfortunately I don't think there's a way around this.

However if your animation has a solid color background, the script will finish in seconds because every frame is the same width and height.

After your done setting the options click Begin!  After some seconds/minutes, the compiled spritesheet will appear!
Ignore the "X" frames, those are not completed, my animation file contains those exact frames.



It will also be saved as a 24-bit PNG in the same directory as the other animation files by default.



You can change the save directory in the configuration by changing the value of this.current.savePath.  You can put your projects charset directory there and the compiled spritesheet will be automatically exported and ready to use in RMXP.  Just make sure Photoshop can write to that directory.



Anyway I've put a decent amount of time into this script, so hopefully other Photoshop CS users will find this useful.  Enjoy!
20
Resources / Re: Actorsprite Maker
March 07, 2012, 09:42:15 pm
This looks awesome!  Can't wait to see a release of this!