Map Changing Tutorial by NeoLogiX

From Spherical
Revision as of 18:38, 8 March 2014 by Apollolux (talk | contribs) (Simple Method: "end here" note)
Jump to: navigation, search

The most common activity in an RPG is walking on a map. A map usually contains places to visit so the game needs to be able to "warp" the player from one map (usually an overworld map) to another (usually a town or dungeon), or vice versa. This tutorial offers two practical, usable methods to scripting a change of map.

Simple Method

var mapfile = "overworld.rmp";
ChangeMap(mapfile);

Sphere has a built-in function ChangeMap that handles all the behind-the-scenes work of switching from one map to another. It requires the map engine to be running, otherwise Sphere will abort with an error telling you that the map engine isn't running. If you don't care about any special visual effects taking place during a map change, all you need to do is call ChangeMap with the file name of the new map.

Triggering

The most common way to activate a change-of-map within a Sphere map is to put a Trigger entity on the same layer as the expected input person and add the map change code to it. In actuality, as long as the map engine is running ChangeMap can be called at any time.


If you don't need anything fancier than this you can simply end here and use plain ChangeMap whenever you need to warp.

Advanced Method

This tutorial exists because Sphere users often want to see visual effects during a map change. The following is sample code for a transition manager, sectioned by purpose.

Easing

Robert Penner presented "a collection of swappable functions that add flavor to motion." He called them "easing functions" because they "ease" an animation. This is the essence of tweening and can be a very powerful tool for animation.

For the sake of simplicity in this tutorial, easing functions take a value from 0.0 to 1.0, representing the percentage of animation completed, and will return a value based on that value's place on a given curve.

Linear Ease

A linear ease is the easing function version of normal linear interpolation. Given a time value from 0.0 to 1.0, it will simply return that value.

function linear(t){return t*1.0;}

Other easing functions can be written to create more natural-looking animations or to use with some less common screen transitions. Visit the links at the bottom for more info.

Effect

A screen transition requires an effect to use. For this tutorial, we will take one second (1000 milliseconds) to fade between two maps; the old map fades into the new one.

For the sake of simplicity in this tutorial, effects functions will only take the before-image, the after-image, the percentage of time completed, and an easing function to transform the time percentage into a percentage to multiply the old image's alpha value.

function fade(a, b, t, ease) {
	var alpha = (ease(1.0-t)*255);
	b.blit(0,0);
	a.blitMask(0,0, CreateColor(255,255,255, alpha|0));
}


The above function simply fades the old image on top of the new image; setting t to 1.0 (i.e. the end of the animation) will render the old image completely transparent, showing the new image unobstructed.

Transition Manager

For convenience, this tutorial demonstrates a simple a transition manager that will initialize a transition, perform the transition over a given amount of time, then prepare the new image for use once the transition completes. Transition takes the before-image, the after-image, the effect function to use, the easing function to use to smooth the animation, the amount of time (in milliseconds) to perform the transition, and an extra object to hold data specific to the given instance of the transition.

function Transition(before, after, effect, easing, ms, data) {
	if ('init' in effect) effect.init(data);
	var start = GetTime(), end = start+ms, time;
	while ((time=GetTime())<end) {
		effect(before, after, (time-start)/ms, easing);
		FlipScreen();
	}
	after.blit(0,0);
}

As you'll see at the beginning of the function, Transition will initialize the given effect with the extra data; the fade effect function above, for example, can be modified to take a color for tinting the old image:

/**** add the following AFTER defining the fade function ****/
fade.prototype.init = function(data) {
	this.color = (data && data.color) || CreateColor(255,255,255,255);
};

...but for it to take effect, the above fade function has to be modified to actually use it:

/**** modified fade function; keep this before defining its init() method ****/
function fade(a, b, t, ease) {
	var h = 'color' in this?1:0;
	var c = CreateColor(
		h?this.color.red:255,
		h?this.color.green:255,
		h?this.color.blue:255,
		h?this.color.alpha:255
	);
	c.alpha = (ease(1.0-t)*c.alpha)|0;
	b.blit(0,0);
	a.blitMask(0,0, c);
}

Triggering

For this tutorial, a map change with screen transition follows the same conditions as a regular map change: it can be activated at any time as long as the map engine is running and the most common method to activate it is to put the required code in a Trigger entity on the map. Below is sample code that can be used for changing maps with the fade effect (the modified one that allows adding a custom tint) and linear easing we defined earlier:

var SW = GetScreenWidth(), SH = GetScreenHeight();
var before = GrabImage(0,0, SW,SH), ms = 1000;
ChangeMap("newmap.rmp");
RenderMap();
var after = GrabImage(0,0, SW,SH);
Transition(before, after, fade, linear, ms, {'color':CreateColor(255,255,255,255)});

Notes

Keep in mind the transition manager and the associated code defined in this tutorial is extremely simplistic. The concept of initializing a given effect is an example of possible additions to its functionality and for more advanced effects like "mosaic" or "piecemeal blackout" this initialization step is essential. The sample fade transition also uses only two images and fixes the coordinates for them at (0,0); a possible edit that can be made would allow use of different coordinates and/or more than just two images.

Another possible modification that can be made is separating the transition's rendering and updating and attaching them to a render script and an update script, respectively, instead of running the whole transition as a blocking function. This is an advanced exercise that should be performed once you feel more comfortable with render and update scripting.

See also

In closing

If there are any questions, you can ask at the forums or the Talk. Enjoy transitioning your maps! --Apollolux (talk) 06:13, 8 March 2014 (UTC)