While I do recommend an invisible bounding box to be used across the board, one thing you could do (so as to avoid repeating the same control inputs over and over) is to have a broad player class that handles the control input and state handling and all the common features between characters, and then have little subclasses for each individual character. Like....
Player is a sprite with platform behavior
Mario and Sonic are both part of the "PlayerSprite" family
"Player Class"
if player state = "idle"
if press right
player move right
PlayerSprite play anim "walk"
if press left
player move left
PlayerSprite play anim "walk"
if press attack
set player state = "attack"
PlayerSprite play anim "attack"
PlayerSprite spawn AttackBox at imagepoint "attack"
if press special
set player state = "special"
"Mario Class"
if player state = "special"
Mario play anim "throw_fireball"
Mario spawn Fireball at imagepoint "fireball"
if Mario anim "throw_fireball" finished
set player state = "idle"
"Sonic Class"
if player state = "special"
Sonic play anim "spindash"
Sonic spawn AttackBox at imagepoint "spindash"
if Sonic angle = 0
Sonic set VectorX = 250
elseif Sonic angle = 180
Sonic set VectorX = -250
if Sonic VectorX is between -50 & 50
set player state = "idle"
Something like that. Not necessarily EXACTLY like that, but the idea there is how I'd do it.