Skip to main content

News

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.

Topics - Rhuan

1
Articles / WIP: Sphere v2 Tutorial
Still a work in progress but I've been a writing a combined tutorial for modern Javascript and Sphere v2.

Would be interested in any thoughts, latest version can be seen here - note the documents aren't linked together they're just all in the same folder of this gitbhub repo - they're formatted with markdown so should be easy to read directly on GitHub:

https://github.com/rhuanjl/SphereLibs/tree/gettingStarted/Sphere%20v2%20Tutorial
2
Libraries / MapEngine for Sphere v2
This is still an alpha version I suppose but really needs some usage so I can know what else to do with it.

Feels good enough to share as a release of sorts now rather than just a project.

https://github.com/rhuanjl/SphereLibs

See the "Map Engine tutorial.md" file for a fairly brief getting started tutorial - it's a lot of files to put in your project but should hopefully be simple to use once in place.

Any questions let me know.

Note: this requires miniSphere version 5.0 (or later) it will not run with earlier versions and certainly won't run with Sphere 1.5.
3
Resources / JS performance profiler - for use in sphere
The below code creates a timer object that you can use to profile the speed of various functions in your project/game. It is intended for people who either:
a) have a slow running large/complex game system and wish to find the part causing the slow down OR
b) are obsessive micro-optimisers like me

It will output the results in a csv file that you can open with excel or openoffice to do some stats/analysis with.

