That's because I want to be able to have non-random levels too, and I don't feel like having to do this again to do it:
SDATAW.WriteString("R");SDATAW.WriteString("0");SDATAW.WriteString("-1");SDATAW.WriteString("2");SDATAW.WriteString("-1");SDATAW.WriteString("1");SDATAW.WriteString("353");SDATAW.WriteString("241");
SDATAW.WriteString("D");SDATAW.WriteString("1");SDATAW.WriteString("-1");SDATAW.WriteString("0");SDATAW.WriteString("-1");SDATAW.WriteString("3");SDATAW.WriteString("348");SDATAW.WriteString("247");
SDATAW.WriteString("D");SDATAW.WriteString("2");SDATAW.WriteString("-1");SDATAW.WriteString("4");SDATAW.WriteString("-1");SDATAW.WriteString("0");SDATAW.WriteString("417");SDATAW.WriteString("266");
SDATAW.WriteString("R");SDATAW.WriteString("3");SDATAW.WriteString("6");SDATAW.WriteString("1");SDATAW.WriteString("7");SDATAW.WriteString("5");SDATAW.WriteString("284");SDATAW.WriteString("241");
SDATAW.WriteString("R");SDATAW.WriteString("4");SDATAW.WriteString("8");SDATAW.WriteString("9");SDATAW.WriteString("-1");SDATAW.WriteString("-1");SDATAW.WriteString("422");SDATAW.WriteString("241");
SDATAW.WriteString("D");SDATAW.WriteString("5");SDATAW.WriteString("-1");SDATAW.WriteString("3");SDATAW.WriteString("-1");SDATAW.WriteString("10");SDATAW.WriteString("279");SDATAW.WriteString("269");
SDATAW.WriteString("D");SDATAW.WriteString("6");SDATAW.WriteString("11");SDATAW.WriteString("-1");SDATAW.WriteString("3");SDATAW.WriteString("-1");SDATAW.WriteString("299");SDATAW.WriteString("236");
SDATAW.WriteString("D");SDATAW.WriteString("7");SDATAW.WriteString("3");SDATAW.WriteString("-1");SDATAW.WriteString("12");SDATAW.WriteString("-1");SDATAW.WriteString("318");SDATAW.WriteString("305");
SDATAW.WriteString("D");SDATAW.WriteString("8");SDATAW.WriteString("13");SDATAW.WriteString("-1");SDATAW.WriteString("4");SDATAW.WriteString("-1");SDATAW.WriteString("455");SDATAW.WriteString("236");
SDATAW.WriteString("D");SDATAW.WriteString("9");SDATAW.WriteString("-1");SDATAW.WriteString("14");SDATAW.WriteString("-1");SDATAW.WriteString("4");SDATAW.WriteString("486");SDATAW.WriteString("253");
SDATAW.WriteString("R");SDATAW.WriteString("10");SDATAW.WriteString("-1");SDATAW.WriteString("5");SDATAW.WriteString("-1");SDATAW.WriteString("15");SDATAW.WriteString("215");SDATAW.WriteString("241");
SDATAW.WriteString("R");SDATAW.WriteString("11");SDATAW.WriteString("16");SDATAW.WriteString("17");SDATAW.WriteString("6");SDATAW.WriteString("-1");SDATAW.WriteString("284");SDATAW.WriteString("172");
SDATAW.WriteString("R");SDATAW.WriteString("12");SDATAW.WriteString("7");SDATAW.WriteString("-1");SDATAW.WriteString("-1");SDATAW.WriteString("18");SDATAW.WriteString("284");SDATAW.WriteString("310");
SDATAW.WriteString("R");SDATAW.WriteString("13");SDATAW.WriteString("-1");SDATAW.WriteString("-1");SDATAW.WriteString("8");SDATAW.WriteString("19");SDATAW.WriteString("421");SDATAW.WriteString("172");
SDATAW.WriteString("R");SDATAW.WriteString("14");SDATAW.WriteString("-1");SDATAW.WriteString("-1");SDATAW.WriteString("-1");SDATAW.WriteString("9");SDATAW.WriteString("491");SDATAW.WriteString("241");
SDATAW.WriteString("D");SDATAW.WriteString("15");SDATAW.WriteString("-1");SDATAW.WriteString("10");SDATAW.WriteString("-1");SDATAW.WriteString("15");SDATAW.WriteString("210");SDATAW.WriteString("282");
SDATAW.WriteString("D");SDATAW.WriteString("16");SDATAW.WriteString("21");SDATAW.WriteString("-1");SDATAW.WriteString("11");SDATAW.WriteString("-1");SDATAW.WriteString("322");SDATAW.WriteString("167");
SDATAW.WriteString("D");SDATAW.WriteString("17");SDATAW.WriteString("-1");SDATAW.WriteString("22");SDATAW.WriteString("-1");SDATAW.WriteString("11");SDATAW.WriteString("348");SDATAW.WriteString("204");
SDATAW.WriteString("D");SDATAW.WriteString("18");SDATAW.WriteString("-1");SDATAW.WriteString("12");SDATAW.WriteString("-1");SDATAW.WriteString("23");SDATAW.WriteString("279");SDATAW.WriteString("345");
SDATAW.WriteString("D");SDATAW.WriteString("19");SDATAW.WriteString("-1");SDATAW.WriteString("13");SDATAW.WriteString("-1");SDATAW.WriteString("22");SDATAW.WriteString("417");SDATAW.WriteString("190");
SDATAW.WriteString("R");SDATAW.WriteString("20");SDATAW.WriteString("-1");SDATAW.WriteString("15");SDATAW.WriteString("-1");SDATAW.WriteString("-1");SDATAW.WriteString("146");SDATAW.WriteString("241");
SDATAW.WriteString("R");SDATAW.WriteString("21");SDATAW.WriteString("-1");SDATAW.WriteString("-1");SDATAW.WriteString("16");SDATAW.WriteString("-1");SDATAW.WriteString("284");SDATAW.WriteString("103");
SDATAW.WriteString("R");SDATAW.WriteString("22");SDATAW.WriteString("-1");SDATAW.WriteString("19");SDATAW.WriteString("-1");SDATAW.WriteString("17");SDATAW.WriteString("353");SDATAW.WriteString("172");
SDATAW.WriteString("R");SDATAW.WriteString("23");SDATAW.WriteString("-1");SDATAW.WriteString("18");SDATAW.WriteString("-1");SDATAW.WriteString("-1");SDATAW.WriteString("215");SDATAW.WriteString("310");
The level creator will automate it for me, instead of having to hardcode it in >__<
Thursday, February 16, 2012
Sunday, February 12, 2012
State of the Project 2
Got the new version of the level generator working. Now it creates side rooms and doors much better then it did before! As well, I tweaked the code involved with the player firing and reloading his weapon and set up the third weapon in the player's arsenal (the mp5). The levels generated look a bit more complicated (but there's still a LOT of work to be done, obviously) and now the player doesn't have to repeatedly click to fire.
Here's two of the levels that were generated.
Where am I going from here? Well, once I fine-tune some of the logic I'm going to be adding some restrictions on where level segments can be built, because right now the segments are being built without checking anything. As well, the level data needs to be saved to a file, more types of level segments are being put in, and I want to improve the collision detecting a bit. I might add some basic enemies into it and start coding the "AI", but there's a few things yet to do before I work on that aspect.
Either way, there is progress...
Here's the latest compiled version: http://adf.ly/5RCZh
And the latest source: http://adf.ly/5RCcb
Still a work in progress, so what you see (of the game and of the code) is subject to change over time...for the better, of course :D
Progress
Level Generator / design ~= 15%
Story and Theme ~= 2%
Player ~= 80%
Enemies = 0%
Objects = 0%
Numbers
Line counts
Headers: ~110
Scripts: ~593
Total: ~703
functions: 17, so 703/17 ~= 41 lines per function average (max~=86,min~=6)
Static images: 10
Dynamically created images: 738
Estimated memory usage: ~12 Mb ---> ~34 Mb (VERY rough estimate)
Bugs
Here's two of the levels that were generated.
Where am I going from here? Well, once I fine-tune some of the logic I'm going to be adding some restrictions on where level segments can be built, because right now the segments are being built without checking anything. As well, the level data needs to be saved to a file, more types of level segments are being put in, and I want to improve the collision detecting a bit. I might add some basic enemies into it and start coding the "AI", but there's a few things yet to do before I work on that aspect.
Either way, there is progress...
Here's the latest compiled version: http://adf.ly/5RCZh
And the latest source: http://adf.ly/5RCcb
Still a work in progress, so what you see (of the game and of the code) is subject to change over time...for the better, of course :D
Progress
Level Generator / design ~= 15%
Story and Theme ~= 2%
Player ~= 80%
Enemies = 0%
Objects = 0%
Numbers
Line counts
Headers: ~110
Scripts: ~593
Total: ~703
functions: 17, so 703/17 ~= 41 lines per function average (max~=86,min~=6)
Static images: 10
Dynamically created images: 738
Estimated memory usage: ~12 Mb ---> ~34 Mb (VERY rough estimate)
Bugs
- Doors aren't being placed correctly
- Collision detection isn't perfect. The player can clip through a wall dividing two side rooms if they are in a doorway connecting the two side rooms.
- When the player's weapon runs out of ammo, sometimes it reloads without the pause or the sound effect, and continues firing. I think I fixed this but I'm not 100% sure
- As the player rotates, it looks like the graphic 'shifts'. Unsure why.
Saturday, February 4, 2012
How the level generator is going to work
I worked it out step by step and I now have a better idea on how to go about coding it. The level structure is going to look like a BSP-tree, since it's a simple and decent place to start. Instead of having a wall of text I made some handy-dandy images to break things up and help show what I mean. On the left is what the level will look like, on the right is how it got generated and is a representation of the connections between sectors. I'll try and spare the nitty-gritty details of it's inner workings and keep the explanation simple.
So, the game needs to build a new level, completely from scratch. Okay, to start, lets pick any valid location within the screen area. We will create sector '0' and drop it somewhere, like so:

