philematophobia. little tutorials.updated 10.21.01


7.16.01

this is a place where i hope to post a bunch of short tutorials on how to do some standard but sometimes confusing kis stuff. please feel free to copy the code straight off this page and paste it into your .cnf-- you don't even need to credit me!!

you can also post these on any page you like, but if you post them to a web page, please credit and link back to here!

thank you so much to calezane for providing many tutorials on this page!! check out calezane's links for more and many kinds of tutorials HERE.


1) color cycling

color cycling is a very useful thing!
It doesn't have to be used just for colors, it can be used to cycle through objects, too.
Most often it is used to change hairstyles but I also use it frequently for cycling through different colored versions of the same clothing item, so that you can store clothing more easily, and I'm sure you can think of many other ways to use it!

let's say you have three hairstyles.
they are hair1.cel, hair2.cel, and hair3.cel

in your FKiSS:

after the @initialize(), put this:

;@unmap("hair2.cel")
;@unmap("hair3.cel")

after the @begin(), put this:

;@press("hair1.cel") unmap("hair1.cel") map("hair2.cel")
;@press("hair2.cel") unmap("hair2.cel") map("hair3.cel")
;@press("hair3.cel") unmap("hair3.cel") map("hair1.cel")

now when you open the doll, only hair1.cel will be visible. then clicking on it will make hair2.cel appear. clicking on hair2.cel will make hair3.cel appear, and clicking on hair3.cel will go back to hair1.cel

you can add lots more .cels, as long as you remember to unmap all but the first one in the @initialize() sections, and remember to make pressing on the last one map the first one back again!

This was originally written for ashley of konon! Thanks ashley!!


2) randomized stuff

so, let's say you want a doll who had multiple facial features, or says different things, or anything that involves multiple possible reactions.

randomizing is tricky! here's how I do it.

let's say you want your doll to smile, frown, and yawn randomly, in addition to her normal expression.

make three .cels, "smile.cel," "frown.cel," and "yawn.cel"

in your FkiSS:

after the @initialize(), put this:

;@unmap("smile.cel")
;@unmap("frown.cel")
;@unmap("yawn.cel")
;@ timer(1,100)

after the @begin(), put this:

;@ alarm(1)
;@ unmap("smile.cel")
;@ unmap("frown.cel")
;@ unmap("yawn.cel")
;@ randomtimer(2,100,5000)
;@ randomtimer(3,100,5000)
;@ randomtimer(4,100,5000)

;@ alarm(2)
;@ timer(3,0)
;@ timer(4,0)
;@ map("smile.cel")
;@ randomtimer(1,100,5000)

;@ alarm(3)
;@ timer(2,0)
;@ timer(4,0)
;@ map("frown.cel")
;@ randomtimer(1,100,5000)

;@ alarm(4)
;@ timer(3,0)
;@ timer(2,0)
;@ map("yawn.cel")
;@ randomtimer(1,100,5000)

you can add as many other .cels to this as you want, but remember that the first @randomtimer() will start first and so if you add a lot, the later ones will hardly ever go off. you can solve this a couple ways.

some people make the lower number for the earlier timers a little higher, like @randomtimer( 2,150,5000) and then @randomtimer(5,200,5000).

I like to make new timers that are called after a .cel is mapped that only start timers for the other .cels & not the one that just mapped, like this

;@alarm(4)
;@timer(2,0)
;@timer(3,0)
;@ timer(5,0)
;@map ("yawn.cel")
;@ randomtimer(2,100,5000)
;@ randomtimer(3,100,5000)
;@ randomtimer(5,100,5000)

;@alarm(5)
;@timer(2,0)
;@timer(3,0)
;@ timer(4,0)
;@map ("grimace.cel")
;@ randomtimer(2,100,5000)
;@ randomtimer(3,100,5000)
;@ randomtimer(4,100,5000)

notice how in the one for @alarm(4), there is no @randomtimer(4,100,5000) and in the one for @alarm(5), there is no @randomtimer(5,100,5000). this keeps the same facial expression from happening twice in a row!


Three ways to stop a rapidly cycling alarm Cycling alarms - by CALEZANE thanks!!!!

try downloading this nifty sample set by calezane to help understand how it works!

 Cycling alarms - two or more alarms that go off one after the other
