I'm not having any fun with trains. I'm really not. I hate the little cars and the little turrets that ride those rails like old timey vagabond rail riding people. That last sentence really came apart like a cheap parachute didn't it? Anyway, the reason that I hate them is because the math is dicking with me, and so are those stupid train cars.
Right, after the last posting everything seemed all good and well yes? I created a series of little switches that allow me to control when and in what direction the little train cars will go by changing their movement vector to be from straight to diagonal using an equation. All in all, good times.
Unfortunately, the math seems to want to be selective for what it will work on and how well. Imagine for a moment that the car is trotting along with it's little hitchhiking turret on top. They are both going the same speed and all is more or less positive looking. Then when they hit the switch they change direction. However, somehow the turret is now going faster than the car and speeds ahead diagonally. So here's the weird thing, with an equation the same input should trigger the same result.
1 + X = 2
...will always be X = 1. But no, instead the same gods damned speeds get converted into different diagonal speeds somehow. I don't know why exactly, and it's not something that I'm going to lose any sleep over. The train idea like I said, isn't interesting enough to support a level anyway.
Hence the titles for today. What I have discovered is that while the wee trains cannot support a level, they can add a little flavor to one. So now, no more changing angles, just little trains doing little train stuff. That's it. Moving on now. Got other stuff to do.
- This post seemed a little snarky at the end there. Hmmm, let's think of something non-sequitur to end this thing like a donkey riding another donkey on a merry go round. Yeah, that'll do.
Saturday, August 20, 2011
Saturday, August 13, 2011
The Speed of Ground
I figured that going with something as simple at Crazy Train would be too easy (unlike spelling today - I've had to backspace out 6 times just now, including but (7) not limited to the word "spelling"...it's (8) going to be one of those kind of posts). So after the last time I got to working on making the train work. Now though, it does which is kind of nice. I started by making everything in the game that move at the same speed as the ground (of which there are a bunch) go at a speed I called groundSpeed. Then I noticed that the timer that I was using to make stuff spawn up was set to 16 ticks. I quickly realized that the 16 ticks was actually the relationship between the size of the tiles (32) and the speed of the ground (2). So instead I told the system to keep track of the ticks like this :
Tile Size / Ground Speed
Now, I can make the ground go any damn speed I would like it to go. Anything but 8 seems to work, since 8 is about the speed of most flying enemies, and looks like crap. Also, really fast.
Anyway, I got to cracking on the train cars. It didn't take too much effort to get the classes that would control them up and running (or rather make modifications to already existing classes to keep track of different inputs). What took more effort was the switches. I had constructed some invisible little boxes that would control how the cars would move. Tiny little objects that had no real value of their own, but would pass their values along like the good gods a-fearing parents that they are. So when they hit an enemy train car they would pass along a rotation value, which in turn would be processed to change the speeds that the car was going.
This took some more doing that you would think that it would. First off, the cars would go different speeds based on what they were doing. So a car would be traveling at a speed of 1 pixel per cycle. It would hit an invisible switch and now be going a speed of 1 up and 1 over. Problem has to do with our new favorite equation:
A^2 + B^2 = C^2
The new speed of the thing was actually the square root of 2...not 1. This had the effect of making the cars seem to speed up when they got to a hill of any variety. Consequently, this looked like crap when there were multiple cars going. So I did the math to fix that and then it worked, but not in relation to anything else. Since the ground itself is always moving (at the speed of ground no less) the cars would travel right on through the ground. This too, looked like crap. Eventually, after doing some tweaking I came to this:
float result = (float)Math.Sqrt(enemy.speed.X);
enemy.speed = new Vector2(result, (result - groundSpeed));
This says to make a new variable based on the square root of enemy.speed and then to set the speeds based on that result. The Y value was then modified by the speed of the ground. Again, thinking about it seems like it shouldn't work, but it does. Since all the stuff that seemed like it should word didn't, I'm going with it. When the wee cars travel up a hill they don't speed ahead of the cars waiting there turn at the bottom.
Right then, what does this have to do with anything? Well, the train levels aren't interesting. They just aren't. It's stupid. It comes down to a basic issue of speed. The ground moves at a certain speed, and the train moves at a certain speed too, but that speed must be slower than the speed of the ground so that the train appears as if it is moving along said ground. It it moved the same speed, then for all intents and purposes, the train is stationary. It's the same reason that certain speeds of ground look awful, since it makes the flying enemies appear to be stationary as well.
If on the other hand I make the train go faster than the ground, it appears to be going in reverse. Therein lies the issue. Turrets and rocket launchers that are moving slower that normal, everyday vanilla turrets and rocket launchers are fundamentally less interesting by default. Hence any level that I build with this crap would be less interesting than a normal level simply because the base conceit doesn't hold up. Especially considering that the engine portion of the train is supposed to be at the front.
So I have some choices to make. First of all, I could try to eke some level pieces out of the stuff I spent 2 days building. Maybe include a short train for a bit of something different. I could do this, for the grins and possibly also, the lulz. Or I can just shit can it. I may do that too if I can't make a portion of train interesting.
Consequently boys and girls, this is part of building a game that kind of sucks. You see, I spent the last 2 days building something. Something that works and plays. From a coding and a feature level, it's all done - finished, in the proverbial can as it were. However, this isn't normal software development - this is game development and it doesn't natter 2 shits if the thing is feature complete if it isn't any damn fun. It's my responsibility as a Game Designer to recognize these things and take them out like Boxer. The alternative is to let them keep on going and devote time and energy to them in spite of the fact that the may never work, or the effort required for something that is not a pillar of the design could be better spent elsewhere.
Could be worse though. Imagine for a moment that this didn't just take a couple of days, but a month. Now let's imagine that I'm telling this to a team of programmers and artists. It's the ugly part that nobody really likes, but occasionally does happen. I think it's one of the reasons that people avoid that particular chair.
Tile Size / Ground Speed
Now, I can make the ground go any damn speed I would like it to go. Anything but 8 seems to work, since 8 is about the speed of most flying enemies, and looks like crap. Also, really fast.
Anyway, I got to cracking on the train cars. It didn't take too much effort to get the classes that would control them up and running (or rather make modifications to already existing classes to keep track of different inputs). What took more effort was the switches. I had constructed some invisible little boxes that would control how the cars would move. Tiny little objects that had no real value of their own, but would pass their values along like the good gods a-fearing parents that they are. So when they hit an enemy train car they would pass along a rotation value, which in turn would be processed to change the speeds that the car was going.
This took some more doing that you would think that it would. First off, the cars would go different speeds based on what they were doing. So a car would be traveling at a speed of 1 pixel per cycle. It would hit an invisible switch and now be going a speed of 1 up and 1 over. Problem has to do with our new favorite equation:
A^2 + B^2 = C^2
The new speed of the thing was actually the square root of 2...not 1. This had the effect of making the cars seem to speed up when they got to a hill of any variety. Consequently, this looked like crap when there were multiple cars going. So I did the math to fix that and then it worked, but not in relation to anything else. Since the ground itself is always moving (at the speed of ground no less) the cars would travel right on through the ground. This too, looked like crap. Eventually, after doing some tweaking I came to this:
float result = (float)Math.Sqrt(enemy.speed.X);
enemy.speed = new Vector2(result, (result - groundSpeed));
This says to make a new variable based on the square root of enemy.speed and then to set the speeds based on that result. The Y value was then modified by the speed of the ground. Again, thinking about it seems like it shouldn't work, but it does. Since all the stuff that seemed like it should word didn't, I'm going with it. When the wee cars travel up a hill they don't speed ahead of the cars waiting there turn at the bottom.
Right then, what does this have to do with anything? Well, the train levels aren't interesting. They just aren't. It's stupid. It comes down to a basic issue of speed. The ground moves at a certain speed, and the train moves at a certain speed too, but that speed must be slower than the speed of the ground so that the train appears as if it is moving along said ground. It it moved the same speed, then for all intents and purposes, the train is stationary. It's the same reason that certain speeds of ground look awful, since it makes the flying enemies appear to be stationary as well.
If on the other hand I make the train go faster than the ground, it appears to be going in reverse. Therein lies the issue. Turrets and rocket launchers that are moving slower that normal, everyday vanilla turrets and rocket launchers are fundamentally less interesting by default. Hence any level that I build with this crap would be less interesting than a normal level simply because the base conceit doesn't hold up. Especially considering that the engine portion of the train is supposed to be at the front.
So I have some choices to make. First of all, I could try to eke some level pieces out of the stuff I spent 2 days building. Maybe include a short train for a bit of something different. I could do this, for the grins and possibly also, the lulz. Or I can just shit can it. I may do that too if I can't make a portion of train interesting.
Consequently boys and girls, this is part of building a game that kind of sucks. You see, I spent the last 2 days building something. Something that works and plays. From a coding and a feature level, it's all done - finished, in the proverbial can as it were. However, this isn't normal software development - this is game development and it doesn't natter 2 shits if the thing is feature complete if it isn't any damn fun. It's my responsibility as a Game Designer to recognize these things and take them out like Boxer. The alternative is to let them keep on going and devote time and energy to them in spite of the fact that the may never work, or the effort required for something that is not a pillar of the design could be better spent elsewhere.
Could be worse though. Imagine for a moment that this didn't just take a couple of days, but a month. Now let's imagine that I'm telling this to a team of programmers and artists. It's the ugly part that nobody really likes, but occasionally does happen. I think it's one of the reasons that people avoid that particular chair.
Tuesday, August 9, 2011
Thinking Out Loud
Let's get this out of the way right now - this post doesn't really do anything and odds are won't make too much sense. For kicks and because I'm thinking about it, I thought I would go through the process of figuring something out here on the blog. A kind of moment to moment look inside the admittedly stupid process that I go through when working out a mechanic or how something is going to work. Hence, this is more of a stream of consciousness kind of post today, and the kind of thing I would usually scribble (text?) out into a disposable Notepad document and then trash without saving. So, lucky day for you I guess.
Next up, the Train levels. Let's think about that for a moment. The train levels are supposed to work by having a series of train cars, each loaded up with stuff, like some kind of battle train. The Engine of the thing is the Base, and I'll probably create a tunnel or something so I have a place to leave a bomb.
From a coding perspective I should be able to create modified versions of the ground based enemy classes, or just make a train car class that I put underneath the normal ground enemies. That could work too I suppose. Either way, that shouldn't be too hard. Hypothetically I could create an invisible spawn box that can make the train cars move in different directions. Spawn them up with some kind of signifier that would tell a collision object what to do. Say, make the X and Y speed values something different so the train can run over terrain that isn't all flat. Again, not too much of a problem. Would have to change the rotation though to match. Could do that without too much worry though, since I'm just passing along variables and whatnot.
Instead, how is this thing going to work mechanically? I mean, if I destroy a train car, what happens? Does only the thing riding get wiped out? Or should the whole car be removed? I like the idea of destroying the whole car, but there are issues with that plan of attack. If, I destroy a car, do the rest just drop off? How do I code that? How does that interact with the destroyed enemies percentage since the enemies that are riding the latter cars would be removed from the screen but considered "escaped" by the game system? Do I have to make a special exception for them in that function?
I suppose that the answers could be, in order, yes, make it so that when a car collides with another car they change their speed values to match, it won't and will fail, unless yes.
The thing though is that considering it, it could create more moment to moment Wow moments, but would normally play like ass. To wit, since the front of the train is towards the end of the level, anything that was shot off would fall towards the back of the screen. By hugging the front of the screen you could always make the cars fall off, which isn't very interesting. Add to that the fact that the crasher type enemies would devastate the train and the pieces on it if the cars could fall off, and it stops being interesting from a level standpoint. I could do more with the level designs if the train cars were more an integral part of the environment.
However, I think that destroying the base should make everything just stop (or explode...that would be cooler). I can probably code a little exception bit into the bomb and base interaction code. Something along the lines of : If destroyed && level == 41 || 43 foreach ground enemy -> explode.
Alright then. So, up next for coding is a modified version of the turrets, rockets and base, each with the ability to move slower than normal. So if the ground is moving at a 2 pixels per frame, if a foreground object is moving at 1 pixels per frame it will have a ground speed of about 1 pixel per frame relative to the ground. Kind of slow considering, but still enough to present the illusion of movement over terrain.
Also, I need a new invisible class that I can detect collision on. Something that holds a value for rotation and new direction. I'm thinking that the speed value could maybe not actually be the speed that the invisible object (let's call it a Ghost) moves. Instead the ghost will always move at (-2,0) - like the ground. The speed value that it would have like every other sprite object would simply be used as a transfer of information to the other sprites that touch it. Might take some tweaking, but I think that it could work.
Well then. It seems like we have a plan.
Next up, the Train levels. Let's think about that for a moment. The train levels are supposed to work by having a series of train cars, each loaded up with stuff, like some kind of battle train. The Engine of the thing is the Base, and I'll probably create a tunnel or something so I have a place to leave a bomb.
From a coding perspective I should be able to create modified versions of the ground based enemy classes, or just make a train car class that I put underneath the normal ground enemies. That could work too I suppose. Either way, that shouldn't be too hard. Hypothetically I could create an invisible spawn box that can make the train cars move in different directions. Spawn them up with some kind of signifier that would tell a collision object what to do. Say, make the X and Y speed values something different so the train can run over terrain that isn't all flat. Again, not too much of a problem. Would have to change the rotation though to match. Could do that without too much worry though, since I'm just passing along variables and whatnot.
Instead, how is this thing going to work mechanically? I mean, if I destroy a train car, what happens? Does only the thing riding get wiped out? Or should the whole car be removed? I like the idea of destroying the whole car, but there are issues with that plan of attack. If, I destroy a car, do the rest just drop off? How do I code that? How does that interact with the destroyed enemies percentage since the enemies that are riding the latter cars would be removed from the screen but considered "escaped" by the game system? Do I have to make a special exception for them in that function?
I suppose that the answers could be, in order, yes, make it so that when a car collides with another car they change their speed values to match, it won't and will fail, unless yes.
The thing though is that considering it, it could create more moment to moment Wow moments, but would normally play like ass. To wit, since the front of the train is towards the end of the level, anything that was shot off would fall towards the back of the screen. By hugging the front of the screen you could always make the cars fall off, which isn't very interesting. Add to that the fact that the crasher type enemies would devastate the train and the pieces on it if the cars could fall off, and it stops being interesting from a level standpoint. I could do more with the level designs if the train cars were more an integral part of the environment.
However, I think that destroying the base should make everything just stop (or explode...that would be cooler). I can probably code a little exception bit into the bomb and base interaction code. Something along the lines of : If destroyed && level == 41 || 43 foreach ground enemy -> explode.
Alright then. So, up next for coding is a modified version of the turrets, rockets and base, each with the ability to move slower than normal. So if the ground is moving at a 2 pixels per frame, if a foreground object is moving at 1 pixels per frame it will have a ground speed of about 1 pixel per frame relative to the ground. Kind of slow considering, but still enough to present the illusion of movement over terrain.
Also, I need a new invisible class that I can detect collision on. Something that holds a value for rotation and new direction. I'm thinking that the speed value could maybe not actually be the speed that the invisible object (let's call it a Ghost) moves. Instead the ghost will always move at (-2,0) - like the ground. The speed value that it would have like every other sprite object would simply be used as a transfer of information to the other sprites that touch it. Might take some tweaking, but I think that it could work.
Well then. It seems like we have a plan.
Monday, August 8, 2011
The Quiet Flicker of Invincibility
Lots of good work done yesterday. Insomnia will do that from time to time, keeping me up into the wee hours with little to occupy my time but lots of things that would like to get done. I'll start with the levels. The Desert stage (as opposed to the Dessert stage natch) is in the bag now. Again, not saying anything in terms of how "complete" it is, since it still requires tuning and balancing and background element placement and multiplayer enemies and whatnot, but it does play and it plays pretty well. The unique (for that level) combination of flying enemies with lots of ground really makes the level play in a distinct kind of way. I'm rather fond if its peculiarities. Actually though I find that all of the levels play in a distinctive way, which makes me happy. Almost like an italian restaurant - the ingredients are almost all the same, but the combinations make for some distinctive tastes.
I also got the background elements popping a little bit more, which falls squarely into the "good" category. So now Paper Zeppelin has background clouds in it. I discovered that the structure called Vector2 can handle float variables. I'll back that up just a bit. In C#, there is a special kind of command called a Vector2 that holds an X and Y variable. You can start one up like this:
Vector2 Position = Vector2.Zero;
What that means is to start a Vector2 type variable and make it (0,0). You could also do this:
Vector2 Position = New Vector2 (0,0)
...or any other numbers. But I tend to like the first way, since it has a special command and everything.
Oh, and by the way, if you were dealing with 3D stuff, there is something called Vector3, which also keeps a Z variable.
Anyway, with Vector2 you have an X and a Y variable, and those can be changed independently. So you can do this for example, once you've set up the variable:
Position.X = 5;
...which makes the X value 5, leaving the total values at (5,0).
In Paper Zeppelin I use a couple of these to track things that have X and Y values, namely position (hence the example) and speed. With speed what I'm actually doing is showing the change in position, so almost everything has something like this in it's little robot update code:
Position.X = Position.X + Speed.X;
That way, everything that would change the speed of an object only changes the speed value. In contrast, The Thief's Tale handled everything by modifying just the position of the objects on screen. That worked only because I was dealing with so few objects (like 1-2, tops depending on whether or not something was trying to stab you). That would fall down in Paper Zeppelin, the code just wouldn't work.
Anyway, this is all a long way of saying what I started with, mainly that I can set the X and Y values of a Vector2 as float variables (less than whole numbers). So I can say, set the speed for the backdrop at 1, which moves the backdrop a nice slow 1 pixel per frame. The ground all moves at a speed of 2, so when I have them both it creates a nice parallax effect (this not this).
When I put clouds in though, I really wanted to create a multiple layer parallax effect. When things move at lots of different speeds and are stacked correctly, it implies a lot of motion and a great deal of depth. So for kicks I told the clouds to move at a speed of 1.5, and wouldn't you know it, they move slower than the ground but faster than the backdrop. The 3D effect is pretty ice cold (which is cooler than being cool). Also, since I can stack things up pretty high and float variables can be staggeringly specific (I can make the clouds move at 1.12345 pixels per frame if I felt like it), the Paper Engine can officially handle more things at the same time than the Super Nintendo is capable of doing. Sweet.
Getting to the titles, I got the player lives system to work right. So now, if you die it creates a crasher (sometimes..it's a work in progress) falls to the ground and leaves a smoking Hindenburg-esque wreck. Then, if you have lives it spawns up a new player of the same type that just got taken out. Hypothetically, if player 4 eats crap, it'll spawn up another player 4, which is good since the controller assignment is tied into the player number. Further, when you pop back into the world the game makes you invincible for a short period of time.
I did this using a 2 step process. First, when you spawn up you get 150 hp. The robot code for each player says that if you have more than 3 hp, to go ahead and subtract 1 every frame. So during this period if a player is hit, they just take the shot. Losing 1 hp from whatever doesn't really matter when you have 100+.
Second, I told the draw code to draw players if they had fewer than 4 hp (the normal amount) or if they can more than 3 and the hp was an even number. Hence, only draw every other time if you have more than the normal amount of hp. What that does is make you flicker just a bit and appear transparent for the most part. It looks good, really good. Like the kind of thing that would be in a Super Nintendo game, provided it could handle the parallax awesomeness.
I've been through the desert on a horse with no name...It felt good to be out of the rain...In the desert you can remember your name...
I also got the background elements popping a little bit more, which falls squarely into the "good" category. So now Paper Zeppelin has background clouds in it. I discovered that the structure called Vector2 can handle float variables. I'll back that up just a bit. In C#, there is a special kind of command called a Vector2 that holds an X and Y variable. You can start one up like this:
Vector2 Position = Vector2.Zero;
What that means is to start a Vector2 type variable and make it (0,0). You could also do this:
Vector2 Position = New Vector2 (0,0)
...or any other numbers. But I tend to like the first way, since it has a special command and everything.
Oh, and by the way, if you were dealing with 3D stuff, there is something called Vector3, which also keeps a Z variable.
Anyway, with Vector2 you have an X and a Y variable, and those can be changed independently. So you can do this for example, once you've set up the variable:
Position.X = 5;
...which makes the X value 5, leaving the total values at (5,0).
In Paper Zeppelin I use a couple of these to track things that have X and Y values, namely position (hence the example) and speed. With speed what I'm actually doing is showing the change in position, so almost everything has something like this in it's little robot update code:
Position.X = Position.X + Speed.X;
That way, everything that would change the speed of an object only changes the speed value. In contrast, The Thief's Tale handled everything by modifying just the position of the objects on screen. That worked only because I was dealing with so few objects (like 1-2, tops depending on whether or not something was trying to stab you). That would fall down in Paper Zeppelin, the code just wouldn't work.
Anyway, this is all a long way of saying what I started with, mainly that I can set the X and Y values of a Vector2 as float variables (less than whole numbers). So I can say, set the speed for the backdrop at 1, which moves the backdrop a nice slow 1 pixel per frame. The ground all moves at a speed of 2, so when I have them both it creates a nice parallax effect (this not this).
When I put clouds in though, I really wanted to create a multiple layer parallax effect. When things move at lots of different speeds and are stacked correctly, it implies a lot of motion and a great deal of depth. So for kicks I told the clouds to move at a speed of 1.5, and wouldn't you know it, they move slower than the ground but faster than the backdrop. The 3D effect is pretty ice cold (which is cooler than being cool). Also, since I can stack things up pretty high and float variables can be staggeringly specific (I can make the clouds move at 1.12345 pixels per frame if I felt like it), the Paper Engine can officially handle more things at the same time than the Super Nintendo is capable of doing. Sweet.
Getting to the titles, I got the player lives system to work right. So now, if you die it creates a crasher (sometimes..it's a work in progress) falls to the ground and leaves a smoking Hindenburg-esque wreck. Then, if you have lives it spawns up a new player of the same type that just got taken out. Hypothetically, if player 4 eats crap, it'll spawn up another player 4, which is good since the controller assignment is tied into the player number. Further, when you pop back into the world the game makes you invincible for a short period of time.
I did this using a 2 step process. First, when you spawn up you get 150 hp. The robot code for each player says that if you have more than 3 hp, to go ahead and subtract 1 every frame. So during this period if a player is hit, they just take the shot. Losing 1 hp from whatever doesn't really matter when you have 100+.
Second, I told the draw code to draw players if they had fewer than 4 hp (the normal amount) or if they can more than 3 and the hp was an even number. Hence, only draw every other time if you have more than the normal amount of hp. What that does is make you flicker just a bit and appear transparent for the most part. It looks good, really good. Like the kind of thing that would be in a Super Nintendo game, provided it could handle the parallax awesomeness.
I've been through the desert on a horse with no name...It felt good to be out of the rain...In the desert you can remember your name...
Subscribe to:
Posts (Atom)