Sunday, October 23, 2016

Random #7 - attack of the view bots

This blog seems to be under "attack" by bots or something. For the last month I'm getting ten times more daily views than the average was. It started on September 30th. Every few hours the statistics shows a spike of 30 new views, and every day the same thing. The views are coming from USA, operating system is Macintosh and the browser is Chrome, but it shows no referring site or anything to pinpoint the source. It has made the statistics data completely useless.

Monday, October 3, 2016

Particle effects

Here is a video showing the updated particle system and editor, and some stuff that can be done with them.

It was all inspired by Unreal Engine particle system. Particle effects can contain several emitters and emitter and particle values are not just variables they are "modules" with "distributions" and stuff to control the values over time, etc. There are around 30 of these modules; emitter and particle lifetime, particle width, height, speed, direction, color, angle, number of particles on init/on update... Each effect, and even particles, can have dynamic light attached to them. Also, particles can be attached to a Box2D body, but then some of the functions wont work (particle position will be updated by Box2D and not by emitter functions). I also implemented ribbon and beam/line emitters.

Here is what you can see in the video:
- Fireworks - shows "nested" effects. Each particle can carry its own effect(rocket trail) and also can create a new one at the end of its life(explosion).
- Text - various line effects. The lightning effect uses a tilemap.
- Circles - nothing special, just a bunch of circular effects.
- Sparks - shows Box2D enabled particles. Particles change rotation and size based on velocity.
- Ribbons - ribbon effect can be attached to other particles or objects.
- Flamethrower - shows effect and individual particle lights, and also collision response (creating ground fire on particle-ground contact).
- Colored lights - shows particles with colored dynamic light.
- Paint explosions - shows creation of decals on contact on static and moving objects.
- Particle effect editor - shows how one effect can be made of several particle emitters.
- Leafs - shows direction change using a sin wave.


Updating, saving, parsing, then the editor code itself.... it's well over 5000 lines of code. It all became over complicated and confusing and I don't know does it even make any sense anymore, I just lack the knowledge to design such a complicated system. Quake 2D didn't even have a particle system, it was all hand made and hardcoded, and it still worked. I have been working on the particle effects until March and then completely stopped. Then fooled around with Abuse SDL and haven't coded since. I wanted to post this way back in March, but just didn't want to bother anymore.

Monday, May 9, 2016

Abuse 1996 - SDL port 0.9a

When I released my Quake 2D demo back in 2012 many people compared it to Abuse, a game by Crack dot Com released in 1996. While I was waiting for my new PC to get fixed(it took months!) I was stuck with a PC bought in 2005. I already played everything I could on it and my gaming options were limited. I found out Abuse was available for free, so I wanted to check it out. It ran in DOSBox at 320x200 resolution and felt like playing a FPS game with very low FOV. Aiming with the mouse was very difficult, because even in fullscreen the mouse was still behaving like it was 320x200 resolution and was too sensitive.

Reading the included readme file I saw there was a high resolution option, but it seemed to be only available in the shareware version or in editor mode, and the game would automatically turn off the in-game lights, because it would be too demanding for the PCs in 1996 on high resolutions. Not to mention a bug would cause the entire screen to go black the second time a level was loaded. While looking for a fix I found out the original source code was released and there were several source ports released during the years, mostly for Linux. Finally Xenoveritas SDL2 port from 2014 showed up in the search results and was exactly what I needed; a working Windows port, plus it had instructions how to build it.

After I enabled custom resolutions and fixed the light, I also wanted to extract the textures, so I can use them in my own engine. Then I saw Xenoveritas never finished adding Xbox controller support, so I did it instead... it didn't stop there, and here is the final result in motion:

As you can see the game gets pretty intense. It's a classic design where you need to find switches to open new areas, and you need to cleverly use security turrets and destructible walls to fight the enemies. It takes 2-3 hours to beat the game.

 Here is the list of updates in Abuse SDL 0.9a compared to Xenoveritas version from 2014:

- Enabled custom resolutions and enabled lights on high resolutions
- Re-enabled OpenGL rendering to enable vsync
- Game screen scaling in window and fullscreen mode using F11 and F12
- Enabled some high resolution images from the 1997 Mac OS release
- Fixed level music not being played correctly, added "victory" music in the end game screen
- Fixed the health power image, fixed mouse image when choosing initial gamma
- Added or re-enabled various settings in the config file (borderless window, grab input, editor mode, high resolution images...)
- Local save game files and configuration files
- Quick load using F9, quick save using F5 on save consoles
- Added cheats via chat console: bullettime, god, giveall, flypower, sneakypower, fastpower, healthpower, nopower
- XBox360 controller support with rebindable buttons
- Updated abuse-tool so it can extract the images in Abuse SPEC files to modern image formats as individual images, tilemaps or a texture atlas with information about image, tile and animation frame sizes and positions

I only tested the game on my old 2005 PC and the new one, running Windows 32bit and 64bit. I would really appreciate some feedback, so I know it works or not. I would also like to know how playing with the Xbox controller feels, since I plan to use the same controls in my own engine. Please read the included README file for more information, controls and links to previous port releases and other stuff. You can download the game from this link or on ModDB:

md5: 16E116B753A2142E4AE2BB63C2A4A351

I already mentioned I wanted to extract the images, so here is an archive that contains all the extracted Abuse images in PNG format, together with information about image name, size and positions of individual frames of animation: 
 Aliens addon

md5: 5A2D1E65A2D76C6C0D340F600E2F7B5B

I also used a HMI to MIDI converter to convert the music to MIDI. I didn't convert them to wav or mp3, because different soundfonts give different results when playing MIDI music. You can download the MIDI files here:
md5: 5FC937F71DB047DA9E46961F83016CDA

The source code for Abuse SDL port 0.9a is available on my GitHub page. As I said the game is not fully tested and there are few issues which are described in the README file. The game physics are locked at 15 FPS, and the rendering is a bit slow, those are two major things I would like to eventually fix. Multiplayer doesn't work, but that is way out of my league:

Thank you for playing Abuse!

Saturday, April 9, 2016

Texture packing algorithm

I was exporting some textures from an old game, and needed an algorithm to pack many small textures into a texture atlas. I found a very nicely explained algorithm on this page and wanted to share, if someone might need something like this:

There are some other interesting articles from the same guy here:

The packing algorithm is so simple, I didn't think it would work. You just create a node with the output texture size and loop trough your images and call Insert() with individual texture's width and height. The node recursively splits itself if its size doesn't match the input, and calls Insert() of the child nodes. The node that gets returned holds the final [x,y] position, and if it returns NULL it means the image couldn't fit.

The grey lines mark individual textures and animations that I grouped together in code, so it doesn't all get mixed, but that is another story.

Tip 1.

In the example above I sorted my images according to their size(width*height) before I started to call Insert().

Tip 2.

If you look at the examples from the link, you will see the images are stored in an upside-down L pattern starting from top left, so if your output image is too big the input images will be positioned in the L pattern and the rest of the space(bottom right) is left unused. To avoid that;
- I sum the size of all the textures and set node width and height to sqrt(sum), so I have a minimum square output.
- Then I check if some image has width higher than that, if so I take that value for the final node width, so it can fit.
- The final height is some arbitrary huge value. While calling Insert() I keep track of where the bottom corners of the images end up and take the maximum value when creating the actual output image, which, after all this mess, should be more or less a square.


Here is my implementation in C++ to spare you 2 minutes of converting the pseudocode. Unfortunately Blogger doesn't have code tags or something to format it properly.

#include <vector>

class AR_Node
    std::vector<AR_Node> child;    //child nodes
    int x, y, w, h;                //position and node size
    bool image;                    //image stored in the node

    AR_Node* Insert(int img_w, int img_h);

        this->x = y = w = h = 0;
        this->image = false;

AR_Node* AR_Node::Insert(int img_w, int img_h)
    //if we are not a leaf then
        //try inserting into first child
        AR_Node *newNode = this->child[0].Insert(img_w,img_h);
        if(newNode!=NULL) return newNode;

        //no room in first child, insert into second
        return this->child[1].Insert(img_w,img_h);
        //if there is already a image here, return
        if(this->image) return NULL;

        //if image doesn't fit, return
        if(this->w<img_w || this->h<img_h) return NULL;

        //if we're just right, accept
        if(this->w==img_w && this->h==img_h)
            this->image = true;
            return this;

        //otherwise split this node and create some children

        //decide which way to split
        int dw = this->w - img_w;
        int dh = this->h - img_h;

            //vertical split           

            this->child[0].x = this->x;
            this->child[0].y = this->y;
            this->child[0].w = img_w;
            this->child[0].h = this->h;
            this->child[1].x = this->x + img_w;
            this->child[1].y = this->y;
            this->child[1].w = this->w - img_w;
            this->child[1].h = this->h;
            //horizontal split

            this->child[0].x = this->x;
            this->child[0].y = this->y;
            this->child[0].w = this->w;
            this->child[0].h = img_h;
            this->child[1].x = this->x;
            this->child[1].y = this->y + img_h;
            this->child[1].w = this->w;
            this->child[1].h = this->h - img_h;

        //insert into first child we created
        return this->child[0].Insert(img_w,img_h);