It's a start. An ordinary room where the player will spawn. Now when a side room is generated, it may or may not have doors leading to other side rooms, closets, corridors, etc. A side room needs to have at least one door (to enter/exit through) but does not necessarily mean that it needs to have any others. When the starting room was created, the engine decided to make the sector have two doors: East and South, or sectors '1' and '2' respectively. The arrows represent the connection between the nodes in the tree or the sectors in the map.

Okay, now we're starting to get somewhere. We have a rough direction to work in. Where do we go from here? We have two doors, numbers 1 & 2, but what do we do with them? How do we decide which one to extend first? I'm going to start with the lowest and work my way up of course! (There is a flaw with this but I'll get into it a wee bit later) After a few checks and random rolls, the engine decides to put a corridor on the other side of sector 1 (east door), which will be sector 3. The engine does the same for sector 2 (south door), decides there will be a corridor there as well, and it will be sector 4. Because of the proximity of sectors 3 and 4 when they are generated, they can be (but are not required to be) connected.

So now we have a starting room, and a corridor outside it with two connections. Things are starting to shape up! Now, there are actually 3 steps I compacted into that one image:

That complication was just made worse. As the sectors expand and splits are added, two adjoining sectors can have ID numbers that are way off (sector 6 adjoins sectors 3, 9, and 10, #3 adjoins #1, and #4 to #7, etc.). However, as long as I stay aware of it and code for it, it shouldn't be too big a problem. It's just another complication in a nontrivial system. Still, it's worth the mention because it is an interesting issue. Moving forward, sector 7 is next to be expanded. Being a corridor, it checks to see if it can connect to another corridor. There are no other corridors to connect to, but it does detect that it could connect to a side room. It checks if it should, gets the go-ahead, and places a door (sector 11) between #7 and #8. The corridor was also flagged to have a door anyways, so it puts one on the east side (sector 12).
Now we hop all the way to the other side of the map (but only separated by two nodes) to sectors 9 and 10. The engine decides to put a side room behind each door, but the created sectors are NOT flagged to have any doors. They are a dead end.

There's only one sector do expand at this point: #12. It's another side room, with no flagged doors either. It's the last sector, #15

So, the game needs to build a new level, completely from scratch. Okay, to start, lets pick any valid location within the screen area. We will create sector '0' and drop it somewhere, like so:

It's a start. An ordinary room where the player will spawn. Now when a side room is generated, it may or may not have doors leading to other side rooms, closets, corridors, etc. A side room needs to have at least one door (to enter/exit through) but does not necessarily mean that it needs to have any others. When the starting room was created, the engine decided to make the sector have two doors: East and South, or sectors '1' and '2' respectively. The arrows represent the connection between the nodes in the tree or the sectors in the map.

Okay, now we're starting to get somewhere. We have a rough direction to work in. Where do we go from here? We have two doors, numbers 1 & 2, but what do we do with them? How do we decide which one to extend first? I'm going to start with the lowest and work my way up of course! (There is a flaw with this but I'll get into it a wee bit later) After a few checks and random rolls, the engine decides to put a corridor on the other side of sector 1 (east door), which will be sector 3. The engine does the same for sector 2 (south door), decides there will be a corridor there as well, and it will be sector 4. Because of the proximity of sectors 3 and 4 when they are generated, they can be (but are not required to be) connected.

So now we have a starting room, and a corridor outside it with two connections. Things are starting to shape up! Now, there are actually 3 steps I compacted into that one image:
- Draw sector 3 off of 1
- Draw sector 4 off of 2
- Sector 3 is next in line, and before it draws any attached doors or other corridor pieces, it checks if a direct connection (no door) to another corridor can be made. If it can be done, a decision is made to whether it does indeed connect or not.
After it decided to connect with sector 4, now sector 3 checks for doors and other corridor pieces. When sector 3 was created, the generator flagged the sector as having one door to build, and two corridor directions. The connection with sector 4 would not have happened if it would have interfered with what sector 3 was flagged to draw. The door is put on the east side, towards the north edge (sector 5). One corridor piece will branch off the north face and head west (sector 6), while the other will branch off the south face and head east (sector 7).

Looking good! The map is getting just a tad more complicated now that it's heading in two directions (east and west). Sector 5 (the door) is up next. There's going to be a big room on the other side of this door (sector 8, because 6 and 7 were already taken). The big room is actually just a side room resized. (in 64x64 chunks).
I'm starting to run into a bit of a complication. It started with the creation of the corridors outside the starting room, and is being aggravated with every step. Can you tell what it is yet? Lets keep moving forward. The next sector we're going to expand is #6. Even though the last sector created was #8, #6 is the lowest sector that still has yet to be checked for expansion. This sector, like the starting one, is going to have two doors, one on the south and west walls, sectors 9 and 10 respectively.
I'm starting to run into a bit of a complication. It started with the creation of the corridors outside the starting room, and is being aggravated with every step. Can you tell what it is yet? Lets keep moving forward. The next sector we're going to expand is #6. Even though the last sector created was #8, #6 is the lowest sector that still has yet to be checked for expansion. This sector, like the starting one, is going to have two doors, one on the south and west walls, sectors 9 and 10 respectively.
That complication was just made worse. As the sectors expand and splits are added, two adjoining sectors can have ID numbers that are way off (sector 6 adjoins sectors 3, 9, and 10, #3 adjoins #1, and #4 to #7, etc.). However, as long as I stay aware of it and code for it, it shouldn't be too big a problem. It's just another complication in a nontrivial system. Still, it's worth the mention because it is an interesting issue. Moving forward, sector 7 is next to be expanded. Being a corridor, it checks to see if it can connect to another corridor. There are no other corridors to connect to, but it does detect that it could connect to a side room. It checks if it should, gets the go-ahead, and places a door (sector 11) between #7 and #8. The corridor was also flagged to have a door anyways, so it puts one on the east side (sector 12).
Now we hop all the way to the other side of the map (but only separated by two nodes) to sectors 9 and 10. The engine decides to put a side room behind each door, but the created sectors are NOT flagged to have any doors. They are a dead end.

There's only one sector do expand at this point: #12. It's another side room, with no flagged doors either. It's the last sector, #15

So there it is: a nice, small little map. It isn't a terribly complicated concept (the tree is easy to follow (well, to me it looks easy anyways...)) but I have to think of, and code for every possible condition and conflict that could appear. The goal here is to make a flexible and fast level generator, so I have to compromise from time to time.
Now, keep in mind that it won't just be the levels that are randomly generated: as much as I can get away with randomly generating is where I'm drawing the line =D Much of how the generation will work is already expressed in how the levels are generated, so once I have the initial design of the system I can modify it to generate other things =)
Now, keep in mind that it won't just be the levels that are randomly generated: as much as I can get away with randomly generating is where I'm drawing the line =D Much of how the generation will work is already expressed in how the levels are generated, so once I have the initial design of the system I can modify it to generate other things =)
Code refactoring!
A fancy way of saying that I'm reorganizing and redoing the level generator code, while preserving what it is that the code does. I've been reading a book about design patterns, and it's given me a few insights on what could have been implemented better and more efficiently. It's more work (boo!) but in the long run it'll make coding/maintenance easier(ahh...), and generally be less of a pain in my ass.
Damn you O'Reilly and your helpful books!
My current goal is to get a basic but stable version of the level generator working so I can start working on spawn logic for the static objects that will decorate the level, dynamic objects that will help or hinder the player, and enemies that will generally just hinder the player. Hopefully, next build will have a new-and-improved level generator that generates side rooms and doors correctly (and generate more) with a basic implementation of corridors and hallways, a few more weapons to play with...Simple stuff =D
Thursday, February 2, 2012
State of the Project 1
The first of my 'state of the project' posts. Here I'll try and quantify my progress and share some of the bugs I'm fixing.
Here's the compiled version: http://adf.ly/5BwNB
And here's the source for anyone curious: http://adf.ly/5GKhS
Just remember that this is a work in progress =P
Progress
Level Generator / design ~= 10%
Story and Theme ~= 1%
Player ~= 75%
Enemies = 0%
Objects = 0%
Numbers
Line counts
Headers: ~96
Scripts: ~583
Total: ~679
functions: 15, so 679/15 ~= 45 lines per function average (max=111,min=10)
Static images: 10
Dynamically created images: 738
Estimated memory usage: ~12 Mb ---> ~34 Mb (VERY rough estimate)
Bugs
Here's the compiled version: http://adf.ly/5BwNB
And here's the source for anyone curious: http://adf.ly/5GKhS
Just remember that this is a work in progress =P
Progress
Level Generator / design ~= 10%
Story and Theme ~= 1%
Player ~= 75%
Enemies = 0%
Objects = 0%
Numbers
Line counts
Headers: ~96
Scripts: ~583
Total: ~679
functions: 15, so 679/15 ~= 45 lines per function average (max=111,min=10)
Static images: 10
Dynamically created images: 738
Estimated memory usage: ~12 Mb ---> ~34 Mb (VERY rough estimate)
Bugs
- Level generation is still in early development, but after I expanded from just creating one side room with doors to adding side rooms after those doors did some of the doors stop being drawn correctly
- There's only supposed to be a maximum of one door per side of a room, but at the moment nothing really stops two doors from being generated.
- Ammunition for your weapons is infinite.
Now, I share the bugs more for myself. It's so I have a list of what's broken and needs to be fixed, and what needs to be optimized.
Procedurally Created Content 1
More of an experiment, really.
Although it may have escaped your attention, many games do in fact have dynamic content that is generated at run time like the maps in Diablo II, or enemy and object locations in Left4Dead. Still, there is generally more static content then there is dynamically created.
What if the majority of a games content was generated dynamically? Not just the maps the player explores or where enemies are going to spawn and be, but also what the enemies are, the story the player experiences, objectives, weapons...it would offer almost endless replayability.
This is a non-trivial concept and implementing it will be a nightmare, but I'm taking a crack at it anyways because it IS possible, and I'm pretty sure I can code for it.
What made me want to try was getting fed up with making the tons and tons of sprites, maps, and characters needed for a game. I'm terrible at graphic design, so of course I jumped at the idea of creating it all dynamically.
Now that you have an idea of what I'm trying to accomplish, lets dive into what I'm using to make the concept live.
I'm using the Adventure Game Studio game engine. It's intended to create those old school 'point-and-click' adventure games, but can be used for so much more. I've been messing around with it and twisting it's arm this way and that for a few years, and this is the most basic place to start. Once I finish the concept in AGS, I'll move on to other game engines and implement what I learned.
I'll put more information about the project as time moves forward and I get more done, but feel free to have a preview of the game in progress. What you see is not even close to what the finished product will be, instead it is the bare bones of what it will become.
At the moment my biggest challenge is the level generator, which I'm probably about 10% done. Granted, I don't think the level generator will be 100% done until the game itself is approaching completion. As for the code involved with the player, that's more like 75-80% done. I already had most of the code associated with a player in this style written in a few previous games, so it was a bunch of copy-paste, tweaking, and now the player detects collisions, moves, shoots, reloads, and switches weapons. The basic stuff, really.
Although it may have escaped your attention, many games do in fact have dynamic content that is generated at run time like the maps in Diablo II, or enemy and object locations in Left4Dead. Still, there is generally more static content then there is dynamically created.
This is a non-trivial concept and implementing it will be a nightmare, but I'm taking a crack at it anyways because it IS possible, and I'm pretty sure I can code for it.
What made me want to try was getting fed up with making the tons and tons of sprites, maps, and characters needed for a game. I'm terrible at graphic design, so of course I jumped at the idea of creating it all dynamically.
Now that you have an idea of what I'm trying to accomplish, lets dive into what I'm using to make the concept live.
I'm using the Adventure Game Studio game engine. It's intended to create those old school 'point-and-click' adventure games, but can be used for so much more. I've been messing around with it and twisting it's arm this way and that for a few years, and this is the most basic place to start. Once I finish the concept in AGS, I'll move on to other game engines and implement what I learned.
I'll put more information about the project as time moves forward and I get more done, but feel free to have a preview of the game in progress. What you see is not even close to what the finished product will be, instead it is the bare bones of what it will become.
At the moment my biggest challenge is the level generator, which I'm probably about 10% done. Granted, I don't think the level generator will be 100% done until the game itself is approaching completion. As for the code involved with the player, that's more like 75-80% done. I already had most of the code associated with a player in this style written in a few previous games, so it was a bunch of copy-paste, tweaking, and now the player detects collisions, moves, shoots, reloads, and switches weapons. The basic stuff, really.
As you can see, the level generator is still in construction
first!
Decided to start a development blog as a way to try and organize the projects I have going, the projects I'm thinking of, and what I've done. This is more for myself then anything, so that if I abandon a project (perish the thought) and return a few months later, I'll have an idea of what I was thinking when I did what I did.
I will (try) and update it every week, no promises though.
I will (try) and update it every week, no promises though.
Subscribe to:
Posts (Atom)