(I'm afraid it uses v1 file handling as v2 file writing still does not seem to work on Mac)

Usage:
1. Create a timer object - needs to be global or at least available in the whole of the scope you're going to use it in:
var time_logger = new Timer("log");
If you have multiple separate scopes and no global available you could make one in each scope with different names.

2. At the start of each portion of code you wish to time put in a record call:
time_logger.record("Update function", false);//the false parameter is optional
NOTE: the string must not contain a comma

3.The Timer will time the section until the next record call, you can end a section either by beginning another section:
time_logger.record("Render function", false);
OR by calling record with the second parameter set to true
time_logger.record("this string is ignored", true);
When true is set no new section is begun but the previous section is ended - this is so when one seciton follows another you only need one function call whereas if there's a big gap you can end the section off without creating a log entry for the gap that doesn't interest you.

4. Call the end function before you exit
time_logger.end();//this writes everything out to a file
Output is not done to a file during execution as this can significantly impact performance and hence skew the results.

Code: [Select]
function Timer(file_name)
{
  this.output_file = OpenRawFile(file_name + ".csv", true);
  this.output_file.write(CreateByteArrayFromString("Time,Event,TimeTaken\n"));
  this.start = new Date().getTime();
  this.records = [];
  this.open = false;
}

Timer.prototype.record = function(status, end)
{
  var time = new Date().getTime() - this.start;
  var length = this.records.length;
  if(this.open === true)
  {
    this.records[length -1].time_taken = time - this.records[length -1].time;
    this.open = false;
  }
  if(end !== true)
  {
    this.records[length] = new Record(time, status);
    this.open = true;
  }
}


Timer.prototype.end = function()
{
  var time = new Date().getTime() - this.start;
  this.record("",true);
  var string = "";
  for(var i = 0; i < this.records.length; ++i)
  {
    string = string + this.records[i].time +"," +this.records[i].status +","+this.records[i].time_taken +"\n";
  }
  string = string +time + ", Total time running, "+ time +"\n";
  this.output_file.write(CreateByteArrayFromString(string));
  this.output_file.close();
}

function Record(time, status)
{
  this.time = time;
  this.status = status;
  this.time_taken = 0;
}
4
Site Comments / The Like Button
I don't seem to have a Like button - I'm on the default theme, is something wrong with my account? Or am I just being stupid?
5
Sphere General / Promoting Sphere?
So... We all know that Sphere is a great game development tool.

And with forthcoming changes it's going to get even better:
- Fat Cerberus is working on high speed JS with chakracore
-> once CC works there's a possibility of full type script support via Cell with CC which could be attractive to some people
- there's already basic 3d support (though i think it may need some fine tuning)
- there are the v2 map/sprite engines I'm working on (including tiled support)
- with a decent tutorial for it the dataReader script from Fat Cerberus can load any basically data type you care to design
- there's the possibility of a web based implementation, Oozaru (though this is a little way off at the moment)
- there's the possibility of Android support from Eggbert.

What does it not have?
- There's no good 0 to everything tutorial or outline anywhere.
- There are very few great demos of what it can do, probably Trial and Error 4 beta and Aquatis Journey to Kiltos are the best we've got
- It doesn't have many active users talking about what they're using it for

How do we fix this?
1. I think the first few things on the improvements list should get finished before we do anything else as they could have some significant impacts on the best way to use Sphere
2. I think we want a 0 to working game tutorial using v2, possibly more than one such to cover a few different game types
3. Accompanying tech demos to go with the above
4. Consider where to share such materials (rpgmaker.net is one obvious place) but is there anywhere else that would be good?

Thoughts? Opinions? Volunteers?
6
Programming / Javascript array size and performance
Every Javascript tutorial on arrays says make your arrays with var array_name = []; unless you have all the values at the start and can do it explicitly.

Additionally if you read up on fast loop performance you're told to do:
Code: [Select]
var i = number_of_interations;
while(--i)
{
  //do stuff
}

Put this together and the way to fill a large array is apparently to do:
Code: [Select]
var i = planned_array_size;
var array_name = [];
while (--i)
{
  array_name[i] = insert_value_or_function_call_here;
}

I've spent a bit of time recently looking at the comparative Javascript performance of JavascriptCore (Safari), SpiderMonkey (Firefox) and V8 (Chrome).

One thing that stood out to me was a test where SpiderMonkey and V8 destroyed JavascriptCore by a factor of almost 100, the test was meant to be about Math.trunc performance vs bitwise operators but Safari just performed like a dog in all cases. The test's preparation code was using the above syntax to fill a loop with random numbers then in the test was looping through the array flooring them and adding them up.

I found that if I changed the preparation code to loop forwards suddenly safari scored highest, changing it to set the array size with the array constructor advance made it perform even better. Notably this changes improved performance in all browsers though Safari in particular went to the top.

Conclusions:
Primary: you don't want to dynamically resize arrays backwards it kills performance; use the Array Constructor to size it
Secondary: Safari's JS engine is crazy fast when it's not dynamically resizing (as in it curb stomps V8 in a lot of tests I've been doing)

Try running this in a couple of browsers then consider bringing back that array constructor :):
https://jsperf.com/array-creations/1

(I note that those tests only show creation speeds, it was access speeds that pointed me to the issue, for those try out these two test pages and compare - I note the differences here are smaller except in Safari:
https://jsperf.com/or-vs-floor/43
https://jsperf.com/trun-vs-or
7
So, picking up from some brief discussion in the miniSphere topic I'm planning on building Javascript based replacements for sphere's map engine and spriteset handling to work with the Sphere v2 api.

This is at an early stage (I've not written any code yet) but I've previously written a close to fully functionally engine for sphere v1 which I intend to use as a model as it supported most of the features we'll want and had a logical structure which should map to Sphere v2 - though there will be several key changes and it needs to be more flexible and work for other people not just me - I'm also hoping that using Galileo properly will enable the whole system to run a lot faster.

My hope is that this can become part of the standard minisphere distribution if I get it right...

Anyway that said I've written out my current design thoughts below, I'd appreciate comments, feedback and suggestions:

Planned features

  • Sprite engine allowing for extensive control of sprites
    • Queuing commands

    • Setting destinations to have the engine generate a route

    • Function for adding entities

    • Most controls to be done by setting values

    • Collision detection

    • Each entity will be a shape or model that has a sprite sheet as its texture/atlas, uniforms will be varied to enable the shader to update the U/V values as needed to show the correct frames

    • The code will support zooming in and out for the whole screen AND will also enable individual sprites to be drawn scaled

    • Update function that can be added to the Dispatch queue that updates the position/state of all entities. OR can be called in a user's own loop

    • Render function that can be added to the Dispatch queue to draw the sprites OR can be called in a users own loop

    • Can draw to the screen or to a specified surface

    • Functions to work with the Map Engine when it is in use AND alone when the Map Engine is not in use

  • Map engine allowing for extensive control of maps :P
    • Any number of layers

    • Drawing maps transformed if needed (ideally will add deformations as well as simple transformations - need Matrix axis and ideally Z-axis drawing enabled)

    • Applying masks of various kinds

    • Zooming in and out (feature will sync with sprites)

    • Can draw to the screen or to a specified surface

    • Collision detection

    • Each layer to be represented as a shape or model the size of the provided drawing space for the map (by default the game's resolution) that has the full map as its texture/atlas, uniforms will be varied to enable the shader to update the U/V values as needed to show the correct portion of the map.

    • Update function that can be added to the Dispatch queue that updates the position/state of all entities. OR can be called in a user's own loop

    • Render function(s) that can be added to the Dispatch queue to draw the sprites OR can be called in a user's own loop (probably have one function to render content under the sprites and another to render content over them) OR could have one function that calls the sprite renderer in the middle.




Choices to make:
  • Tile or Pixel or Shape based processing (collisions etc)
    Preference is tile for simplicity + speed of processing

  • File Formats:
    • Maps, options:
      • .rmp -> consistent with sphere v1 BUT contains some unneeded detritus  AND there's no modern editor for it

      • JSON description +one or more png tileset files -> can output with Tiled BUT human readable which some may not appreciate AND 2 files not one.

      • Custom of some kind, but include functions that can covert both of the above? (current preference)

    • Sprites, options:
      • .rss -> consistent with sphere v1 BUT pretty nasty to work with within the sphere v2 api, and generally quite an inefficient format (each image is stored separately as an array of RGBA values (each value being itself 4 bytes)

      • .png -> consistent with rpgmaker, easy to make/edit BUT how do you establish what size each frame is and other such things -> not flexible enough.

      • Json description containing directions/sizes etc + a png file with the images -> png files are easy to make, JSON is hand writeable + could have a script to make it if needed -> Looks good except for needing two files not one.

      • Custom format with a creation function that takes any of the above 3 as inputs -> current preference

  • How many directions to support for movement, 4? 8? Variable?

  • What transformations to allow (low priority can add more at the end)

  • Should sprites be able to be drawn on multiple layers with a property specifying which one to draw on OR should it be one or two only?

  • Should each map have one collision map or multiple (e.g. different collisions on different layers - links to point above)?

  • Should the code be in .mjs or .js files...



Other thought patterns
  • Can I track locations of entities with their transformation matrices? or do I need to track separately, I think I'll need separate tracking, even with component access if I allow zooming in and out and other transformations will be too messy to read out of the matrix.

  • Persistent transformation matrices OR just have one that gets updated for every item drawn? Probably the latter if using separate tracking, as can't see a purpose in retaining the matrices.
8
So... Working on a SRPG battle system - and I keep finding more things I need temporary variables for, and it just feels like I've made some kind of monster, I've got something like:

20 variables holding specific values
3 menu objects
a map object (containing 2 different obstruction arrays)
an array of people objects (for drawing)
an array of characters (with stats etc)
an index array into both of the above arrays
an object holding the output of a path finding function

And the whole thing just looks like this: https://youtu.be/Bp4tGTNNi1I?t=1m10s

Is there a method anyone can suggest to avoid this?
9
Resources / Function to parse a CSV file
I want to be able to use spreadsheets as data files in my current project - and obviously want Sphere to be able to read them, the easiest method seemed to be to save as CSV and then parse it, so I wrote a simple CSV parser (only tested with UTF-8 character encoding may need tweaking for different formats), anyway thought I'd share it in case any else wants this functionality.

Notes:
- sphere version 1 (sorry Fat Cerberus)
- has to use a length variable for the current field byte array (out_Rdata) as miniSphere doesn't let you dynamically resize byte arrays
- only supports 200 bytes per field - though you can change this by increasing the number on line 5
- returns the data as a 2D array where output[1][2] would be the value from the 2nd row and 3rd column. output[0][0] = value from 1st row and 1st column etc. It converts numbers into JS numbers and returns anything else as strings.

Code: [Select]
function parseCSV(input)
{
  var file = OpenRawFile(input);
  var in_data = file.read(file.getSize());
  var out_Rdata = CreateByteArray(200);
  var R_length = 0;
  var out_data  = [[]];
  var in_quotes = false;
  function convert_data(Rdata)
  {
    if(!(Rdata * 1))
    {
      out_data[out_data.length-1].push(Rdata);
    }
    else
    {
      out_data[out_data.length-1].push(Rdata*1);
    }
  }
  for(var i = 0; i<in_data.length; ++i)
  {
    if(in_quotes)
    {
      if(in_data[i] == 0x22)
      {
        in_quotes = false;
      }
      else
      {
        out_Rdata[R_length]=in_data[i];
        ++R_length;
      }
    }
    else
    {
      switch(in_data[i])
      {
        case(0x2C)://comma
        {
          if(R_length > 0)
          {
            convert_data(CreateStringFromByteArray(out_Rdata.slice(0,R_length)));
          }
          else
          {
            out_data[out_data.length-1].push("");
          }
          R_length =0;
          break;
        }
        case(0x22)://quotes
        {
          in_quotes = true;
          break;
        }
        case(0x0D)://Carriage Return -ignored as followed by LineFeed
        {
          break;
        }
        case(0x0A)://Line Feed - push the data and then move down a line
        {
          if(R_length > 0)
          {
            convert_data(CreateStringFromByteArray(out_Rdata.slice(0,R_length)));
          }
          else
          {
            out_data[out_data.length-1].push("");
          }
          R_length = 0;
          out_data.push([]);
          break;
        }
        default://anything else
        {
          out_Rdata[R_length]=in_data[i];
          ++R_length;
        }
      }
    }
  }
  if(out_Rdata.length > 0)//push the last piece of data as there's no terminator character
  {
    convert_data(CreateStringFromByteArray(out_Rdata.slice(0,R_length)));
  }
  else
  {
   out_data[out_data.length-1].push("");
  }
  return out_data;
 
}
10
A bit of JS I wrote as a workaround as miniSphere has no function to save a spriteset thought I'd share it in case anyone else needs to edit and save spritesets with JS and wants to work in miniSphere. I haven't made a spriteset creation function as you can just have a template spriteset you open to start with. Note this is kinda slow for large spritesets (particularly the image saving) but I couldn't think of another way to do it.

Code: [Select]
function save_sprite(sprite, filename)
{
  var file = OpenRawFile(filename,true);
  //header data - commented where not self explanatory
  file.write(CreateByteArrayFromString(".rss"));//file signiture
  Write_16Word(3, file);//rss version number - always 3
  Write_16Word(sprite.images.length, file);
  Write_16Word(sprite.images[0].width, file);
  Write_16Word(sprite.images[0].height, file);
  Write_16Word(sprite.directions.length, file);
  Write_16Word(sprite.base.x1, file);
  Write_16Word(sprite.base.y1, file);
  Write_16Word(sprite.base.x2, file);
  Write_16Word(sprite.base.y2, file);
  file.write(CreateByteArray(106));//blank space needed by format
  /*this next bit is horrid (it works but it's super slow) the format
  requires 4 bytes per colur in rgba order not aware of any other way
  to do it with sphere's available functions:( */
  var temp_s;
  var col;
  var temp_c = CreateByteArray(1);
  for(var i = 0,x=0,y=0; i < sprite.images.length; ++ i)
  {
    temp_s = sprite.images[i].createSurface();
    for(y=0;y<sprite.images[0].height;++y)
    {
      for(x=0;x<sprite.images[0].width;++x)
      {
         col = temp_s.getPixel(x,y);
         temp_c[0] = col.red & 0xff;
         file.write(temp_c);
         temp_c[0] = col.green & 0xff;
         file.write(temp_c);
         temp_c[0] = col.blue & 0xff;
         file.write(temp_c);
         temp_c[0] = col.alpha & 0xff;
         file.write(temp_c);
      }
    }
  }
  //Direction data - this is easier
  //the CreateByteArray calls are for padding the format needs
  for(i = 0; i<sprite.directions.length; ++ i)
  {
    Write_16Word(sprite.directions[i].frames.length,file);
    file.write(CreateByteArray(6));
    Write_16Word(CreateByteArrayFromString(sprite.directions[i].name).length,file);
    file.write(CreateByteArrayFromString(sprite.directions[i].name));
    for(x=0;x<sprite.directions[i].frames.length;++x)
    {
      Write_16Word(sprite.directions[i].frames[x].index,file);
      Write_16Word(sprite.directions[i].frames[x].delay,file);
      file.write(CreateByteArray(4));
    }
  }
  file.close();
}

function Write_16Word(word, file)
{
  var array_of_integer      = new Array();
  array_of_integer[0]       = (word & 0xff00) >> 8;
  array_of_integer[1]       = (word & 0x00ff);
  var byte_array_of_integer = CreateByteArray(2);
  byte_array_of_integer[0]  = array_of_integer[1];
  byte_array_of_integer[1]  = array_of_integer[0];
  file.write(byte_array_of_integer);
}
11
EDIT: I just tested this again and both options now work - so either I changed it whilst pasting it to here and back or the fact that miniSphere now handles transparencies in cloned surfaces correctly has fixed it.


I can't figure this one out, as far as I can see these two pieces of code for reading a Tiled JSON map file and drawing each layer of the map onto the screen should be functionally identical and yet one worked perfectly (except for minisphere not handling the alpha channel) and the other worked for 1 layer and produced garbage for the rest - I used drawText to output the various increment/index values and coordinates and they were all correct all the way through in both cases can anyone see any reason why the first script would not work?

So this version did not work - it would do layer 0 correctly it would produce total garbage for any other layer, including if I adjusted K to start on a different layer.
Code: [Select]
function Load_map(name)
{
  var m_file = OpenRawFile("../maps/"+name+".json", false);
  var m_data = CreateStringFromByteArray(m_file.read(m_file.getSize()));
  var m_raw = JSON.parse(m_data);

  var t_surface = LoadSurface("../maps/"+m_raw.tilesets[0].image);
  var m_layers = [];
  var temp_x = 0;
  var temp_y = 0;
 
 
  for(var i = 0, j = 0, k = 0, l = 0; k < m_raw.layers.length; ++ k, l = 0)
  {
    m_layers[k] = CreateSurface(m_raw.layers[k].width * m_raw.tilesets[0].tilewidth, m_raw.layers[k].height * m_raw.tilesets[0].tileheight,CreateColor(0,0,0,0));
    for(i = 0; i < m_raw.layers[0].height; ++ i)
    {
      for(j = 0; j < m_raw.layers[0].width; ++ j, ++l)
      {
        temp_x = Math.max(0,(m_raw.layers[k].data[l] - 1) % m_raw.tilesets[0].columns);
        temp_y = Math.max(0,(m_raw.layers[k].data[l] - 1 - temp_x) / m_raw.tilesets[0].columns);
        m_layers[k].blitSurface(t_surface.cloneSection(temp_x * 32, temp_y * 32, 32, 32), j*32, i * 32);
      }
    }
    m_layers[k].blit(0,0);
    FlipScreen();
    GetKey();
  }
}


This version worked perfectly.
Code: [Select]
function Load_map(name)
{
  var m_file = OpenRawFile("../maps/"+name+".json", false);
  var m_data = CreateStringFromByteArray(m_file.read(m_file.getSize()));
  var m_raw = JSON.parse(m_data);
 
  var t_surface = LoadSurface("../maps/"+m_raw.tilesets[0].image);
  var m_layers = [];
  var temp_x = 0;
  var temp_y = 0;
  var t = 1;
  var tiles = [];
 
  tiles[0] = t_surface.cloneSection(0, 0, 32, 32);
  for(temp_y = 0; temp_y < 52; ++temp_y)
  {
    for(temp_x = 0; temp_x < 20; ++temp_x, ++t)
    {
      tiles[t] = t_surface.cloneSection(temp_x * 32, temp_y * 32, 32, 32); 
    }
  }
  for(var i = 0, j = 0, k = 0, l = 0; k < m_raw.layers.length; ++ k, l = 0)
  {
    m_layers[k] = CreateSurface(m_raw.layers[k].width * m_raw.tilesets[0].tilewidth, m_raw.layers[k].height * m_raw.tilesets[0].tileheight,CreateColor(0,0,0,0));
    for(i = 0; i < m_raw.layers[0].height; ++ i)
    {
      for(j = 0; j < m_raw.layers[0].width; ++ j, ++l)
      {
        m_layers[k].blitSurface(tiles[m_raw.layers[k].data[l]], j*32, i * 32);
      }
    }
    m_layers[k].blit(0,0);
    FlipScreen();
    GetKey();
  }
}
12
This is a question on how javascript (or at least sphere/minipshere's implementation of it) handles scope when it comes to arrays and objects; this may just be a problem arising from my scripting/programming knowledge being 90% self taught - I don't know how some of these things work.

Suppose I create an array inside a function:
Code: [Select]
function my_func()
{
  var my_array = [];
  ...
}

Now further suppose I wish to update that array inside another function:
Code: [Select]
function other_func()
{
  ...
  my_array[2] = 5;
  ...
}

Obviously this will not work as the array is not in scope, now let's suppose instead I pass the array as a parameter to other_func:
Code: [Select]
function my_func()
{
  var my_array = [];
  other_func(my_array);
  ...//do something else with my_array which relies on the 3rd value being 5
}

function other_func(param)
{
  param[2] = 5;
}

The second function will now not have a scope problem, but I think I'm right in saying that back in the first function will also have that value of 5 available to it, is this right? And is it appropriate to rely on this behaviour? I had instead been intending to have other_func return the array after updating it and have my_func overwrite the array with the returned one - is this functionally different?
Code: [Select]
function my_func()
{
  var my_array = [];
  my_array = other_func(my_array);
  ...//do something else with my_array which relies on the 3rd value being 5
}

function other_func(param)
{
  param[2] = 5;
  return param;
}


Is either of the above suggestions better than the other?
Is there any difference if the array is a property of a different object and you pass either the full object my_obj or just the array my_obj.my_array as a parameter?
Can getting this wrong create memory leaks?
13
I studied pathfinding maths about 7 or 8 years ago... I can't remember much of it at all, and I've never written any code involving pathfinding.

I'd like to write a pathfinding algorithm in sphere and don't know where to start - I've been looking around and tried reading up A* and JPS but most things I can find are pitched too high for me I could do with a simpler introduction.

Ultimately I'm looking to write something I can use in Sphere that will do the following thing:
Given:
- a weighted graph
- a starting point
- a maximum path cost
Calculate:
- all possible destinations
- the cheapest path to each destination

But for now please could I have some very introductory pointers
14
Script Support / Best way to script an SRPG
Not sure if this belongs in the script support board as I din't have a script to debug rather I have question on how people think I should start...

So I'm making the beginnings of an SRPG (think Fire Emblem).

I'm trying to think what the best way to script this would be I've got a lot of different ideas and don't want to rewrite it 10 times so was hoping for some extra opinions before I start, during a battle I'll need:
a) a map...
b) units placed around the map - note for various of the mechanics to work without excess complexity, units will be locked to a tiled grid and only be able to move in 4 directions
c) units moving when instructed - will only ever be one moving at a time
d) battle animations etc
e) a menu interface
f) a cursor you can move around the screen to select stuff
g) other logic (including pathfinding and AI and stuff but I'm happy with that side of things)

Decisions:
1. Should I try and do this in the sphere map engine or just do it in script with the map as an image
2. Should I tie the cursor to the mouse or have it movable with arrow keys or do a hybrid - perhaps moves with arrows but you seperately have a mouse pointer and if you click anywhere the cursor jumps there (if using the map engine and doing arrows should the cursor it be handled as a Person or drawn with a render script))


