-
-
Notifications
You must be signed in to change notification settings - Fork 33
characters
In Open Surge, you can create your own playable characters. To create a playable characrer, first of all you need to create a character file.
Character files are human-readable configuration files located in the characters/ folder. They have the .chr extension. These files are used to specify the properties of the characters.
Each level has one or more playable characters. You can select which characters appear in which levels.
Character files are used to specify the following data:
- the name of the character;
- the
multipliers
. These values are used to specify how fast a character runs, how high it jumps, how fast it accelerates, etc. For example, if you set the acceleration to one, it will accelerate by the default rate (set by the game engine). If you set it to two, it will accelerate two times faster than that. If you set it to 0.5, it will accelerate by half of the default rate, and so on. By default, all the multipliers are set to 1.0; - the
animations
for each action the character performs: walk, run, jump, etc., as well as the sprite name. See also: Sprites; - the
samples
or sound effects this character uses: jump, brake, etc.; - the
abilities
this character has: roll, charge, etc.; - optionally, the name of one or more
companions
, a.k.a. companion objects. If defined, companion objects can be used to give custom abilities to characters.
File: characters/surge.chr (simplified)
character "Surge"
{
companions "Surge's Lightning Boom"
multipliers
{
acceleration 1.0 // modifies the acceleration rate
deceleration 1.0 // used when moving in opposition to the current movement
friction 1.0 // modifies the friction (since version 0.5.0)
topspeed 1.0 // modifies how fast the character can run
jump 1.0 // modifies how high the character jumps
gravity 1.0 // gravity modifier
slope 1.0 // affects the physics on slopes
charge 1.0 // modifies the charge-and-release speed (since version 0.5.0)
airacceleration 1.0 // the rate at which the horizontal speed can change while midair (since 0.5.0)
airdrag 1.0 // air drag / air friction (since version 0.5.0)
}
animations
{
sprite_name "Surge"
stopped 0
walking 1
running 2
jumping 3
springing 13
rolling 18
charging 6
pushing 14
gettinghit 11
dead 8
braking 7
ledge 10
drowned 9
breathing 12
waiting 15
ducking 4
lookingup 5
winning 17
ceiling 16
}
abilities
{
roll TRUE
brake TRUE
charge TRUE
}
samples
{
jump "samples/jump.wav"
roll "samples/roll.wav"
death "samples/death.wav"
brake "samples/brake.wav"
charge "samples/charge.wav"
release "samples/release.wav"
}
}
The example above has been simplified for the purpose of explanation. The actual character file of Surge has some additional things in it.
Note
Compatibility notes: animation charging
, sounds charge
and release
, the abilities
block, as well as some multipliers (indicated above) are available since Open Surge version 0.5.0.
Note
Companion objects: companions
is available since Open Surge version 0.5.0. It is followed by one or more names of objects surrounded by double quotes ("
). These objects should be created in SurgeScript. In older versions of the engine, you'd write companion_object
instead (it supported only one companion).
Playing as the character is a matter of adding it to the levels of your choice. Using a text editor, open the lev files you choose (they are in the levels/ folder) and add the name of your character to the players
entry. For example: in the Sandbox level (file levels/sandbox.lev), change the players
entry to:
players "Tux"
Save the file and open the level. You should be able to play as Tux the Penguin. Now change the players
entry again to:
players "Surge" "Tux"
Save the file and open the level again. You should see two playable characters: Surge and Tux. For more information, refer to: Level specification - players.
One of the exciting features of Open Surge is the possibility to create custom abilities (custom moves) for your characters. You can create these abilities by adding companion objects to your characters. These objects are created in SurgeScript.
To understand better how to create your own custom abilities, let's study the case of a dash movement ("Super Peel Out"). If your character is endowed with that ability, you can give it instant speed when it's stopped. In Open Surge, character Tux features that ability. Surge does not. To add this custom move to Surge, add the corresponding object to his companions:
companions "Surge's Lightning Boom" "Super Peel Out"
The new companion is defined in a script, a .ss file located in the scripts/ folder. Writing new scripts is beyond the scope of this article, but the script of this move has been reproduced here for clarity (do not copy and paste it - it's already shipped):
using SurgeEngine.Level;
using SurgeEngine.Vector2;
using SurgeEngine.Audio.Sound;
//
// This is a dash move that should be configured as a
// companion object in a character definition file (.chr)
//
// When you are stopped, hold up and press jump to charge.
// Release up after half a second and you'll gain a nice boost!
//
object "Super Peel Out" is "companion"
{
public anim = 2; // default animation: running
speed = 720; // dash speed, in pixels/second
charge = Sound("samples/charge.wav");
release = Sound("samples/release.wav");
player = parent; // since this object is configured as a
// companion, parent is the reference
// to the correct Player object
// capture the event
state "main"
{
if(player.lookingUp) {
if(player.input.buttonPressed("fire1")) {
charge.play();
state = "charging";
}
}
}
// charging the dash
state "charging"
{
// disable the dash?
if(player.midair || player.hit || player.dying || player.winning) {
state = "main";
return;
}
// change the animation
player.restore(); // stop looking up
player.anim = anim;
// make the player stand still
player.xsp = player.ysp = player.gsp = 0;
player.input.simulateButton("right", false);
player.input.simulateButton("left", false);
player.input.simulateButton("down", false);
// ready to go?
if(player.input.buttonReleased("up")) {
if(timeout(0.5)) {
player.gsp = speed * player.direction; // dash!!!
release.play();
spawnSmoke();
}
state = "main";
}
else if(player.input.buttonPressed("fire1"))
charge.play();
}
fun spawnSmoke()
{
Level.spawnEntity(
"Speed Smoke",
Vector2(
player.collider.center.x - player.direction * 22,
player.collider.bottom + 2
)
).setDirection(player.direction);
}
}
What custom abilities can you add? Whatever you can imagine! Swimming, flying, climbing, wall kicking, you name it! The sky is the limit for those who learn SurgeScript!
We now present Speedy the Rollerskater, an original character created by community member Synfigmaster91. In addition to the basic abilities of braking, rolling, etc., Speedy has a special ability of his own: he can swim. The following files are relevant to this character:
- the spritesheet: a png image featuring the animations of the sprite. In the image below, the sprites are aligned to a 64x64 grid.
- the sprite script: a spr file that describes how the animations are laid out in the spritesheet. Read the Sprites page for more information on the subject.
- the character file: a chr file that describes the character in the way we have just seen.
- the SurgeScript file(s): these are ss scripts that add new traits to the character - the swimming ability is an example. Inventing new special abilities requires a more in-depth knowledge of the engine and is beyond the scope of this article. If you're interested, you can learn SurgeScript.
File: sprites/speedy.png
File: sprites/players/speedy.spr
sprite "Speedy"
{
source_file "images/speedy.png"
source_rect 0 0 512 704
frame_size 64 64
hot_spot 32 44 // hot_spot.y is (frame_size.y - 20)
// stopped
animation 0
{
repeat TRUE
fps 8
data 0
}
// walking
animation 1
{
repeat TRUE
fps 16
data 3 4 5 4 3 2 1 2
}
// running
animation 2
{
repeat TRUE
fps 16
data 8 9 10 9 8 7 6 7
}
// jumping / rolling
animation 3
{
repeat TRUE
fps 16
data 11 12 13 14
}
// ducking
animation 4
{
repeat FALSE
fps 12
data 19
}
// looking up
animation 5
{
repeat FALSE
fps 8
data 16
}
// charging
animation 6
{
repeat TRUE
fps 32
data 35 36
}
// braking
animation 7
{
repeat FALSE
fps 8
data 15
}
// dead
animation 8
{
repeat FALSE
fps 8
data 18
}
// drowned
animation 9
{
repeat FALSE
fps 8
data 18
}
// ledge
animation 10
{
repeat TRUE
fps 5
data 23 24
}
// getting hit
animation 11
{
repeat FALSE
fps 8
data 20
}
// breathing
animation 12
{
repeat FALSE
fps 8
data 21
}
// springing
animation 13
{
repeat TRUE
fps 8
data 17
}
// pushing
animation 14
{
repeat TRUE
fps 8
data 28 29 28 27
}
// waiting
animation 15
{
repeat TRUE
fps 6
data 25 26
}
// ceiling (being carried)
animation 16
{
repeat TRUE
fps 8
data 22
}
// winning (victory)
animation 17
{
repeat TRUE
fps 8
data 34
}
// rolling
animation 18
{
repeat TRUE
fps 8
data 30 31 32 33
}
// falling
animation 20
{
repeat TRUE
fps 8
data 22
}
// swimming
animation 21
{
repeat TRUE
fps 8
data 37 38 39 38
}
}
File: characters/speedy.chr
character "Speedy"
{
companions "Super Peel Out" "Speedy Swim" "Dash Smoke" "Brake Smoke" "Speedy Falling"
multipliers
{
acceleration 1.0
deceleration 1.0
friction 1.0
topspeed 1.0
jump 1.0
gravity 1.0
slope 1.0
charge 1.0
airacceleration 1.0
airdrag 1.0
}
animations
{
sprite_name "Speedy"
stopped 0
walking 1
running 2
jumping 3
springing 13
rolling 18
pushing 14
gettinghit 11
dead 8
braking 7
ledge 10
drowned 9
breathing 12
waiting 15
ducking 4
lookingup 5
winning 17
ceiling 16
charging 6
}
abilities
{
roll TRUE
brake TRUE
charge TRUE
}
samples
{
jump "samples/jump-7408.wav" // <-- notice that Speedy uses a jump sound of his own
roll "samples/roll.wav"
death "samples/death.wav"
brake "samples/brake.wav"
charge "samples/charge.wav"
release "samples/release.wav"
}
}
File: scripts/players/speedyfalling.ss
//
// We modify Speedy's animation:
// 1. when he falls down after hitting a spring
// 2. after breathing an air bubble
//
using SurgeEngine.Player;
object "Speedy Falling" is "companion"
{
player = parent;
falling = 20;
springing = 13;
state "main"
{
// The player may be in the springing state,
// but that alone doesn't mean he has just
// been hit by a spring. We use the springing
// state to create other things, like the double
// jump, so we need to check player.anim as well
if(player.springing && player.anim == springing)
state = "watching";
// From breathing to falling
else if(player.breathing)
state = "watching";
}
state "watching"
{
// Now the player is midair and will fall
// down. We'll capture this event and
// change the animation accordingly
if(player.ysp >= 0 && player.midair) {
player.anim = falling;
state = "falling";
}
else if(!player.springing && !player.breathing)
state = "main";
}
state "falling"
{
if(player.ysp >= 0 && player.midair)
player.anim = falling;
else
state = "main";
}
}
File: scripts/players/speedyswim.ss
//
// This is a swimming move that should be configured as a
// companion object in Speedy's character definition file (.chr)
//
// When you are underwater, jump and press fire1.
// Speedy will swim and if you press fire1 repeatdly he will keep swimming!
//
using SurgeEngine.Player;
object "Speedy Swim" is "companion"
{
player = parent;
timeMidAir = 0;
state "main"
{
state = "nounderwater";
}
state "nounderwater" // out of water
{
if(player.underwater) {
state = "underwater";
}
}
state "underwater" // underwater but not swimming
{
timeMidAir += (player.midair ? Time.delta : -timeMidAir);
if(timeMidAir >= 0.1 && player.underwater) {
if(player.input.buttonPressed("fire1")) {
state = "swim";
}
else if(!player.underwater) {
state = "nounderwater";
}
}
}
state "swim" // swimming
{
player.springify(); // make it vulnerable to attack
player.anim = 21;
player.ysp = -90;
state = "swim2";
}
state "swim2"
{
player.anim = 21;
if(!player.underwater) { // got out of water
state = "nounderwater";
}
else if(!player.midair) { // landed on the ground
state = "underwater";
}
else if(player.input.buttonPressed("fire1")) { // swim more
state = "swim";
}
else if(player.dying) {
destroy();
}
}
}
Even though Open Surge provides built-in 360º physics (with curvy roads, loops, and so on), careful modification of the character files can make it behave like a regular platformer. Example: if you create a character named SuperTux without the special abilities listed above (rolling, charging, etc.), set its slope multiplier to zero (and adjust the others), as well as build levels mainly out of rectangular platforms, you'll end up with a platformer like SuperTux. Additionally, companion object "Lock Angle" (located at scripts/players/lock_angle.ss) prevents the character from rotating on slopes.