Client graphics

This describes how graphics is created on the client side. That involves position recalculation from world to screen coordinates, calculating shifts towards pivot points, and more.

This is sub-layout for documentation pages

This was last updated when game had version: dev - 2.0.2

1 Introduction

The task of displaying content on player's screen boils down to convert world coordinate to the screen coordinate with respect to camera position.

2 Definitions

In order to be able to explain this topic, let's start with some definitions:

2.1 Real world position

Is position that is maintained on bot server side and client side (and server sends it to client). It respects the cartesian plane coordinates, and server sends these positions only (when objects are moving), for all objects in game world. Each game object has this type of position, and there is no exception what so ever!

2.3 Virtual array index position

Referred to as VAI, this is in depth explained in position modulation), however, brief idea is, that VAI is a real world position, but modulated to a virtual grid coordinates

2.2 Screen position

Aka client position is position of mouse with respect to the screen.
By retrieving mouse position, you get client position The retrieved position is in following format:

\(pos(x,y) = [X, Y]\)


\(X \in [0, screenW]\)
\(Y \in [0, screenH]\)

which means, that \([0,0]\) is the origin of the screen, and is the upper left corner of screen (or HTML element)

2.4 Draw position

Is simply position, at which we draw target texture (or element)
If the position would be \([0,0]\), the texture would be drawn in upper-left corner of the screen / canvas.
The position, however, can be outside of range of screen, meaning that the texture will be overflowing outside the user's screen

2.5 User's camera

Is object, which is telling at what subarea of world is player looking at.
Mathematically, it is point in game world, which will be always displayed at centre of user's screen.
The position of camera is always in real world position.
According to that point, the real world position is converted to screen position and vice versa

3 Input from server

Server sends to client positions in real world position, or alternativelly in VAI (explained in position modulation)
In case where VAI is sent, client uses function to compute the real world position.

4 Creating function for mapping World position to Draw position

The task is, given camera position, object's real world position, get object's draw position, such as the object will be displayed correctly with respect to the camera.

However awful this might sound like, the implementation is even more awful, trust me.

We calculate shift \(S=(s1, s2)\):
\(s1 = -1 * c_{x}\)
\(s2 = c_{y}\)

We move the shift point to the centre of screen / canvas:

\(S = (s1 + \frac{S_w} {2}, s2 + \frac {S_h} {2})\)
Notice that for \(y\), the value is added, not subtracted, as we are now in draw position (which is fourth quadrant of cartesian plane coordinates), not in full cartesian plane coordinates!

The shift position \(S\) will be added to all drawn entities's positions as follows:
Suppose we want to draw object with real world position
\(R=(r1, r2)\)

Then, the coordinate passed to the draw function will be: \(I=(r1 + s1, -1 * r2 + s2)\)

When drawing object on position \(I\), the object will be displayed correctly with respect to camera.

Note: You might notice, that \(y\) coordinate of \(I\) was multiplied by \(-1\).
The reason for that is, that draw position is in fourth quadrant of cartesian plane only!

Having calculated the shift \(S\), it has to be recalculated only if the object we are following with camera (or camera's position) changes.

5 Displaying object of some size in centre of screen

Having some object of some size \(S=(x, y)\), if we want to display it at centre of screen, the same approach as above is used, however, the half of size must be subtracted / added to final draw position in order to display centre of object on centre of screen.

Suppose that final draw point was calculated, and we have: \(I=(i1, i2)\)

Then, in order to display object at centre of screen with respect to size \(S\):
\(I=(i1 + S_x, i2 - S_y)\)

Here, \(y\) coordinate is subtracted, and it is because draw position is in fourth quadrant of cartesian plane only

6 Draw optimaliazation

Allthough performance and optimalization of client side is not first priority, there are some things that just must be optimized in order to guarantee smooth run.

Before an entity is drawn, check is done on client side, whether the entity rectangle (or some desired aproximation shape) would collide the camera viewport rectangle at all.
If so, then entity is drawn. Else, the draw function is not called, saving a lot of performance

7 Blender

7.1 Notes

This contains notes about blender that I used frequently, and this serves as a nice lookup.

7.2 Shortcuts
Shortcut meaning Shortcut
Connect 2 vertices with edge (or faces) F
Parent object to another object CTRL + P
Merge vertices ALT + M
Change pivot point of object CTRL + ALT + SHIFT + C
Clear parent ALT + P
Cursor to selected SHIFT + S
Toggle quad view CTRL + ALT + Q
Add bone constraint with target (in pose mode) CTRL + SHIFT + C
Scale to zero S + (X/Y/Z) + 0
Copy mirrored bone pose CTRL + SHIFT + V
With finished rig, how to change the rest pose to a new rest pose Go to pose mode, and set a new pose for new rest pose.
For all deformed objects, apply the current armature modifier.
Pose > Apply > Apply pose as rest pose
For all previously deformed objects, deform them to this armature again
Weight paint, select the bones Select an armature, and go to the pose mode.
Shift select an object you want to weight paint (in pose mode!)
Go to weight paint mode
A to delselect all
You can now weight paint. To select a bone, use SHIFT + LEFT MOUSE CLICK on a bone

8 Concrete realizations

This section focuses more on how were exact elements drawn.

8.1 Sprite depth
Please navigate here for explanation
8.2 Wall

Walls are drawn using tile approach, same as floortiles.

8.2.1 Display opacity

The goal is to make wall see-through, when some character is behind it, preventing players to hide behind walls.
This is solved purely on client side.

8.2.2 The method

Every single time when character's position is changed (as a result of the message being received from server), the system checks, whether the VAI index would change. If yes, then the map is notified, and all wall segments that are relevant are notified as well.
Like this, the wall pieces are drawn at reduced opacity

It can be a heavy computation task. However, it is done on the client side, so it is not such a big deal

9 Blend modes

Blend modes are discussed here