Thursday, February 27, 2014

The almost finished player's field of view, finally

One of the most, if not the most important mechanics in our game is that the player have no vision behind walls. I've had the task of writing this code the past few weeks now, and I'm happy to say I've finally solved it. As you can imagine there have been a few problems along the way and I will explain everything here in detail.
Early mockup of the shadow system

Before I talk about anything else, I want to make this clear: what exactly was I supposed to do?
Shadow system the we decided not to use.
   In the early development of our game we discussed how exactly the lighting system should work. We talked about making the player just barely be able to see behind walls, that way the observant players wouldn't be surprised when walking around a corner and only to be shot by a guard. However this was voted against and instead we added a sneak system where if the player is sneaking he can see nearby sounds, like footsteps of patrolling guards.
   We also considered only giving vision in a cone in front of the player rather than everything around him, this was also down voted leaving me with a definite task: make everything behind walls pitch black (except for sounds when the player is in stealth).

For the prototype it was more emphasis on getting a working solution rather than a good solution, so I thought of the easiest solution I could find. At the time I worked in SDL and had only used the draw line method and nothing else, so my solution was this:
  • I have the player's position.
  • I take a pixel on the edge of the window and call it point.
  • I take a pixel and set its position to the player's position. I move it one pixel closer towards point until it hits a wall or arrives at point. When it hits a wall a line is drawn from its position to point.
If this doesn't sound too bad, let me explicate. When the player stands inside a wall this method compare values this many times: screen width * 2 + screen height * 2. For a window with the dimensions 1024x768 this is 3944 times it has to check for walls and draw lines. If there are no walls on a map this method runs a while loop around 450 times more times, almost 2 million times each update that is. This caused the game to run significantly slower even if there wasn't even one wall on a map that was 512x512 pixels in dimensions.

For the real thing I had to figure out a much better solution, so my first thought on the problem was to draw one black shape for each wall after everything else, except sound, had been drawn. Each shape would cover the area behind the wall from the player's position.This is a simple solution in theory but it has one big flaw, if I set an opacity on each wall making them see-through there would be darker areas where two walls cast their shadows. Back then we hadn't decided whether the player could see faintly behind walls or not so I had to think of another solution were overlapping walls didn't cause darker shadows.
   I came up with an idea that there was only one big shape that was drawn. It would be defined from taking all wall edge points and see if the current point is in front of the previous and the next, if so, then it should be included, otherwise it should be discarded. I didn't think to much on this since we decided quickly on having no vision behind walls.

Now it was time to get the shadows correctly.
  1. At first I created a shape with four points. The first two points were always the same, the start and end points of the wall. The third point, the point after wall end, was going to be the point on the edge of the screen which if a line was drawn between it and the player's position, it would go through the wall end. I called that point the edge end. The fourth and final point was the edge start which was similar to edge end except it went through the wall start instead.
  2. I realized quickly that this wasn't enough if the shadow hit a corner. At this point I thought a lot on two different possible solutions to this specific problem. The first one being to simply extend the two edge points beyond the screen thus creating a large quadrilateral. The second one was to find the corner and set another point there. I liked the second solution better since it was a neater solution and I believed it shouldn't be too hard.
  3. So I changed the shape to have five instead of four points. If the shadow didn't hit a corner, the now fourth point would have the same position as the third point, edge end. I moved the edge start to position five since the corner point had to be between the both edge points.
  4. I believed I was finished here but before I could program too much I realized that the shadow could hit two corners, so back to thinking again. I had already decided on this specific solution so not much was needed to change. I added one more point to the shape and moved the edge start to position six to let the second corner come between it and the first corner. Then I got to the programming bit.
In the wall constructor I set the shadow to have six points and a fill color of black. Then I set the first two points to wall start and wall end.
   In the update I set the remaining points depending on the player's position. I first calculate the two edge points, then I use those points to calculate the corners.

To get the point on the edge of the screen was fairly straight forward. I first calculated the unity vector from the player's position to the specified wall position. I took the unity vector and calculated how many steps it had to go to reach the edge of the screen in both x and y-axis. Then I multiplied the unity vector with the smaller distance of the x and y value. Lastly I returned the walls position plus the vector, which is the position of the point on the edge of the screen.
   For example: the player's position is x = 138 and y = 88. The wall position is x = 128 and y = 128. The unity vector from the player's position to the wall position is then: -0.24 in x-axis and 0.97 in y-axis. The distance to the edge of the screen in x-axis is 128 since it's moving in a negative direction and it's x position is 128, therefor it takes 128 / 0.24 which is approximately 533.33 steps to get to the end of the screen on the x-axis. The distance to the edge of the screen in y-axis is the window height, 768, minus the wall y position; 768 - 128 = 640. Therefor it takes 640 / 0.97 which is close to 659.79 steps to get to the end of the screen in y-axis. Since the unity vector hits the end of the screen on the x-axis first I multiply the unity vector with the number of steps it takes to get to the x-axis. This gives me the vector from the wall to the edge of the screen and so I just add the wall position to the vector and ta-da, I have the edge position!

To see if there is a corner between two positions was a little bit harder. First of all I had to have the player's position as well as the two points I wanted to check since I need to know which way I should look for a corner. Secondly I tested if there even was a possibility that there was a corner between the two points, if there weren't I just returned the first parameter (the position took look for corners from). Then I tested to see if the first parameter was a corner, if it was, the second corner had the same x or y value as both the points and the other value equal to the second point. If however the first point was not a corner I tested to see if there were two corners between the two points, if there were, then it found the first corner by taking the x or y value from the first point (whichever is 0 or the screen dimensions) and the other value is set to 0 or the screen dimension depending on the player's position. If the first point was not a corner and there was only one corner between the two points, the corner had the same x or y value as the first point which ever is a 0 or screen dimensions and the other value of the other point.

That worked fine, until we added a view port. . .

Bugged shadows
What happened when we added view port to our game was that no longer was the top left corner always at point 0, 0 nor the bottom right the width and height of the screen. Since both my methods EdgePoint and GetCorner calculated everything from 0, 0 to width, height; adding the view port made everything to bug completely except when in the top left corner of the game.
   It may sound simple to change this, I certainly thought it should have been. However after several hours of not understanding why my changes didn't work I started to doubt my code. I looked deeper into SFMLs View class and it worked just as expected so there was clearly something wrong in my code but I just couldn't see it. After a week I described the problem to my programming teacher Tommi who said I shouldn't make things so complicated. He advised me to draw huge shapes that went way outside of the screen instead.

Since I had already thought some on this idea it didn't take long until I knew exactly what I should do. It was basically exactly the same as getting the point on the edge of the screen except taking the longer distance instead of the shorter one.

In the end the code looked like this:
Define m_shadow in the constructor
Update the two changing points in m_shadow
The get point method

In the GetPoint class I set the maximum value on distance to 1 million, I do this because the value can be infinite if the player is on the same x or y position which results in the shadow not drawing at all.

That was all I think! If you made it all the way please leave a comment. Also thank you for reading and stay awesome!

Thursday, February 20, 2014

Loading levels

This week I have been working on several different things. I've implemented a state manager, texture manager and created the class game object and seen to it that all classes that should now inherit from it. I have moved code from engine to the game state and changed some of it to make better sense and one of these changes is what I'm going to explain into detail about today.

In our game state we load the level from a text file. From the start there was only the tile map to load from the file but as we added more objects to the game our level file grew. Now it includes everything: tile map, player starting position, guards and their patterns, all props, evidence location and more. As we added more and more to the file we simply added more and more to our method that loads it, this made our method pretty big and clumsy.
When elevator doesn't have a rotation
   The main problem with the method was that each object had to be listed after a specific other object. For example: The elevator position had to be directly after the player position, otherwise the program would load everything wrongly and the game would either crash or look really weird. Another problem with the method was that it couldn't load anything but rectangular levels.

So when I created the load method again I though I'd rewrite the whole thing and solve the existing problems.
   The first and most important problem was fairly easy to solve. After the file was opened I created a while loop that continues until the file stream reads "End". The first thing that happens in the while loop is it reads one word from the file, it then checks to see if it was a keyword like "Player:". If it is a keyword a few lines specific to that keyword is run, for example if the keyword "Player" is found; it creates a sprite from a read texture and sets it to a read position. This way any object can be written anywhere in the file also we can write anything like explanatory text without the load method reading anything wrong.
   The second problem with the loading of empty tile was solved by skipping one tile if the stream reads two 9's. 9,9 means to take the tile from the image file with the x and y position at 9 which will only happen if we manage to get 81 tiles. I believe this was a easy and good solution and we will most probably not need to change it.

Well, that was it! Thanks for reading and stay awesome!

Wednesday, February 12, 2014

Collision and a few other things

It's been a while since I last posted since I've been combining the work with my two fellow coders into one single project. So far we've been doing great and we have a finished pre-alpha ready for tomorrows deadline.

My job this week was mainly collision but I have worked with a few other parts of the project as well. For the collision though we are going to have box vs line collision for the walls and later box vs box as well for props.
   My theory for box vs line collision was this:
  • First check if the player is on the same x or y coordinates as a wall.
  • If he is: see which side of the wall he is on, and if he moved with his current speed if he yould end up at the other side of the wall.
  • If he would: Change his speed so that he hits the wall instead.
I thought it was a simple enough theory and it wasn't difficult to write. I had some trouble at the start where I used the wrong variable, but that's just because I'm not used to name my variables this way we are doing it, so I got confused.

Other than that it's not much to tell. I implemented the tile system Viktor wrote and recode it so it read the tiles and walls in from a file. William fixed the rest and our artists drew what was needed.

Thanks for reading and stay awesome!

Friday, February 7, 2014

Player's Vision

Finally I'm done with all I need to do this week. There were some big changes from yesterday and I will try to explain it all here.

Yesterdays bugged FoV
I started today by fixing a bug. Yesterday I said the polygons had four points and if it covered a corner an additional point would be added. However, I did not implement the corner code yesterday but got an almost perfect result anyway. I would have tried to understand why the "bug" made almost everything right, if it wasn't for the fact that if a wall had a position were either x or y was equal to 0, it would draw the polygon wrong. I did not go in to detail on what was wrong but the polygon clearly went outside of the screen and I don't want to not know what is happening in my code. So I fixed the bug and I got the result I was looking for so far.
Unbugged FoV
   When the bug was fixed I changed the Wall class a lot. I removed the VertexArray that displayed a line between the two positions and added a ConvexShape to draw a polygon instead. I removed the SetPosition and GetPosition methods and added an Update instead. I also removed a constructor since I believe it will never be used and added two private methods: PointOnWall and CheckCorner.
  • SetPosition and GetPosition are not needed anymore since everything is done in the class instead.
  • The VertexArray that drew the line was not needed anymore since I added the ConvexShape (polygon) to the wall class instead.
  • I moved the code from the Run method in the Engine class to the Update method in the Wall class. I do not want too much code in my Engine, so this was obvious.
  • The PointOnWall method take two Vector2f parameters and calculate where on the edge of the screen a line, from the first position tangent to the other position, hit and then returns the position.
  • The CheckCorner takes three Vector2f parameters, and return the position of the first corner between the two first position. The third position is the player's and is used for checking what way to look for corners. If there are no corners between the two lines it simply returns the first parameter.
The PointOnWall and CheckCorner methods took a long time to program, also figuring out the concept took a while.
   PointOnWall creates a Vector2f vector that is set to the unit vector between the two positions given. It then calculates how many steps are needed to get to the closest wall in both directions. The fewest amount of steps needed is then multiplied to the unit vector which creates a position on the edge of the screen which is returned.
   CheckCorner is a bit more complicated. First it checks if there are of corners between the two given positions. If there is none, it simply return the first position. Otherwise it checks the first position to see if it is a corner. If it is, it checks the other position for and x or y value that is not 0, width or height of the screen. That value is replaced by the corresponding variable from the first position and the position of the corner is returned.
   If however the first position is not a corner the program checks if there are two corners between the two given positions. If there are, it checks the value from the first position that is not 0, width or height of the screen and then the player's position to see if it's going to look up or down for the next corner. It then returns the position of the corner.
Finished FoV
   Lastly if there is only one corner between the two positions it simply checks which position is not 0, width or height of the screen and takes the other variable of the other position and returns that position.

So, that's something. . .

If you read all this, you're awesome and thank you so much!

Thursday, February 6, 2014

Walls and Player FoV

I'm soon done with my tasks for this week which are to draw out walls and make it so that the player can't see behind the walls.

I started out with the walls and created a new object called Wall. A wall is simply a line which the player can't cross nor see behind, nothing can interact with walls so the class was easy to make. Two Vector2f variables to keep track on start and end position of the lines, a VertexArray which is the line, two constructors, a Draw method, two SetPosition methods and a GetPosition as well.
  • There are two constructors, one that take four int parameters and the other take two Vector2f parameters that sets the position of the line. I did this to make it easier creating a wall later on.
  • The draw method only draw the line but I have it there if I later decide the walls should include the shadows.
  • The two SetPositions does what the constructors does.
  • The GetPosition method takes a string parameter which asks for which position to return. I did this quickly because I thought it might be easy, but it is not and I will change it later.

I am going to rework the Wall class, it is far from optimal.

Just walls, no shadow.
After the walls were finished and placed out on the window I started with the player's vision. In our prototype we checked every pixel around the screen with the player's position. We calculated the unit vector from the player toward the position of the current pixel and used it to take one step at a time and check for walls. When we hit a wall we drew a line from the current position to the position to the pixel. Yea, many iterations.
   This time I though I'd take the two positions from the wall and calculate the unit vector from the player to each of them. Then use the unit vector to calculate where a line from the player that intersect with the edge of the wall hits the edge of the screen. The draw a polygon with four points, the two wall edges and the two calculated values. If the polygon would cover a corner another point would be added to the polygon with the coordinates of the corner. A lot fewer iterations.
Player in the middle can't see through walls.


This was a lot harder to implement than I though but now it's almost perfect. I think about moving the polygon to the wall class and add a method taking two parameters (the player's position and the render window) and calculate everything there.

I will fix some detail and quality assure my friends work tomorrow.

Thanks for reading, and stay awesome!

Wednesday, February 5, 2014

Another Photoshop day

My friend told me of an idea to a skin for a League of Legends champion. It is focused on water and ice so I immediately thought of Elsa from the Disney movie Frozen and I'm now going to draw her more realistically.

Today I mainly sketched her face and pose. It took a long time since I couldn't make a good sketch without reference and finding an good reference was hard. When I was finished with her head I just drew her pose quickly and not very detailed or exact, I'll be focusing on that later.

I did not do much today, but thanks for reading and stay awesome!

Tuesday, February 4, 2014

More Photoshop

So today I continued practicing reference drawing, because. . .

This time I drew Udyr, another character from League of Legends.
I focused on the sketch a lot more today since I believed that a better sketch would improve the final image considerably. Looking back now I'm not very sure yet, this image is much nicer than the one yesterday but it is probably just the amount of detail this one had compared to the other. The sketch took longer time to complete and so did the refining and coloring, but those all depend on the detail as well, so I just have to keep trying until I know what suit me best.
Also I'm not focusing to much on shadows, depth or coloring right now, I will start doing that when I feel comfortable drawing without reference. For now I use paint bucket.

I hope that I in a not to distant future can draw bodies without reference and I just might try that in a few days. For now this is good enough.

Thank you for reading, and stay awesome!

Monday, February 3, 2014

Mushroom Man

Mushroom-man is a common name for many species of non-stationary mushrooms.When observed, mushroom-men looks just like an ordinary mushroom but it is a known fact that they actually wander about and even talk with each other.

The most obvious proof is fairy rings. It's merely a gathering of mushroom-men that you happened to witness, and just like troll mushroom-men have build in "turn to object" cells that actives the nanosecond a human lay eyes on them.

Think about it.

Photoshop fun

I love to draw, so I thought I'd practice some figure drawing from reference.

The first one I drew was Renekton, a humanoid lizard from League of Legends.
I used a small brush with low opacity for my sketch which served as guidelines when later drew more precisely on another layer. The main goal for me was to keep the proportions same as much as I could and I believe I did a good job, I was proud enough to color it when I was finished.

My second attempt was on a random female model.
I started out the same but it was way harder than the lizard-man. I think it was due to the lack of muscles and therefore harder to get the proportions right. After I was finished with the sketch I realized I didn't want to continue with it and just refined some parts that where completely off.

For the next time I will try to make better sketches and eventually draw without reference, but that's far in the future.

Thanks for reading and stay awesome.

Welcome

Hey! May I say, you look good today!
Welcome, to my blog!
I'll catch you around, okey?