# Expressing "2.5D" spaces with Cocos2d-x

## Background

These days, the terms of "dimension" is not limited to vector spaces -- in Japanese internet slang, "2.5D girls" refer to girls rendered using 3DCG. As a matter of fact, you can actually formally define dimensions that aren't integers -- fractal dimensions are in general irrational numbers.

I got a bit off track. This article is about expressing "depth" with Cocos2d-x.

Cocos2d-x is a game engine for 2-Dimensional games, as its name implies. However, with just a little extension, we can achieve "depth" expression -- I will introduce such an extension in this article.

The technique that we will use is "Perspective View Transformation" often used in 3DCG literature. We will scale our sprite images according to the coordinate in the depth direction, by which we achieve a virtual "depth" experience.

## Objective

In this article, we consider the two coordinate systems Screen and World shown in the figure above. The Screen coordinates denote the position of the sprite on the screen, where the World coordinates denote the position of the model defined in the virtual world of our game.

We have conventionally used the cocod2d::Point class to specify the position of the sprite to be rendered. Here, we will implement its subclass PointWithDepth for our depth expression. Our objective is to implement a mapping such that by specifying the World coordinates through the PointWithDepth::SetWorldPosition method, the corresponding Screen coordinates are obtained through the cocos2d::Point (up-casted) class, and the scaling factor by the PointWithDepth::GetScale method.

## Transformation

The perspective view transformation onto the xy-plane is obtained by the following equation:

$\dpi{300}&space;\begin{bmatrix}&space;X&space;\\&space;Y&space;\end{bmatrix}&space;=&space;\frac{1}{z-z_\mathrm{e}}&space;\begin{bmatrix}&space;z_\mathrm{s}-z_\mathrm{e}&space;&&space;0&space;&&space;\left(z&space;-&space;z_\mathrm{s}&space;\right&space;)&space;x_\mathrm{e}&space;\\&space;0&space;&&space;z_\mathrm{s}-z_\mathrm{e}&space;&&space;\left(z&space;-&space;z_\mathrm{s}&space;\right&space;)&space;y_\mathrm{e}&space;\end{bmatrix}&space;\begin{bmatrix}&space;x\\&space;y\\&space;1&space;\end{bmatrix}$

By introducing the infinite-point ( $\dpi{300}&space;z&space;\rightarrow&space;\infty$ ), we can simplify the definitions of the constants:

$\dpi{300}&space;\begin{bmatrix}&space;X&space;-&space;X_\infty&space;\\&space;Y&space;-&space;Y_\infty&space;\end{bmatrix}&space;=&space;\frac{z_s&space;-&space;z_e}{z-z_\mathrm{e}}&space;\begin{bmatrix}&space;x\\&space;y&space;\end{bmatrix}$

Things that are farther away appear smaller. The scaling factor $\dpi{300}&space;S$ for such an effect is calculated according to:

$\dpi{300}&space;S&space;=&space;\frac{\partial&space;X}{\partial&space;x}&space;=&space;\frac{\partial&space;Y}{\partial&space;y}&space;=&space;\frac{z_\mathrm{s}-z_\mathrm{e}}{z-z_\mathrm{e}}$

## Implementation

Before implementing the feature in this article, we have conventionally specified the position of the character as follows:

character->setPosition(cocos2d::Point(x,y))


We can naturally extend our code for this feature by defining the following class:

class PointWithDepth:public cocos2d::Point{
...
void SetWorldPosition(float local_x,float local_y,float local_z){
m_scale=(Z_S-Z_E)/(local_z-Z_E);
cocos2d::Point::x=X_INF+m_scale*local_x;
cocos2d::Point::y=Y_INF+m_scale*local_y;
}
float GetScale(void){
return m_scale;
}
private:
float m_scale;
};


Using the PointWithDepth class, we can specify the character position and scale factor based on the World coordinates $\dpi{300}&space;\left(&space;x,y,z&space;\right)$ :

PointWithDepth point;
point.SetWorldPosition(local_x,local_y,local_z);
character->setPosition(point);
character->setScale(point.GetScale());


Our implementation allows us to express perspective-transformation-like effects with 2-Dimensional libraries. The figure below illustrates our output.

## Conclusion

By adding just a few lines to a class that represents a point in a 2 dimensional space, we can now express our sprites in a 3 dimensional space.

You can probably apply the trial & error method and adjust some parameters to achieve the same kind of expression. However, I think we should always think systematically and mathematically before writing any kind of code -- it's the only way to assure code quality.