Getting Started With Crafty: Entities

In the last tutorial, you learned about the basics of entities and how they are the building blocks in your game. In this tutorial, you will go beyond the basics and learn about entities in more detail.

Getting Started With Crafty: Entities

Entities and Their Components

Every entity is made up of different components. Each of these components adds its own functionality to the entity. Crafty offers a lot of built-in components, but you can also create your own custom components using Crafty.c().

You learned about a few basic components like 2D, CanvasColor, and Fourway in the first tutorial. Let’s begin by creating another entity using these components:

var playerBox = Crafty.e("2D, Canvas, Color, Fourway")
    .attr({ x: 50, y: 50, w: 50, h: 50 })
    .color("black")
    .fourway(200);

When you have a lot of entities with different components, it might become necessary to know if a given entity has a specific component attached to it. This can be accomplished by using the .has() method.

Similarly, you can add components to an entity by using .addComponent(). To add multiple components at once, you can pass them as a string with different components separated by commas or pass each component as different argument. Nothing will happen if the entity already has the component that you are trying to add.

playerBox.addComponent("Jumper, Gravity, Collision");
playerBox.addComponent("Jumper", "Gravity" , "Collision");

You can also remove components from an entity using .removeComponent(String Component[, soft]). This method takes two arguments. The first one is the component that you want to remove, and the second argument determines whether the element should be soft removed or hard removed. Soft removal will only cause .has() to return false when queried for that specific component. A hard removal will remove all the associated properties and methods of that component.

By default, all components are soft removed. You can set the second argument to false to hard remove a component.

Setting Values for Different Attributes

You will probably need to set different values for specific attributes of all the entities in your game. For example, an entity that represents the food of the main player in the game should look different than the entity that represents the player itself. Similarly, a power up is going to look different than food entities. Crafty allows you to set the values of different entities in a game either separately or all at once using .attr().

The main entity is currently stored in the playerBox variable. So you can set value of different properties directly using the following code:

playerBox.x = 50;
playerBox.y = 50;
playerBox.z = 2;

playerBox.attr({ x:50, y:50, z:2 })

The z property sets the z-index of different entities. An entity with higher z value will be drawn over another one with a lower value. Keep in mind that only integers are allowed as valid z-index values.

Let’s create a food entity with smaller size, a different position, and rotation applied to it. The rotation is specified in degrees, and using a negative value rotates the entity in counterclockwise direction.

var foodBox = Crafty.e("2D, Canvas, Color, Food")
    .attr({ x: 150, y: 250, w: 10, h: 10 })
    .color("red");
  
foodBox.attr({ z:1, rotation: 45 });

As you can see in the demo below, both the food and main player are easily distinguishable now. If you try to move the main player over the food, you will see that the food is now drawn below the main player because of a lower z-index.

Binding Events to Entities

There are a lot of events that you may need to respond to while developing a game. For example, you will have to bind the player entity to a KeyDown event if you want it to grow in size when a specific key is pressed. Crafty allows you to bind different entities to specific events using the .bind() method. Here is an example:

playerBox.bind('KeyDown', function(e) {
  if (e.key == Crafty.keys.T) {
    this.alpha = 0.5;
  }
  if (e.key == Crafty.keys.O) {
    this.alpha = 1;
  }
});

In the following demo, try moving the player over the food and then press the ‘T’ and ‘O’ keys. Pressing ‘T’ will set the opacity of the player to 0.5, and pressing ‘O’ will restore the opacity back to 1.

Now, let’s bind a collision event to our player so that it grows in size whenever it hits food. We will have to add a collision component to the player and use the .checkHits() method. This method will perform collision checks against all the entities that have at least one of the components that were specified when .checkHits() was called.

When a collision occurs, a HitOn event will be fired. It will also have some relevant information about the hit event. A HitOff event is also fired once the collision ends.

playerBox.checkHits("Food")
  .bind("HitOn", function(hitData) {
    this.color("green");
    this.w = this.w + 3;
    this.h = this.h + 3;
  });

The width and height of the player increases each time a hit occurs. We can use this event for a lot of things including changing the position of food or increasing the score in the game. You could also destroy the food entity by using the destroy() method once the hit was detected.

Making a Selection

In the previous section, we had to just change the properties of a single entity. This could be done easily by using the variable assigned to each entity. This is not practical when we are dealing with about 20 different entities.

If you have used jQuery before, you might be familiar with the way it selects elements. For example, you can use $("p") to select all the paragraphs. Similarly, you can select all entities that have the same common component by using Crafty("component").

Here are a few examples:

// Select all entities that have the Gravity component
Crafty("Gravity");

// Select all entities that have either DOM or Canvas component
Crafty("Gravity, Jumper");

// Select all entities that have both Gravity and Jumper component
Crafty("Gravity Jumper");

Once you have the selection, you can get the number of elements selected using the length property. You can also iterate through each of these entities or bind events to all of them at once. The following code will change all food entities whose x value is greater than 300 to purple.

Crafty("Food").each(function() {
    if(this.x > 300) {
        this.color("purple");
    }
});

Once you have a selection, you can use get() to obtain an array of all entities in the selection. You can also access the entity at a specific index using get(index).

Final Thoughts

In this tutorial, you learned how to add or remove components from an entity. You also learned how to select entities with a given component or components and manipulate their attributes and properties one by one. All these things will be very useful when we want to manipulate different entities on our screen based on a variety of events.

If you have any questions about the tutorial, let me know in the comments.