A flexible, convenient, simple and efficient architecture primarily for game development. It will get your game development up to speed quickly and allow your game to expand smoothly.
Kran provides nothing but an architecture that can be used for any type of game. All other decisions - like how to do rendering or physics - is up to the user. Kran can without problems be used in conjunction with other libraries.
Note: Kran is under heavy development, everything is work in progress.
[Try the crazy demo game with explosions and blood!] (http://paldepind.github.io/Kran/examples/circlebomb/)
Note: It only works in modern desktop browsers - currently only tested in Firefox and Chrome.
It's flexible: Kran gains most of its flexibility from the entity system architecture which it is an implementation of. Unlike the case with object oriented programming data isn't tied together with the functions that processes it. And you don't have to fit things inside an inflexible class hierarchy to share code. In Kran entities are created by composition rather than inheritance. They can be composed out of any combination of data components desirable and they'll automatically find their way to the functions that wants to operate on them. This allows for maximum flexibility and reuseability - nothing is tightly coupled, everything can be mixed to ones hearts desire.
It's effortless: Kran has a simple convenient API that makes common tasks very easy. It provides structure to your code so that you can worry about actually getting your game rolling without being hindered later on by inflexibility or a cumbersome design that makes further expansions hard. It has an event system that integrates with DOM events and makes using the pub/sub pattern straightforward. It shows you the way without getting in you way.
It's simple: We aren't kidding when we claim that Kran is a tiny library. We makes other so called tiny libraries look gigantic. Kran gives you an architecture and that's all. It has a tight focus. This means you can learn it quickly and easily get a complete understanding of how it works. It won't impact your page loading time in any noticeable way either.
It's efficient: Kran is designed from the bottom up with an efficient use of data structures and an API that doesn't introduce garbage during game runtime. Note however that Kran is in an early stage of development and the optimization isn't done.
In an entity system all data/state is stored inside components. Components
are tiny bits of tightly related data. It's a property/characteristic that
a thing can possess. That could be a position component, a shape component
or a color component. In Kran a component can be defined by passing a
constructor function to
kran is an instance of
var kran =var velocity = kran
Components with just one property can be created using the shorthand syntax shown below
var weight = kran
This is the same as doing
var weight = kran
We've now created two components. A velocity component and a weight component. We want to make all entities that has both speed and a weight to accelerated towards the ground. In other words we want to implement gravity. For that we need a system. Systems is were the logic that would be methods in OOP is put in an entity system.
That's all we have to do in order to make entities get attracted towards the ground! The system is automatically registered inside Kran, and now when systems are being run in the main loop the above system will automatically be run for every entity that satisfies it's dependencies.
The final thing we need to do is compose some entities that the system can
operate on. Fortunately it's super easy!
Kran.entity creates a new entity and
returns it. The returned entity has an
add method that as its first argument
takes the component to add. Further arguments will be passed along to the
components constructor function. It returns the entity to allow for chaining.
// Creates a new entity, adds two components to it and initializes themkran// This component is heavy and heading right towards the ground, might be a meteor ;)kran
Now we set up the game loop. This is what a simple game loop might look like in Kran (actually this is exactly what the demo game's loop look like):
The above simply runs all systems in order of creation. If more control is needed systems can be put into groups and ran like this:
That's all for now. Kran is still in heavy development and more documentation will be created in the future. As of now take a look at the source code of the example game for an example on how a game made with Kran can look like.
Note: The API documentation is still very rough and should be considered a draft.
A Kran "universe" is created by instantiating the Kran object.
var kran =
This "univers" contains a seperate collection of components, systems and entities.
Components are created with the
component function on a Kran instance. The
function supports three different ways of creating components. Either by
passing it a constructor function, a string or undefined.
The basic way of creating components is by passing
component a constructor
constr is a constructor function that initializes the component. Since
perfectly possible to add methods to component. That however is not proper
usage of a entity system and should probably never be done. The constructor
function gets passed the argument given when an instance of the component is
added to an entity.
var pos = kran
For creating a component with only one property
component provides a
convenient shorthand syntax. Simply call it with the name of the single
component as a string.
propertyName is a string and the above is identical to.
If one needs a component where only its presence if of concern (i.e. it doesn't
contain any changing data)
component can be called with no arguments
This creates a component that takes no initialization arguments and contains no properties. Kran will store it as a boolean internally.
Sysems are registered by calling
system method with an object describing the
systemObj is an object and can contain the following properties
components: A component id or an array of component ids that the function depends on.
pre: A function called once before the
everyfunction when the system is run.
every: A function being called once for every entity that has the component required by the component. As arguments the function is given the entities components followed by the entity itself.
everyexcept it is called after
arrival: Called whenever an entity not satisfying the system gets a component added making it satisfy the system. The components and the entity is passed as arguments.
When systems groups are created a function with the same name as the group will
be attached to
kran.system. It allows running all the systems in the group
in order of creation.
Alternatively all systems except those listening to global events gets added to
a special group named
all. Thus all systems can be run with
A new entity is created by calling the
entity method on a Kran instance. The
function takes no arguments. It returns an entity object.
var ent = kran
ent is now an entity object with no components. I.e. it's an empty container.
Composing entities is easy and consice. All the entity methods returns themselves to allow for chaining. Example:
Components are added with the
Entity#add method. The first argument to which
is a component followed by a variable amount of arguments that will be passed
along to the components constructor function if any.
Components are removed with the
Entity#trigger method is a convenience method for adding a component
and immediatly removing it again.
is equivalent to this:
The former is more consice and more clearly communicates the intention of
the addition and removal of the component. With this simple function and the
arrival hook in systems Kran implements gets and integrated event system
Kran has a concept of entity collections. These are collections of entities containing a given set of components. Kran will update these collections when needed as components are added to and removed from entities. Internally these entity collections are used by systems but they have other uses and thus they are also exposed in the API.