Showing posts with label 5SD033. Show all posts
Showing posts with label 5SD033. Show all posts

Thursday, March 20, 2014

Level Editor

Now when all of the features of our game is finally implemented we've been working hard on our levels. Our game is played on four floors where the first, top floor is the tutorial. After the tutorial the player is going down until he is on the first floor where the game end and he wins. The levels are loaded in from text files and those have become extremely hard to create since we have so much that needs to be loaded. Therefore I've been working on an editor to make level design much easier.

The main features of the editor are: Save and load to/from a file, place and remove objects from level. It seem simple, maybe it is, but I had to think a while before I started so that I made the easiest and fastest solution since we only had two week left before final. I also wanted it to be easy to add extra content to the editor so that I could send the new versions to our level designer and have him be able to load the levels he had already made and continue with the new features implemented.
   I first got the idea to have states, and that depending on which state was active you placed and removed different thing, and since it was such an good idea and worked, I didn't really think of a plan B. Instead of making a state_manager though I created a string called m_state and in the update and draw I had an if-statement for each state there was. Now I know this isn't good looking but I wanted a fast solution, not a good looking one!

I started with tiles and the first problem was: How should I select the tile I want? There was either a UI that showed all tile available where you could click to select which tile to place down next, or it was to cycle between all tiles with a keyboard button. Since all tiles are in one single sprite sheet I decided to do the first one. I drew the sprite sheet on the top middle of the screen and when the user clicked on it the editor found out which specific tile was clicked and set the current tile to that tile. When I clicked anywhere on the background a tile identical to the current tile was place there. I had some trouble with several tiles added on the exact same place but solved it by first going through all tile to see that there wasn't already a tile there. I also added so that the right mouse button removed the tile on the current mouse position.
   After the basics was finished I just added some tools to make things easier. The current tile was draw where the mouse was, the tile aligned them-self to the grid and a border was drawn around the current tile to be able see it clearer.
   When that was done I came to a little bit more difficult problem: How to save the map? The load map was easy since all I had to do was copy it from our main game and adjust it slightly, but the save was a little bit harder. All the tiles are stored in a vector instead of a two-dimensional array and thus I don't know which the most left, right, top and bottom tiles are. But after some thought I simply decided the go through the whole vector saving the lowest and highest of the x and y values in four variables. This also made it possible to not only work in a specific area but anywhere. If the top tile had a position of -512 it would have the position 0 in the saved file and all others would move down 512 pixels as well. To save them I had two for-loops with a third for-loop in them. The first two checked each position and the third went through each tile to see if it should be in that specific position and when a tile was found it was written to the file. If there where no tile there, simply write "9,9" to the file (when I wrote about the loading of levels I said "9,9" was chosen to represent an empty tile).

Finally I had the tiles finished, so I sent the version to our level designer and started working on the walls. The wall where a bit simpler in that they all have the exact same texture, but also harder since they had two points which had to create a perfect line. In the wall state update I made it so that the left mouse button set the starting point of the wall and the right mouse button created the end point. All I had to do was checking when an end point was placed to see if it had either the same x or the same y value as the starting point, but not both. For removing a wall shift had to be held down when right clicking and saving the walls was very simple since it didn't need to be saved in any order, just a loop with a single write to file line inside it.

After I had sent the new version away I started working on the props. These where like the tiles only I didn't have to align them in a grid, but I had to rotate them. No biggie and saved just like the walls.
   I fixed the vents after that, then the doors, player starting position, evidence and lastly the elevator. These last ones where really simple since I mostly copied from what I had written before. The only thing that is left are the enemies and their patrol pattern, which I wall do eventually. This editor have been great though! The time it have taken me to code has already been worth it since our level designer have had a super easy and fun time creating the levels. Now we are focusing on play testing and to create fun and difficult level for our game.

I don't have much more to add, thanks for reading and stay awesome!

Thursday, March 13, 2014

The Tutorial

The tutorial is a great tool to introduce the player to your game and this week I've been working on the tutorial for our game.

