I find them tricky too. Especially tricky is when tiles are above ground, at the player characters' level. Here's some things you can do from a tile- and level design perspective, if lethal properties are decided on a per tile basis. Red colour shows kill pixels that are supposed to be air. If a tile contains black, that means it is nonlethal.While it may seem odd, I've been struggling to implement decent spikes since I began making games... I think it's about time I open a discussion in the dev forums about how you guys implement spikes and spiky objects, and how you make interact actors with them, 'cause I never seem to get them 100% right.
Fig. 1
This is subtle, but i'm adding a few pixels on top and to the sides to make the spike look slightly bigger than the kill area. It's no problem if you want to replace the sides with grass tufts here and there or some other bg tile , but the points are kind of important.
Cons:
-it's just a tiny nudge in the right direction
Fig. 2
Same as before, but placing lesser, non-lethal spikes on the sides. Player will jump prematurely, less risk of hitting unfair kill pixels, and they're within the diagonal line of the first (nonlethal) spike.
cons:
-player can walk a bit into the spikes without being killed. The game rules may feel a bit loose then.
Fig 3.
This shows two pretty airtight solutions to whenever a spike is below normal ground level. It feels very natural to have the player actually fall a distance before getting killed. The size of the spikes can be varied - if the player character overlaps them by some at kill time, the action looks better. Spending some time on it, i might've made the spikes a size between the two examples shown.
Fig 4.
One or a few bigger spikes in the middle helps the player evaluate the situation and jump appropriately, and the spikes become more visible.
Fig 5.
By offsetting the spikes so that they're off-centre, you can achieve the smoothest result. The kill pixels are only between sets of spikes this way, never at the edge of a spike field. Collision wise, this is almost perfect.
Con:
-You might have a bit of attribute clash and placement problems this way, but it can be worked around.
-My example is nonsymmetrically shifted. This should be more exact if the player comes form the left (often the case), but not as exact if coming from the right). You may want to even that out. As it is, it's debatable if the rightmost tile should be non-lethal as showed, or lethal.
Fig 6.
Same as 5, but with bigger spikes and a more even offset to both right and left. Again, falling a bit through spikes before getting killed looks more natural than getting killed directly on contact with the top of the spike. The tricky part here is balancing how much (the height of the spike) against not allowing any kill pixels outside the spike fields' borders.
Same goes for lava and the like, except it is easier since it's mostly a horizontal line.
None of these examples except maybe fig 1 cover circular or omni-directional kill tiles. 2x2 tile kill blocks hanging in the middle of the air are hard this way.
Other, non graphic-related methods on top of my head:
screen position checking:
If player_y (or x) is more/less than n, assume player is killed by spikes/lava. Metroid does this in horz scrolling rooms.
Pros:
-You can very precisely set the height when the damage/kill happens.
-You can also make it wave up and down along with some tile animation.
Cons:
-you may need to create exception clauses/attributes if you don't want it to be universal.
-no middle of the room placements, unless you want to do a lot of checks for every kill object on the level.
conditional sub-tile hit detection:
-if colliding with a kill tile (or meta-tile), try the player position against a hit mask. It doesn't need to be full 8x8 (or 16x16) granularity - 2x2 hit fields or the like might suffice. The amount of frames the player object is valid for these extra checks are few.