Tuesday, April 5, 2016

Random #6 - Youtube channel statistics

This January my YouTube channel exploded ! Well, at least one video did. My "The Bloodcrafter - Minecraft 2D shooter" video is getting in average almost 1000 views DAILY, and is rapidly approaching 400 000 views, with the channel surpassing 500 000 total views. If I were monetizing this I might have made enough money to buy the actual game :/

Other videos are not that successful, and the total view count of all the videos I uploaded in the last two years is only around 15 000, and that number would be much, much lower if Bloodcrafter wasn't attracting so much attention to the channel.

Since the most popular videos are based on Minecraft, Serious Sam and Quake, and with so many views in the period of over 5 years, the channel statistics are worth looking at to see some trends. I think it would make sense to say that the viewer demographics represent the actual player base.

The most significant change in the last 5 years is how Minecraft has become more popular among female players. In the first year(2011-2012) only 5 percent of players were female, and the data from last year (2015-2016) shows it is currently at almost 40%.

The percentage of Serious Sam female viewers/players jumped from 5% to around 16%. Quake 2 continues to be a "man's" game, probably because 90s girls weren't interested in it, and new generations don't even know about it, since the series is dead since 2005. But, looking at Serious Sam, which is a similar game, the new entries don't help much. Serious Sam continues to be most popular in Eastern Europe.

Other videos share the same faith like Quake, it's such a sausage festival that YouTube doesn't even want to display the statistics and it shows an error. Since most of them are about video game development, and are shared on some game development and gaming forums, my conclusion would be that we wont see a rapid increase in the number of female game developers any time soon... unless it is forced.

Another sad statistic is Linux. I only have the data starting from January 2013, and they show only 1.3% of PC viewers are on Linux, and 1.8% use Mac. The stats from this blog are a bit more positive, where 5% of readers are on Linux, and 5% on Mac (but these are overall numbers, not just for PC).

Monday, December 21, 2015

Particle emitters #3

I think it is the third time already that I am rewriting my particle system. There is always some effect I want that is missing; lightning, velocity based deformation, pulsating size or color, physics...

Look at how many variables there are already ! And just when I thought I was done, I realized everything is flawed AGAIN. It's the randomization of values ! Those also need more control, so they can change like a sin wave, or linearly, or randomly, or in discrete values...

Tuesday, December 8, 2015

Dynamic 2D light and shadows

This video shows my dynamic 2D light system based on Box2D (nothing to do with Box2DLights library) and Clipper:

This is how it all works:
- light is a textured quad/polygon
- Box2D is used to get all the sprites inside the light polygon by either using light as a sensor, or using b2World::QueryAABB()
- for convex shapes visible edges are calculated using a dotproduct of light and edge normals
- for concave shapes(which can only be chains in Box2D) all edges are considered visible
- shadow polygons are created by extending visible edges
- using polygon clipping library called Clipper a "difference" operation is performed between the light polygon and shadows to get the final light polygon
- UV mapping is performed on the resulting vertices
- the resulting polygon is rendered as a GL_TRIANGLE_FAN

No raycasting is performed, which you usually find in tutorials.

The "depth" mask uses the green channel to mark which pixels should be illuminated, and for the intensity (ex. transparent smoke should be illuminated less than a solid surface). Blue channel is used for depth, and works basically the same. It's not perfect, but I can get some nice effects with it.

Soft shadows are generated by rendering the lights on a FBO smaller than the screen size and rendering it with a blur shader.

Wednesday, November 25, 2015

Depth mask

I realized that, since I am rendering a mask to use it for light rendering I could as well render it in different color values and use it as a depth mask too. Layers that are further away are rendered in darker tones of the color for the mask, and when I use multitexturing to mix the mask and light FBO I multiply the final light values with the values of the mask and get light with different intensity: