Sprite Engine

The sprite engine is a development component that loads and manages sprites and tiles. This functionality is implemented in the  namespace. Essentially, all sprites inherit from a  base class, and all tiles inherit from a   base class. These base classes provide the basic functionality required, such as position, velocity, other physics fields, and abstract and virtual methods to be overriden in the derived classes.

The sprites and tiles themselves will be, of course, written in C# code, in Visual Studio or whichever C# IDE that the developer prefers. Compiled sprites and tiles will be stored inside of DLL files, here called assemblies. Assemblies will also contain a  static type that contains useful information.

Sprites and tiles, apart from testing sprites and tiles, will not be stored in the SMLimitless.exe program. They will always be stored in a separated DLL.

Definitions
A sprite is an optionally named object that has graphics to be drawn to the screen. It has a position, size, velocity, and acceleration, and its position, velocity, acceleration are updated every frame. Sprites can collide with the solid sides of tiles, other sprites, and the player, with different behavior in all cases. Sprites are active within a rectangular area of a level which is slightly larger than the camera's view, and most sprites will stop updating and drawing once they fall out of this area. Sprites can be part of layers.

A tile is an optionally named object that has graphics to be drawn to the screen. It has a position and a size, and does not move unless part of a layer. It does not check collision with anything, rather, other sprites check collision against it. Tiles can have certain solid edges on which sprites will collide, or it can cause sprites to react in a specific way on collision.

A layer is a named group of sprites and tiles that can perform certain actions (such as moving or vanishing) on certain triggers (such as a P-Switch is pressed or a certain block is destoyed). Moving layers can also kill sprites if they intersect too far inside the block (such as blocks designed to crush the player).

Usage of Assemblies
Sprite and tile types will be stored in DLLs containing assemblies which reference the SMLimitless assembly. These DLLs will be used for all sprites, custom or not, in SML. SML's own sprites will be stored in an SMLSprites.dll file in the program's install directory. Custom DLLs will be stored alongside Content Packages.

Level files will list the filenames of all assemblies used in the level. Only the filenames, and no path information, is needed, as all the assemblies would be copied or moved to the custom assembly folder when the level is added to the game's level list. On level loading, these assemblies will be loaded, their types derived from reflection, and IDs assigned (see below for ID assigning).

Sprite and Tile Base Classes
In order to be treated generically by levels, all sprites and tiles should derive from abstract base classes in the SMLimitless assembly that may have virtual implementations as necessary. Additionally, these base classes should implement certain interfaces, such as IPosition and perhaps IName, and possibly others. These types will expose a public methods and fields, listed below.

A sprite should expose the following fields and methods:
 * : The label that this sprite has in the level editor.
 * : Should be used to set a sprite's properties to the defaults, and then any other necessary initialization.
 * : The label that this sprite has in the level editor.
 * : Should be used to set a sprite's properties to the defaults, and then any other necessary initialization.
 * : Should be used to set a sprite's properties to the defaults, and then any other necessary initialization.
 * : Should be used to set a sprite's properties to the defaults, and then any other necessary initialization.
 * : Should be used to set a sprite's properties to the defaults, and then any other necessary initialization.
 * : Should be used to set a sprite's properties to the defaults, and then any other necessary initialization.

A tile should expose the following fields and methods:





















IDs
A sprite or tile has at least one identification numbers. The first ID is an UInt32 that is used to identify a specific sprite. For example, a Red Parakoopa may have an ID of 54. IDs will be assigned on level load, after the assemblies containing sprites have been loaded.

Each level file will contain a list of the assemblies from which it uses sprites or tiles. Each assembly has an ID associated with it within the level file as well. Meanwhile, as assemblies are loaded into the AssemblyManager, each loaded assembly gets a different ID, which increments for each loaded assembly. This ID is used to substitute for the level file assembly IDs, and all loaded sprite and tiles will use this new ID as the first two bytes of its own ID. This allows for up to 65,536 loaded assemblies, each with 65,536 sprites and 65,536 tiles.