Pros of the map engine
1. I'd like to have animated tiles in the maps hence the map engine could make this easier
2. I'd like to have birds flying over and stuff which is easy to do in the map engine
3. The combatants will be doing normal walking/running animations which means if I use the map engine some of the logic is pre-built for me
4. I can use the inbuilt engine array of people to keep track of combatants
5. I can use the sphere map editor to set up animated tiles and stuff

Pros of not using the map engine
1. In some circumstances I'll need to draw stuff underneath combatants as well as ontop of them so I'll likely end up drawing at least some sprites of the combatants with a renderscript if I'm in the map engine
2. I'll probably want a button that skips animations - i.e. if someone is walking between two spots there will be a press button to make them jump there -> not sure how I'd do this if I've queued up movement commands within the map engine
3. If someone is walking between two spots and I want to draw something behind them the ME functionality breaks... I could handle this in a renderscript (draw their sprite on their ME X and Y coords whilst having the ME walk an invisable box between the coordinates or something)
4. I don't need to use spritesets and can use my own custom sprite format which may work better for what I'm doing)
15
Script Support / Drawing behind and in front...
Background - I've decided to start making an SRPG in Sphere (there is a 90+% chance I'll never finish it but hey...)

I'd like to have what I call a "spinning ring" as a selection cursor. This is an ellipse rolling up and down on its side - obviously I'd do this in some kind of render script but to show what this ought to look like here's some example code that simply draws the ring:
Code: (javascript) [Select]
function draw_ring(x, y, a, b)
{
  var ring_s = CreateSurface(2*a + 5,2*b + 5,transparent);
  for(var i = 0, t_x = 0, t_y = 0; i < 200; ++i)
  {
    t_x = a * Math.cos(i*Math.PI/100) + a;
    t_y = b * Math.sin(i*Math.PI/100) + b;
    ring_s.setPixel(t_x, t_y, red);
    ring_s.setPixel(t_x + 1, t_y, red);
    ring_s.setPixel(t_x, t_y + 1, red);
    ring_s.setPixel(t_x - 1, t_y, red);
    ring_s.setPixel(t_x, t_y -1, red);
  }
  var ring = ring_s.createImage();
  for(i = 0; i < 800; ++ i)
  {
   ring.transformBlit(x                                        ,//X1
                      y + b *         Math.cos(i * Math.PI/100),//Y1
                      x + a                                    ,//X2
                      y + b *         Math.sin(i * Math.PI/100),//Y2
                      x + a                                    ,//X3
                      y + b / 2 - b * Math.cos(i * Math.PI/100),//Y3
                      x                                        ,//X4
                      y + b / 2 - b * Math.sin(i * Math.PI/100)); //Y4
    FlipScreen();
  }
}


Note: I do not expect any part of the above to be final except perhaps the image creation at the top - but this does show what the spinning ring should look like. (note I probably should change this to use the ellipse functions rather than the loop of points though I couldn't immediately see how to do a multi-thickness outlined ellipse particularly not in minisphere which seems to have not implemented the ellipse functions)

Now the problem:
1. from looking at that code (or trying it out) you'll soon see that sometimes the front of the ring is at the top and sometimes the back is at the top.
2. Imagine you have a sprite and this ring is around their feet - you want the front to show in front of them and the back not to. The only ways I can currently think of to do this are to have two seperate images, one for the back half which is drawn before the sprite and one for the front half which is drawn after the sprite - this seems a tad painful

Does anyone have any suggestions of ways to make this better?