continually - are most often used to make a doll blink. Other uses
include: glinting jewellery, the smoke rising off a cigarette, or a
scarf flapping in the wind. The principle is the same in each case:
two or more cels mapped one after the other to suggest movement. For
something like the flapping scarf, the alarms that map and unmap the
cels would need to have 100-millisecond values to make the animation
look smooth enough. That kind of timer activity can tax a processor,
and you may actually hear the computer "grind" when such alarms
begin to cycle - and they don't automatically turn themselves off
if you switch to a page where the scarf isn't displayed. If you try
to turn them off with the usual "timer(A, 0) timer(B, 0)" construction,
you may find this doesn't work, because timer A managed to trigger
alarm B just before it was stopped, and timer B called alarm A
again just after it was stopped, and the scarf keeps flapping
without missing a beat.

There are three solutions to this, where a flapping scarf can be
changed to a hanging scarf (or a smoking cigarette to an
extinguished one, or glinting jewellery to dull jewellery, etc.).
The initial code would look like this:

;@initialize()
;@  unmap(#4)         ; unmaps all four scarf cels
;@  map("scarf1.cel") ; flapping scarf, cel 1
;@  timer(1,100)      ; starts the cycle

Then, instead of the usual code for permanently cycling alarms,
which might look like this:

; three cycling alarms to alternate between three "flapping scarf" cels
;@alarm(1)
;@  unmap(#4) map("scarf2.cel") timer(2,100)
;@alarm(2)
;@  unmap(#4) map("scarf3.cel") timer(3,100)
;@alarm(3)
;@  unmap(#4) map("scarf1.cel") timer(1,100)

you can use one of the following:


Solution 1: the FKiSS3 way:

This is super-simple. FKiSS3 uses variables, which are called A to Z
and all have a value of 0 when the set is opened. (There are also
variables A0 to Z0, A1 to Z1 etc. but all you need is one variable
which isn't used anywhere else.) In all three examples, you start and
stop the scarf flapping by clicking on it. In this example, I'm going
to use variable M. The code will look like this:

;@press(#4) ; press any cel of the scarf object
; Toggle value of M between 1 and 0
;@  ifgreaterthan(M,0) let(M,0) unmap(#4) map("scarf0.cel")
;@  else() let(M,1) timer(1,100)
;@  endif()

;@alarm(1)
;@  ifequal(M,1)
;@  unmap(#4) map("scarf2.cel") timer(2,100)
;@  endif()
;@alarm(2)
;@  ifequal(M,1)
;@  unmap(#4) map("scarf3.cel") timer(3,100)
;@  endif()
;@alarm(3)
;@  ifequal(M,1)
;@  unmap(#4) map("scarf1.cel") timer(1,100)
;@  endif()

The alarms will refuse to do anything unless M = 1.


Solution 2: the FKiSS2.1 way

This solution uses ifmapped() and ifnotmapped(), which set timers
depending on whether cels are mapped, and needs one extra alarm
to clean up after the timers have been stopped. The cycling alarms 
are brought to a halt by mapping the cel of the scarf hanging down, 
and the code goes like this:

;@press(#4) ; press any cel of the scarf object
; Toggle hanging scarf mapped/unmapped
;@  altmap("scarf0.cel")
;@  ifnotmapped("scarf0.cel",1,100)

;@alarm(1)
;@  unmap("scarf1.cel") map("scarf2.cel")
;@  ifmapped("scarf0.cel", 4, 1)
;@  ifnotmapped("scarf0.cel", 2, 200)
;@alarm(2)
;@  unmap("scarf2.cel") map("scarf3.cel")
;@  ifmapped("scarf0.cel", 4, 1)
;@  ifnotmapped("scarf0.cel", 3, 200)
;@alarm(3)
;@  unmap("scarf3.cel") map("scarf1.cel")
;@  ifmapped("scarf0.cel", 4, 1)
;@  ifnotmapped("scarf0.cel", 1, 200)
; Get rid of the moving scarf
;@alarm(4)
;@  unmap("scarf1.cel") unmap("scarf2.cel") unmap("scarf3.cel")

As you can see, the code now unmaps cels instead of the whole
object, because unmapping #4 would also unmap scarf0.cel, which
is needed to start and stop the cycle of flapping alarms.


Solution 3: the FKiSS way

This is the solution most likely to work on any viewer, and it
needs two extra alarms. The first extra alarm calls all the
animation alarms one after another, and then itself; the second
cleans up after the first. Because the real cycling alarm is now 
the first extra alarm - in this example, alarm 4 - the initial
code becomes:

;@initialize()
;@  unmap(#4)         ; unmaps all four scarf cels
;@  map("scarf1.cel") ; flapping scarf, cel 1
;@  timer(4,100)      ; starts the cycle

where alarm 4 replaces alarm 1. The code to start and stop
the animation is:

; stop the cycle 
; this has to be repeated for every "animation" cel
;@press("scarf1.cel")
;@  timer(4, 0) timer(5, 500)
;@press("scarf2.cel")
;@  timer(4, 0) timer(5, 500)
;@press("scarf3.cel")
;@  timer(4, 0) timer(5, 500)

(Note the 500-millisecond delay for alarm 5.)

; start the cycle
;@press("scarf0.cel")
;@  unmap(#4) map("scarf1.cel") timer(4, 1)

; keep scarf flapping
;@alarm(4)
;@  timer(1, 100) timer(2, 200) timer(3, 300) timer(4, 400)
;@alarm(1)
;@  unmap(#4) map("scarf2.cel")
;@alarm(2)
;@  unmap(#4) map("scarf3.cel")
;@alarm(3)
;@  unmap(#4) map("scarf1.cel")

; map hanging scarf
;@alarm(5)
;@  unmap(#4) map("scarf0.cel")

As there is only one cycling alarm, namely alarm 4 which
repeats itself, the cycle is easy to stop, and after that 
it's a matter of letting the alarms called by alarm 4 
execute themselves and then cleaning up with the second extra
alarm which is guaranteed to go off after alarms 1 to 4 have
finished. A refinement is to build the timer for alarm 5 into 
alarm 4 itself, so you don't have to remember to call alarm 5
under every event where alarm 4 is set to 0:

;@alarm(4)
;@  timer(1, 100) timer(2, 200) timer(3, 300) timer(4, 400) timer(5, 500)

Since alarm 4 calls itself before alarm 5 can execute, alarm
5 can't be carried out until alarm 4 is stopped with "timer(4, 0)".

BEWARE! There is one viewer (WKiSS 0.68) which won't allow
timers to be set to 0. They have to be set to their highest
value, 32767, the idea being that this is so high that they 
won't go off.

colour cycling - refinements another tutorial by CALEZANE! THANKS!

try downloading this nifty sample set by calezane to help understand how it works!

This howto expands a bit on tea's colour-cycling tutorial. Her method can be used to cycle colour, shape (like raising and lowering a hood) or whatever you can think of, but I'm going to concentrate on the colour-changing function, and instead of a head with three hairstyles, I'm going to use a flower with six colours of petals. There are two basic cels, a stalk cel and a flowerhead cel; the flowerhead cel can be copied and filled in with different colours to make differently coloured petals.


refinement 1: using layer order

In tea's tutorial, only one of the cycling cels is mapped at a time. But for cels that exactly cover each other, only the topmost mapped cel will be visible anyway, so you can have them all mapped and "click away" each cel until you get to the bottom cel, and clicking that one remaps all the cels.

The object and cel declarations will look like this:

#1   	petals.cel	*0 :0		; red petals
#1      petpink.cel     *0 :0		; pink petals
#1      petorng.cel     *0 :0           ; orange petals
#1      petblue.cel     *0 :0           ; blue petals
#1      petyelw.cel     *0 :0           ; yellow petals
#1      petpurp.cel     *0 :0           ; purple petals
#1   	stalk.cel	*0 :0           ; flower stalk

And the code looks like this:

;@press("petals.cel")
;@   unmap("petals.cel")  ; exposes pink petals
;@press("petpink.cel")
;@   unmap("petpink.cel") ; exposes orange petals

(etc. - repeat for all but last cel)

;@press("petpurp.cel")    ; bottom-most petals
;@   map(#1)              ; a quick way to remap all the flowerheads

Note that object #1 includes all parts of the flower, so you can freely drag it around.


refinement 2: putting all cycling cels into one object

This makes for easy coding when you can't use layer order, and know that the object won't be moved around. The object declarations are:

#1.999	petals.cel	*0 :0		; red petals
#1.999	petpink.cel     *0 :0		; pink petals
#1.999	petorng.cel     *0 :0           ; orange petals
#1.999	petblue.cel     *0 :0           ; blue petals
#1.999	petyelw.cel     *0 :0           ; yellow petals
#1.999	petpurp.cel     *0 :0           ; purple petals
#2.999	stalk.cel	*0 :0           ; flower stalk

And the code goes:

;@press("petals.cel")
;@   unmap(#1) map("petpink.cel")
;@press("petpink.cel")
;@   unmap(#1) map("petorng.cel")

and so on, up to and including the purple petals.

Note that flowerheads and stalk are now two different objects. This flower has to be locked into place, or it and its petals will part company.


refinement 3: using the same cel with different palettes

This solution requires a basic knowledge of palettes. It uses the same cel six times with six different object numbers, which keeps down the size of the set but uses up much RAM, possibly making the set slow to load and play with. In the basic flower palette, colour number 5, which colours the petals, is red. Cels themselves are colourless, so if I make five more palettes in which colour 5 is respectively pink, orange, blue, yellow or purple, list these in the cnf header and define the objects as follows:

; **Palette files**
%flower.kcf
%pink.kcf
%orange.kcf
%blue.kcf
%yellow.kcf
%purple.kcf

[playfield size and other stuff]

#1.999	petals.cel	*0 :    2 	; red palette
#2.999	petals.cel	*1 :    2       ; pink palette
#3.999	petals.cel	*2 :    2       ; orange palette
#4.999	petals.cel	*3 :    2       ; blue palette
#5.999	petals.cel	*4 :    2       ; yellow palette
#6.999	petals.cel	*5 :    2       ; purple palette
#7.999	stalk.cel	*0 :    2       ;

then I can colour-cycle by alternating objects, like this:

;@press(#1)
;@   unmap(#1) map(#2)
;@press(#2)
;@   unmap(#2) map(#3)

and so on, up to:

;@press(#6)
;@   unmap(#6) map(#1)

Note that this flower, like the one before, has to be locked in place or its petals will go flying off in all directions.


refinement 4: using merged palettes

This solution assumes a more in-depth knowledge of palettes. It is possible to pack up to ten palettes into a palette file. Each of these ten can be made visible by activating its "palette group", but this will also activate that palette group for any other palette used. Anyway, suppose you have one merged palette. This is how you define the flower object:

#1   	petals.cel	*0 :0		;
#1   	stalk.cel	*0 :0           ;

This is a flower that can be dragged around without losing parts. The colour will change when the palette group does. This can't be done by clicking on the petals (unless you use FKiSS3, where you can have a variable to keep track of the palette group number) so it needs something like a button object to click:

#2   	cycle1.cel	*0 :0           ;
#2   	cycle2.cel	*0 :0           ;
#2   	cycle3.cel	*0 :0           ;
#2   	cycle4.cel	*0 :0           ;
#2   	cycle5.cel	*0 :0           ;
#2   	cycle6.cel	*0 :0           ;

;@press("cycle1.cel")
;@     unmap("cycle1.cel") changecol(1)
;@press("cycle2.cel")
;@     unmap("cycle2.cel") changecol(2)

and so on until the last button cel:

;@press("cycle6.cel")
;@     map(#2) changecol(0)

Which means that the cels of the button object are being cycled, using the first method described above.

Or you can simply use the viewer's own palette buttons, in which case no FKiSS is required whatsoever. This method requires only one cel, one object and one palette, making it a big space-saver if you don't need more than ten different colours.


refinement 5: using transparent()

In this example, cels are not unmapped, but made transparent, allowing the cel beneath to shine through. This solution is clunky rather than refined, but it may allow for extra steps in the colour cycling if you make a cel semi-transparent, which blends its colour with the cel underneath, rather than making it fully see-through straight away. The object declarations may, but don't have to, look like that of the first method, with a transparency tag added:

#1   	petals.cel	*0 :0		;      red petals
#1      petpink.cel     *0 :0		;%t255 pink petals
#1      petorng.cel     *0 :0           ;%t255 orange petals
#1      petblue.cel     *0 :0           ;%t255 blue petals
#1      petyelw.cel     *0 :0           ;%t255 yellow petals
#1      petpurp.cel     *0 :0           ;%t255 purple petals
#1   	stalk.cel	*0 :0           ;%t255 flower stalk

As you can see, this is again a flower that won't separate into components when moved around, although you could also make each ring of petals a different object, since transparent() works both with cels and objects. Since the cels are never unmapped, you can't cycle through them by clicking on them (unless you use FKiSS3 to count the number of clicks), so you have to add an extra button object as in the previous example. The code might look like:

;@press("cycle1.cel")
;@   unmap("cycle1.cel")
;@   transparent("petals.cel",255)
;@   transparent("petpink.cel",-255)
;@press("cycle2.cel")
;@   unmap("cycle2.cel")
;@   transparent("petpink.cel",255)
;@   transparent("petorng.cel",-255)

and so on. Or, you might try intermediate transparencies:

;@press("cycle1.cel")
;@   unmap("cycle1.cel")
;@   transparent("petals.cel",128)
;@   transparent("petpink.cel",-128) ; colour between pink and red
;@press("cycle2.cel")
;@   unmap("cycle2.cel")
;@   transparent("petals.cel",128)
;@   transparent("petpink.cel",-128) ; completely pink

since transparent() doesn't set an absolute transparency value, but adds or subtracts the given value from the transparency value, meaning that after the second cycling cel has been clicked away, the red petals are 0 + 128 + 128 = 255 which means totally transparent, while the pink petals are 255 - 128 - 128 = 0 which means totally opaque. (This looks like bad arithmetic, but computers start counting at 0.) This changing of transparency can be done in even smaller steps, or transparency-altering controls can be included in the KiSS set to let the users do a bit of colour-mixing themselves.


blinking with different eyelid colours- submitted by calezane, originally by the invisible phan

This tip was originally submitted to the KiSS mailing list by the Invisible Phan.

Blinking is easily the most frequently used FKiSS effect, but when the doll can have different eyeshadow colours, you have to keep track of what the eyelid colour is, so that you don't map the purple-lidded half-closed eye over the green-lidded open eye, or the flesh-colour closed eyelid over the blue-shaded half-open one. This can be kept track of in FKiSS3 with variables, or you can use a different set of blinking alarms for each eyelid colour, stopping one set and starting another when the colour changes, but there is a much simpler method: transparent eyelids.

The most basic blinking-doll construction is a cel of a base doll with open eyes drawn on the face, and a cel of closed eyelids which are periodically mapped to cover the eyes. This method requires that the open eyes become a separate cel. You now have: a doll with no eyes, just two holes filled with the flesh tone of the base doll (and possibly outlined, to make it easier to fill in the eyelid colour cels later) a pair of eyes that completely covers these holes, and a pair of closed eyelids that also completely covers these holes. You may want to add a pair of half-closed eyes for smoother animation. Now, the eyelid cels must be flooded with the transparent background colour. You can keep the lashes and any outlines, but the "flesh" part should be the background colour. The rim of eyelid visible on each open eye should also be filled with the background colour. (As should the eyelid part of the half-closed eyes cel, if there is one.) The blink cycle, rather than just mapping the eyelid cels over the eyes now and then, should now map the eyelid cels and unmap the eye cels, so that the eyelid cels lie directly on top of the eyeless face. What colour are the eyelids going to be? That's right, the same colour as the face.

Now I want to add blue eyeshadow. Rather than making extra closed-eyelid and half-open-eye cels with the eyelids coloured blue, I make two patches of blue that exactly cover the eye holes. (This is where it's handy to have the eye holes outlined on the face: I can copy the base doll image, flood-fill the eye holes with the eyeshadow colour, then erase the rest of the copy.) In the cnf, these two patches of colour go over the face, but under the eyes and eyelids. When I want the doll to have blue eyeshadow, I map those colour patches, and the blue can be seen through the transparent rim of eyelid over the open eye. When the doll blinks, the area of eyelid increases, showing more blue. (Hence the unmapping of the open eyes; else you'd still see them staring through the eyelids.) Next, I want green eyeshadow, so I copy the image file of the blue patches and flood-fill them green. When I want the eyelid colour to change, I unmap the blue patches and map the green ones. Now the eyelids appear to be green, although it's still the same open-eyes cel alternating with the same closed-lids cel when the doll blinks. I can add as many differently coloured patches as I like and cycle through them with any colour cycling method described under the colour- cycling howtos.

This method can be used to simplify any shape-changing cycle where the shape-changing parts can change colour. The original tip had a bar of colour lying under a face with two transparent eye holes in it, rather than a face with two flesh-coloured eye holes with the colours mapped over them, but if the colours lie over the face, the eyelids always have a basic flesh tone which automatically changes when the whole doll's flesh tone does (from pale to tan, for instance). In the case of, for instance, different lipstick colours and a smile cycle, the original method works better: a face cel with a lip-shaped transparent section, an alternate face cel with a transparent section in the shape of smiling lips, and a bar of lipstick colour underneath that shows through either shape.


using version() --yet another tip from calezane!

This howto quotes a code example from Chad Randall's KiSS .cnf layout, FKiSS/FKiSS2 command reference, and various PlayFKiSS notes, which can be found at the Big KiSS Page.

FKiSS syntax was implemented not simultaneously but sequentially, meaning, some commands were defined and viewers were programmed to understand them, then some more commands were defined and newer viewers were programmed to understand those too, and so on. This means that a viewer which is FKiSS-capable may still fail to understand the FKiSS code in a set, with two possible results: the viewer either ignores the unknown code, or starts to malfunction. Code that causes the viewer to malfunction (eg. freeze, ignore code that it should understand, or any other strange behaviour) is said to "break" the viewer. To warn the user that the viewer may not understand the FKiSS syntax in a set, FKiSS2 introduced the event version(), used with the number of a FKiSS level.

The currently existing FKiSS syntax has five levels: FKiSS, FKiSS2, FKiSS2.1, FKiSS3 and FKiSS4. The version() event works like this: put the level number of the highest FKiSS level used by the cnf in the brackets (for FKiSS3, that would be version(4) and if the viewer understands that level, it will carry out the actions under the event. As version() is an event and is triggered only once (to be exact, as soon as the parser encounters it in the cnf) it can't be used for "If viewer understands command X then do command X else do command Y" constructions; its main use is to warn the user when the set is opened in the viewer, and so it should be put above any other FKiSS code. Typically, it unmaps a warning cel that would stay mapped if the FKiSS level number was too high for the viewer. As version() is a FKiSS2 event, a FKiSS-only viewer won't even recognize it, which has the same effect as putting in a level number that is too high. The example in Chad's FKiSS2 document goes like this:

;@EventHandler
;@never() ; This tricks older viewers into ignoring the next 2 lines.
;@version(2) ; If the viewer supports FKiSS2,
; ; revision 2, run the following commands.
;@ unmap("warning.cel")
; ; warning.cel is a huge poster saying
; ; "You need a FKiSS2 viewer to play this set."
;@begin()

The event never() acts like a wrapper to the version() event, making the viewer believe that the unknown event is an action that belongs to never() and is consequently never executed. Another wrapper to hide events that might not be understood by the viewer is the so-called "dummy alarm"; alarm(n) is used instead of never(), where timer(n) is never set. Whichever is used, version() and its wrapper must be put above both initialize() and begin(), or the viewer may ignore both events and see the unmapping action immediately under them as belonging to initialize() or begin(), and happily unmap the warning cel even though the viewer is not FKiSS2-capable.

Depending on the viewer, version() can be used once for each level number, or simply only once. Being able to use it only once can be annoying in a set which has more warning cels: for instance, one to say that the set absolutely requires FKiSS2 and another one to say that the set will run with FKiSS2 but would look even better with FKiSS2.1. The solution is to do what never() does, with another event: only trigger the unmapping action if the viewer is up to the event. In this case, the warning "This set requires FKiSS2" can be unmapped with version(2), while the cel "But to show all the effects, you need FKiSS2.1" could be unmapped via a specifically FKiSS2.1 action that also goes under version(): ifmapped(), which sets a timer if a cel is mapped. The code would then be:

;@EventHandler
;@never()
;@version(2)
;@ unmap("warning1.cel")
; ; warning1.cel is a huge poster saying
; ; "You need a FKiSS2 viewer to play this set."
;@ ifmapped("warning2.cel", 20, 1)
; ; warning2.cel is a huge poster saying
; ; "This set will work with FKiSS2 but looks better with FKiSS2.1."
;@initialize()

;@alarm(20)
;@ unmap("warning2.cel")

A viewer which isn't FKiSS2.1-capable will ignore ifmapped(), which means that the timer isn't set, and the second warning cel isn't unmapped.

And of course if you don't want the warning cel to stop the user from playing with the set, you can add:

;@press("anywarning.cel")
;@ unmap("anywarning.cel")

so the user can get rid of it with a mouseclick.


triggering collision after page change -- by calezane!

try downloading this nifty sample set by calezane to help understand how it works!

I should first explain what collision detection is. There are six collision events: in(), out(), stillin(), stillout(), collide() and apart(). The first four require two object numbers in the brackets. in(#1, #2) would be triggered if objects #1 and #2 overlap now, but didn't overlap before; out(#1, #2), if the objects overlapped before, but have now moved apart; stillin(#1, #2), if the objects overlapped before and are still overlapping now, and stillout(#1, #2), if the objects didn't touch before and are still apart. collide() and apart() are like in() and out(), but use cel names instead of object numbers.

I repeatedly used the words "now" and "before"; what I mean is, after and before collision detection. When something happens to an object that triggers collision detection in a viewer, this viewer checks if this object number occurs in any collision events, and then, whether it has just collided with or moved apart from the other objects in those collision events, or was already overlapping or apart, and then fires the appropriate collision events. Collision detection is always triggered by moving the object, whether by FKiSS code or by dragging it with the mouse. Depending on the viewer, collision detection may also be triggered by (un)mapping the object, or by the automatic shift in position of the object when changing to another page, either through changeset() or by clicking on a different page number, but in most viewers this is not the case. And that can be a nuisance.

As an example: I have a vase object, which is in a different spot on each page, and a bunch-of-flowers object which has two cels, one simply the bunch of flowers, the other the same bunch of flowers wrapped up in paper. By alternately mapping these two cels, I can "wrap" and "unwrap" the bunch of flowers. When the flowers touch the vase, I want them to pop into the vase and lose their wrap, and when I pull them away from the vase, I want them to become wrapped again. The code might look like:

;@initialize()
;@  unmap("flowers.cel")
;
;@in(#1,#2)   ; where #1 is the vase and #2 is the flowers
;@  movebyx(#1, #2, -10) movebyy(#1, #2, -65)
;@  unmap("flowrap.cel") map ("flowers.cel")
;@out(#1,#2)
;@  map("Flowers.cel") unmap ("flowrap.cel")

If I stay on page 0, this will work; the flowers pop into the vase and lose their wrap as soon as flowers and vase overlap. But now I change to page 2, where the flowers and the vase are not overlapping at all; moving actions are restricted to the page being viewed, so the flowers were only put in the vase on page 0, but mapping actions happen on all pages, so the unwrapping happens on both page 0 and 2. The viewer doesn't detect that when I go to page 2, the flowers and vase are separate, and out(#1, #2) is not triggered.

But I do want it triggered, else the flower-vase trick doesn't seem to work, so I put in a page change event for each page, from 0 to 9:

;@set(0)
;@  move(#2,0,100) ; that should move the flowers completely clear of the
vase
;@  move(#2,0,-100) ; now they're back where they were
;
;@set(1)
;@  move(#2,0,100)
;@  move(#2,0,-100)
;
;@set(2)
;@  move(#2,0,100)
;@  move(#2,0,-100)

and so on until set(9). What happens is that, as the end position of the flowers after all these move actions is the same, they'll stay exactly where they are; but the viewer sees a moving action, and checks if the flowers are in or out of contact with the vase.


using snap-to, and turning it off -- by calezane!

try downloading this nifty sample set by calezane to help understand how it works!

This howto is based on a post to the KiSS ML by Dov Sherman about using collide() for "localized" snap-to, and one from Alexandra Werres on how to turn snap-to on and off.

"Snap-to" is when a cel, usually a clothing cel, jumps into position over another cel, usually the base doll, often after a collision event is triggered; the general use for snap-to is having clothes position themselves correctly over the doll when they touch it, and it has a few advantages:

However, people sometimes like to position clothing cels in a different way from the artist, and may be very irritated at having them shoot into place. To please everyone, the artist could make two cnfs, one with and one without snap-to code, or have just one cnf with the possibility of turning off the snap-to effect.

But first, how to add snap-to code:

In PlayFKiSS 0.8x, this is very easy. Right-click on the "parent" object (usually the base doll) and select "Set Snap-to Parent". If this option is not in the menu, the viewer isn't in editor mode: go to Tools|Options, click on the second tab, and select "Editor mode", then try again. PlayFKiSS now remembers that the coordinates of this object are the starting point for the snap-to code. Now position a cel over the parent object, right-click on it and select "Add snap-to code". Then, save the cnf.

If you open the cnf in a text editor, you will see the added lines:

;@in(#1, #5)
;@  movebyx(#5, #1, 9)
;@  movebyy(#5, #1, 22)

The snap-to code uses object numbers, not cel names, because only objects can have coordinates. I happen to know that object #1 is the base doll and object #5 is a hat. The movebyx(), movebyy() code tells the top left corner of the hat object to move 9 pixels down and 22 pixels to the right from the top left corner of the base doll object. If the numbers had been negative, the hat would have moved up and to the left. The in() code says that this movement should happen when the hat object and the base doll object touch. (To be exact, when the bounding boxes of the two objects touch.) This is not necessarily when the artist wants snap-to to happen, but let's first see how to add snap-to code if you don't have PlayFKiSS. To do this, drag the parent object and all the objects that should snap to it in exactly the right position, then save the cnf and open it in a text editor. The line of coordinates for the page the objects have been arranged on might look like this:

$0 0,0 0,0 59,56 138,156 133,6 9,22 125,120

Objects are counted starting at 0, so I can see that objects 0 to 6 have the following coordinates:

object #0: 0,0
object #1: 0,0
object #2: 59,56
object #3: 138,156
object #4: 133,6
object #5: 9,22
object #6: 125,120

The coordinates tell me how many pixels the top left corner of each object is away from the top left corner of the screen. I can see at a glance that object #5 is 9 pixels down and 22 pixels to the right of object #1. If I wanted it to snap to object #2, I would have to do the following sum:

59 - 9 = 50, code = movebyx(#2, #5, 50)
56 - 22 = 34, code = movebyy(#2, #5, 34)

Now, to decide what event will cause the snap-to. It could be:

- the hat touching the base doll.
- the hat touching an object other than the base doll.
- a "button" cel being clicked (ie. a press() event).
- an alarm going off.
And so on.

If I wanted simple snap-to, I could keep the in() event: if the hat touches the doll, it whizzes to the doll's head. But I may want to be able to put the hat in the doll's hands too, so it should only jump on the doll's head if it touches the doll's face. It is then more convenient to take a different object, which may simply be a circle in one colour, and put that in the same position as the doll's face, but one layer below it, so it is hidden by the doll but can still trigger a collision event when the hat object touches it. If this new object, which is strictly for the localized snap-to, is object #7, then the code becomes:

;@in(#7, #5)
;@  movebyx(#5, #1, 9)
;@  movebyy(#5, #1, 22)

Note that the order of the object numbers doesn't matter for the in() object, but it does matter for the "moveby" actions, as the first object number "snaps to" the second.

Now that the snap-to is brought about by a cel which is hidden, the snap-to effect can easily be turned off by unmapping that cel, and turned on by remapping it. This can also be done in many ways, but a simple way is with a button cel:

;@press("button.cel")
;@  altmap(#7)

An alternative way, if the snap-to is caused by the hat touching the base doll itself, is to assign the base doll cel to two different object numbers:

#1.999	basedoll.cel	*0 :0
#2.999	basedoll.cel	*0 :0

and alternately map #1 and unmap #2, or map #2 and unmap #1; when only #2 is mapped, the base doll is still visible, but dragging the hat over it doesn't trigger in() and consequently doesn't reposition the hat.