Properties in Editor
A sprite or tile will define and inherit additional properties which define certain aspects of a sprite. These properties will be displayed in a PropertyGrid control in the level editor. Properties can also be inherited from base classes. These properties will also have default values (not null or default(T)) that are set in Initialize and then can be changed by the level loader or level editor. Many properties will have an enumeration for a type; any enumerations specific to a sprite or tile must be stored in the same source file as the sprite, and below the sprite's class. The Sprite type should implement the following properties (subject to change):
 * (default ""): An optional name that can be used as a reference. For example, a layer may move if a block named "TriggerBlock" is hit from below.
 * (default ""): An optional message that will be displayed if the player presses the Up button while standing near the sprite. Sprites with messages will display an exclamation mark over themselves.
 * : If true, this sprite will injure or kill players.
 * (default usually true): If true, this sprite will move, otherwise it will stand in place, but can still be interacted with.
 * : Left, Right, or FollowPlayer. FollowPlayer means that the sprite will face the player on first load and when the sprite re-enters the active area.

Sprite-Tile Interaction
On every frame, the Level class runs a collision handler that takes information available for all sprites and tiles to properly resolve all collisions between sprites and solid tiles. The collision mode of the sprite and the TileCollisionType of the tile is used to determine if a certain collision must be resolved. Then, after the collision has been resolved, the tile is informed of the collision and is passed the reference of the intersecting sprite. From there, it can determine the right course of action to take. For example, lava would kill the sprite instantly and spawn a small cloud of smoke. Water would enable the sprite's water physics, and custom tiles would define a custom behavior.

Tiles may have to check a sprite's state to determine how to respond. For example, a sprite may intersect a Question Block, and the tile would check if the sprite's state was "shell_spinning", and if so, would trigger the item inside.

The sprite is then informed of the collision once the tile has handled it, but in most cases, the sprite wouldn't have to do anything. An example of a sprite having to do something would be a moving Throw Block hitting a wall - once informed, the block would shatter.

Sprite-Sprite Interaction
Sprites have a string property that represents their state. These states are used to determine how to respond to certain occurrences, such as two sprites colliding with each other. For example, a Goomba might intersect another sprite, which is a spinning Koopa shell, but the Goomba doesn't know that. The Goomba checks the other sprite's state, and if it's "shell_spinning", the Goomba will be knocked out of the stage. In order to reduce the number of states to check, many sprites can use the same state. For example, any spinning Koopa shell can have a "shell_spinning" state, or a Throw Block, as most sprites behave the same way when hit by a spinning shell or a throw block. Sprites that have collided with other sprites can determine what to do if the other sprite's state is a specific string, or act generally if it is not a state for which a special behavior must be used. When two sprites collide, both sprites will be informed of the collision so they can both do as they see necessary. The Goomba would be informed of a collision, check if the other sprite is in a state to kill the Goomba ("shell_spinning", "fireball", "iceball", "player_hammer", etc.), see that the other sprite's state is "shell_spinning", and knock itself off the stage, informing the level that it had been killed so the level could score points or 1-Ups. The Koopa would be informed of a collision, check the other sprite's state, see that it is not a state which would kill the shell, and continue spinning. The user must have no access to states, either by reading or changing them. All states will always use lowercase letters to avoid many unnessecary .ToLower calls all over the place.

For more information on sprite states, please see the Sprite State article.

Layers and Events
A layer is a named collection of sprites and tiles. An event is an action that a layer or object performs when a named object triggers something. The Layer class exposes the following fields and properties: Layers have a "position", but it's more of an offset. The position of every layer always starts at (0, 0). If, say, you moved the layer 20 pixels to the right (20, 0), every object in the layer would be offset by 20 pixels. Layers can also have a velocity and acceleration.

