Categories

Thursday, 19 March 2015

Brightness and flickering effect

This week's blog post is about the visual effects used on the flare in the game and how it was created using the built in functionality in the SFML. Namely the scaling functionality for SFML's sprite. This method was used because it was convenient and time saving to use the inbuilt functionality instead of programming it by my self. It was also probably better because it has been developed by the SFML community.

the shrinking sprite
To create the shrinking effect of the light the sf::sprite.SetScale() function was used. SetScale() takes two float variables as arguments, x scale and y scale, which are basically multipliers for the width and height of the sprite. This means that if .5 is put in as argument for x the sprite's width will shrink to half it's size and if 2 is put in, the width will increase to the double of the original width. To shrink the sprite over time with this function a variable that represents how much burning time is left on the flare before it extinguishes, can be used. The flare's lifetime is defined by a variable and in the update function a variable increases with the time since the last time the update function was called. Using these two variables we can get the normalized value of how much of the burning process has taken place. This is done by dividing the currently burned time with the total possible amount of burning time. The value given by this division can not yet be used in our set scale because if we used this value the scale would begin at scale 0 and grow towards scale 1. What is wanted is the opposite of that, so to make it shrink instead of grow the inverted value of this is needed, which can be obtained by subtracting the value from 1. This will invert the value and what is left is the normalized value of how much time is left. This value can be put into the setScale() with the effect of shrinking the light sprite according to how much burning time is left.

the randomness
The decrease of light was only a part of the effect that was sought. It was also sought an effect that would make the flare look like it was flickering. To achieve this a random number generator was used. The random number generator was used because it has a potential to do things inconsistently and a flickering light is just that, a light with inconsistent brightness. The random number generator was set to generate a number between 0.9 times the normalized time left and the normalized time left. This gives the light a random brightness every frame between maximum brightness and a bit bellow the maximum brightness which resulted in the wanted flickering effect.

Thursday, 12 March 2015

Collision checking part 2 of 2

This is part two of the collision implementation of our game Ambient Pressure. See last blog post. This blog post is about the lagging issue that was solved by putting multiple Wall blocks into bigger blocks.


It was observed that there was a drop in performance. The reason for the drop was thought to be due to the collision handling code being too expensive (taking too much time for the computer to execute). We thought this was the case because such drop of performance had not been observed before the collision was implemented and the the extensive amount of collision checks we saw was required suggested this was the case.

The lines represents collision checks between the player the wall blocks.


After consulting our tutor he suggested a method to reduce the number of computations needed with the potential of reducing lag. The method was to minimize the amount of collider shapes created in the game by replacing the individual wall blocks with fewer but bigger collider rectangles spanning over the area of multiple adjacent wall blocks.

Following our tutors suggestion an rectangle finding algorithm was created for the map creating text file.

This is how our map look inside our text file:

1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,2,2,1,1,1
1,1,1,1,1,1,1,1,0,0,0,0,0,0,5,0,0,2,2,1,1,1
1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,0,2,1,1,1,1
1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,2,2,2,3,2,8,0
1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,2,2,2,2,2,8,0
1,1,1,1,1,1,1,1,0,0,0,1,1,1,1,1,1,1,1,1,1,1
1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,1,1,1
1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,6,0,0,1,1,1
1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,1,0,0,1,1,1
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,1,1,1
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,5,0,0,7,1,1,1
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1
1,1,1,1,1,1,0,0,0,0,0,0,1,1,1,1,0,0,1,1,1,1
1,1,1,1,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1
1,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1
1,4,0,0,0,0,0,0,0,5,0,0,1,1,0,0,0,9,0,0,1,1
1,0,0,0,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,1,1
1,1,1,1,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1
1,1,1,1,1,1,0,0,0,0,0,0,1,1,1,1,2,2,1,1,1,1
1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,2,2,1,1,1,1
1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1
1,1,1,1,3,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1

The 1's represents walls, the 0's represents open space the other shown numbers represents other specific in-game objects like pickups, enemies, the player spawning point, etc.

The following algorithm was chosen for this purpose because it was practical to implement and was thought to give us the result aimed for.

The algorithm works by reading the text file as a two-dimensional map of integers. The algorithm Goes through all positions of the map one row at a time until it finds a 1 representing a wall block.

When a wall block is found the algorithm starts to define a collider rectangle. In this stage it is currently known that the collider rectangle at least has the width and height of one wall block.

After this the algorithm tries to find the biggest formable square shape, consisting of only wall blocks, downward and right from the first found wall block by looking at all of the adjacent coordinates both below and to the right of the biggest currently found square block. When ever there is a wall block adjacent to the square one block below or one block to the right of the collider square that is not a 1 the search for bigger square sizes ends.

When the biggest square is found the algorithm goes into a new state where it tries to find the biggest rectangle rightward. It follow the same principles as last state with the difference that it is now only checks rightward and that if anything other than a 1 is found in the first step it goes over to searching for a the biggest rectangle downwards instead.

When the biggest possible rectangle is found by this algorithm the algorithm creates a collider of that size.

Implementing this algorithm gave the result aimed for:


This might not be the most efficient way to optimize tiled based collision blocks. It was just a quick solution that optimized the collision checking significantly. It may also be compatible with other two-dimensional collision checking optimizations such as these quadtrees which could increase collision performance even more.


Thursday, 5 March 2015

Collision checking part 1 of 2

This weeks post will be about my attempts to implement collision in our game.What was aimed for this week was to implement a collision system between the player entity and the walls in the game. To achieve this, a method for checking if shapes are overlapping is needed and a method of adjusting back the position of the overlapped objects in the right direction so that they are no longer intersecting.

example of  drawn collision shapes


Fortunately for us our tutor had uploaded an example for how to handle collision between two types of shapes. A axis aligned bounding box and a bounding circle. Basically the shapes are defined by a center point and a size. The size of the circle is a number defining its radius and the size of the box is defined by numbers representing the width and height from the center.

The shapes chosen for collision was a circle for the diver controlled by the player and boxes for the walls. The circle was chosen for the diver firstly because if it instead would have been a axis aligned box around the player, the corners of that shape could have collided with the walls collision shape without them visually even being close to a collision, and secondly because the diver will be rotated so that the head points towards the direction the diver is swimming in and thus we want the collision to be the same in any given direction. We were thinking about having multiple circle colliders with a specified relative rotation and distance from the player's center placed on the most important parts of the diver's sprite to get a more realistic collision, but we are going with one bigger circle from the center because we think it will be easier to implement and less resource heavy for the computer.

Unfortunately I have been having trouble understanding the code examples and to come up with a way to implement it because it was a hard coded example with collision checking between only two shapes and not 100 blocks or so simultaneously that our maps contain. Until now I have only managed to draw the collision shapes out and not check the collision between them, but only doing that the game started to lag because there are so many new shapes created and drawn out every frame.

So for the next week I will try to implement the actual collision as well as some optimizations for collision checking so that things do no longer lag.