On the first attempt to create the tutorial I wanted to explain the basics of our game; How you move, shoot, pick up evidence and progress to the next level. The tutorial was also meant to serve another porpoise: Explaining why you are there. I did not want to have much text in the tutorial, mostly images and preferably everything should be intuitive, but I failed on my first attempt.
   Firstly I limited what the player could do before he had advanced to a specific part of the tutorial, which isn't bad except I did it with movement. On the play-test day almost everyone playing the tutorial got stuck right away, some asking "Can't you walk?". This was obviously really bad.
   Secondly I wasn't clear with what the player was meant to do. At the start you are standing in front of a man and there is an image saying: "Move the 'image of a mouse' to aim". Everyone tried to walk with the character, who was immobile until a later stage, instead of aiming at the boss. We had to tell almost everyone what they needed to do at this stage, and that wasn't very good either.
   When the player aimed at the boss another image replaced the old one saying: "Click 'image of left mouse button' to shoot". However, this was so similar to the previous image that some players completely missed it.
   After the player had killed the evil boss it was fine. "Move with 'wasd'" was everyone familiar with and "Press 'space' to pick up evidence" was straight forward as well as the arrow pointing at the elevator when the evidence was collected.

There is one big thing however I did correctly with the tutorial: I completed it in time to be play-tested. I gained a lot of valuable feedback and now know how to create a better one!

So I had to fix these errors and create an easier tutorial. The first thing that happens in the new tutorial is that the character walks out of the elevator into a room with no guards, there is no UI to see either. If the player doesn't move for the first five seconds the image pops up telling the player to walk with 'wasd'.
    The player then progresses out of the room and walks into a corridor with a guard guarding. First now the player will see a circle around him and an image saying simply: "'Ctrl' to sneak". If the player press ctrl while walking he will see the circle getting smaller and that he moves slower. If he stands still the circle disappears. It will be easy to walk past the guard and advance into the next room.
   In the next and final room there is the evil boss. When the character walks in, the boss will say: "Don't hurt me!" and the character replies: "You don't deserve to live.". The 'how to shoot' image will pop up and the bullets UI will show as well.
   When the player kills the evil boss the tutorial will remind the player that the bullets can't be replenished. Also an evidence spawn in the room and the evidence UI is shown as well as the 'how to pick up evidence' image.
   The last stage of the tutorial begin when the player picks up the evidence and an arrow appear pointing in the direction of the elevator. The guard the player walked past before now enters the room and the last tutorial message is displayed saying: "'Shift' to run". When the player run the circle around him will increase considerately but he will be a lot faster and thus outrunning the guard will be easy.

I believe these changes will create an better tutorial which is more intuitive and teaches the player  more things about our game. Still, there is a few weeks before the project should be finished so I have plenty time to play-test it and ask others to try as well.

That's all for me this time. Thanks for reading and stay awesome!

Thursday, March 6, 2014

Theory on doors

This week I've been working a little bit on many different things but I've had the most trouble with doors. Doors in our game are intuitive; the player can interact with a door if he is close enough, when he does the door opens away from the player. The door cast a shadow just like the walls but it gets complicated when it comes to the door-frame.

From the alpha play test we got some feedback concerning the walls; they looked like huge 3D walls. Some thought it was cool, others didn't. Some merely pointed it out and asked if it was out intention to have that effect. One suggestion to fix the 3D feeling was to limit the view when looking through doors, so this is what I've been trying to do.

My first thought was to take the same function as the wall shadow but move both the starting vectors (the two points on the door) further away from the player. I also thought the length by which the starting vectors would be adjusted would be dependent on the distance from the door to the player; this meaning a player far away from the door would only see that the door is open but not much through it, and a player close to the door would see as normal (no shadow from the frame at all).
   This sounded simple, but when I delved deeper into how to get the values by how far the starting vectors should move, the complicated stuff began. I realized it would look "off" if the vectors would move the same distance, so I had to figure out a way to get the both values correctly.
Circle theory
   After some time I had two different theories. The first one was to get the line from the player to one of the vectors and check where it intersected a circle with center in the middle of the door. Doing this for both the vectors would send them back further if they were closer to the player, this way it was also very simple to change the distance you could see by adjusting the radius of the circle.
   The second idea was to get the perpendicular line to the line from the player's position to the middle of the door. Then calculate where both lines from the player to each of the vectors intersected with the perpendicular line. This would give the same result and changing the distance would simply to take a point further back on the center door line.

Perpendicular theory
I never implemented this however. I have started working on it but when we got our new lighting system from our lead programmer this felt unnecessary since the player can't see far anymore.

I know this was a theory heavy post, but that's since I haven't made anything big this week this was the best thing I could write about. Thanks for reading and stay awesome!

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!