Layers can be moved, teleported (all objects in the layer are offset by a certain amount immediately), vanished (all objects in the layer are removed from view, don't update, and cannot be collided with), and restored (undoes any vanishing operation).

Event Scripting
Main article: Event Scripting

Triggers
A trigger is something that a sprite or tile does or has done to it that events might want to know about. When a trigger occurs (sprite is killed, for example), the sprite calls up to its owner Level instance with a string indicating which trigger occurred. Events will register for triggers on objects when scripts are parsed per a structure with two strings, one for the object's name and one for the trigger's name (subject to change). When the Level receives a trigger, it will check its registered trigger list to see if any events are interested, and if so, executes their script.

Players
The player is like a sprite; it has a graphics object, position, velocity, and responds to many of the same collision triggers that sprites do.Additionally, players respond to input events, such as the user pressing keys on the keyboard.

The player's response to tile and sprite collisions is mostly handled by the colliding sprite or tile, although collision handlers would be triggered on both sides.

Players have several different powerup states that modify their behavior, responses, and graphics. These powerup states will be separate types deriving from an abstract base type. A TransitioningPlayer type will also exist; this will be merely a graphics object with a position that plays an animation to switch between powerup states. The TransitionPlayer will store the Player to switch into once the animation is completed. The graphics object would be an AnimatedSingleUseGraphicsObject instance that triggers an event once it completes its animation.

Players expose the following properties, fields, and types:

Player Physics
In its simplest state, a player's physics is the continued addition of the velocity vector to the position vector. Changes in velocity are triggered by keyboard input, collision with objects in the world, or friction and gravity. Typically, velocity increases with keyboard input, decreases with no other action (except downwards with gravity), and decreases suddenly on collision with something.

The user can affect the player's velocity as follows:
 * Walking (Keys: Left/Right): The horizontal velocity is immediately set to a constant value. The player will walk in a direction at a constant speed until something stops him. If the left/right keys are released, the player quickly loses horizontal velocity (more slowly on ice) due to friction, and will eventually stop.
 * Running (Keys: Left/Right while holding Run): The player begins to walk at full walking speed, and accelerates over a short period to a maximum running speed. The player will then run at a constant speed until something stops him. If Run is released while Left/Right are still being held, the player will decelerate to walking speed. If all keys are released, the player will decelerate to a standstill. Stopping while running on ice will make the player decelerate much, much more slowly than on normal surfaces.
 * Jumping (Keys: Jump): The player will jump upwards at a constant velocity that varies depending on the player's horizontal velocity. The jump will continue until the player has jumped to his apex, which again varies by horizontal speed, or the user released the jump button. The player will always jump to a minimum height regardless of how long the jump button is held down. Gravity is not applied as the player jumps upwards.
 * Spin Jump (Keys: Spin Jump): The player will jump much like a normal jump, except the minimum and maximum jump heights are diminished. (NOTE: check if the heights are affected by horizontal velocity)
 * Duck (Keys: Down): The player will duck and stop walking or running. This can be used to slip beneath low ceilings, assuming the player's horizontal momentum is high enough that the player can slide beneath before friction stops him.
 * Wall Jump (Keys: Jump while sliding down a wall): If the player is not standing on a surface, but is colliding with a wall, the player will cling to the wall and slowly slide down it provided the user is holding the proper key down (e.g. if the player is near a wall on his right, the user should hold down Right). If the player presses jump, he will be pushed upwards vertically and in the other direction horizontally. Keypresses in the opposite direction that the player's facing _might_ be ignored for a short period after a walljump.
 * Ground Pound (Keys: Down while in midair): The player loses all momentum for a short period of time, plays an animation and sound, and then falls very quickly. Most sprites will be destroyed if the player lands on them. Certain blocks, such as brick blocks, will be destroyed if the player lands on them; others, such as the turn block, will behave differently. Item boxes will drop their item downwards. The player can cancel their ground pound after falling a certain distance if the player presses left or right.

These actions may be modified or amended by different players or powerup states.

Additionally, the player's velocity is ordinarily affected as follows:

- Gravity: A constant downward pull on all sprites. The player will accelerate downward to a maximum velocity provided that no other upward force is acting on him. Gravity is ignored when the player is standing on a tile, or when a player is jumping upward.

- Friction: This slows down the player's horizontal momentum when the player is standing on something. If the player is not walking or running, he will lose velocity to friction and slow to a stop. If the player is on an icy surface, friction will be much lower, and reduce the player's velocity much more slowly. Friction does not apply if the player is not standing on anything, therefore velocity will remain constant unless the user modifies it.