Yesterday I was quite thrilled with my progress on the game. I felt like implementing the game was a matter of adding game states, which would be quite a lot of work, but ultimately very much doable. There were some possibly hard implementation details with the rosters for each team and the league, and NPC team player logic (how each team values players, makes trades, drafts, etc.) might be difficult, but, at the very least, simple solutions could be rolled out easily, tested, and improved upon.
My optimism has come to an abrupt end. It’s the on-field logic that’s the really hard part. What’s worse, I can’t implement most of the rest of the game without knowing what stats players should have, and I can’t know what stats they should have until I’m pretty close to done with the on field engine.
The game is primarily based upon Madden, since I’ve always loved the idea of their Franchise mode, and yet always found inexcusable bugs with both the Franchise mode itself (both questionable design decisions as well as horrible user interfaces), and the on field action (players getting “sucked” into each other, stats not mattering (seriously – put a kicker in to block and he’ll do just fine in most of the games) as well as many others).
Please excuse my previous rambling paragraph, my point was that in order to implement a Franchise mode I need to know what stats are important to the actual game. I don’t want the Madden problem of a ton of different stats, most of which do diddly squat and just pollute the user interface and make decisions harder. Worse then that, I don’t want to find that I’ve written a bunch of file handling and logic and all that, only to realize that I actually want to add an acceleration variable to each player or something like that.
So yes, I need to actually make the on field part of the game work first. That wouldn’t be a problem, it’s just that coding a football game is really damn hard. I hate talking in ambiguities, so I’ll use the example of pathfinding here.
The easiest form of pathfinding is just placing the character in the spot you want them to be. So if the character needs to be at coordinates x: 34, and y:288, then we just simply put them there. One frame they’re here, the next frame they’re over there.
That’s basically not useful for a game. In one sense, it’s what I’m doing to set up the plays before the snap, but once the play is actually running it doesn’t actually contribute to the experience. What we need is some way of having the players move to where we want them to go.
The simplest way to do this is just to give the players a destination. Then we give them a maximum speed. Then we have them move towards the destination every frame. I guess the absolute simplest would be to give them maximum speeds in both the x and y axis, but that would result in them moving fastest on a diagonal. It takes some moderately hard trigonometry (actually the trig isn’t that hard, it’s just implementing it in code that’s fairly hard) to set the x and y velocities to the right levels, making sure the character doesn’t move faster then their maximum speed and yet also making sure that they move in a straight line to the goal.
That’s better, but football players do not get up to top speed in 1/100th of a second (I’m running the game at 100fps, there are good reasons for this, but that’s a different post). They need to accelerate in whatever direction, and they have differing momentum based on their individual weight. The next step in pathfinding is to add acceleration. This requires harder trigonometry and again, is harder to implement, but we need to make them accelerate in a straight line towards the goal, in addition to the complexity of the previous pathfinding system.
But wait! I’ve skipped over the actual hardest part of pathfinding: actually figuring out which spot to move to. The previous systems only work if we can figure out ahead of time which spot to move to. A cornerback who is sticking to his man in man coverage is a good example of this: he moves towards his man at all times. We might add a cushion so that he tries not to get beat deep. We might also add prediction, showing him the receivers route depending on his awareness stat, but the bottom line is that telling him to move to a certain spot will pretty much work for him.
But let’s imagine a left guard, who is asked to pull on a running play. We now need a system where he will try to follow his path or job on the play, which is pulling into the opposite B or C gap, but he also needs to react to any defenders that he should be blocking at that particular time. That doesn’t seem so hard on the surface, but consider this: 1) we need a system where he moves on a curved path that then straightens, 2) How important sticking to his path is decreases strongly the longer the play goes on, 3) We need logic that makes him intelligently block the players away from the running back, which means that he needs to move into his spot based on where they are, 4) If he breaks off his path, we need to figure out if he should get back onto his path, or just act according to what the defense is doing.
To break down 1), I have a system where I place a bunch of spots down for the player. The player will move to spot, then spot, then spot. As soon as they get to within 0.5 yards of the spot in both axis’s, x and y, they move towards the next spot. I could use a smaller radius, which would make the spots more accurate, but that would accentuate the problem with this solution: missing spots. If the player runs by their spot, they will stop and run back to their spot before continuing on to the next one. Imagine if a DT got a hand on the LG who is pulling and knocked the LG back a foot or so. That might cause him to miss his spot, so he will turn around, possibly hitting the runningback, but definitely not do anything useful and he’ll look extremely weird.
The only solution to this that I’ve come up with, and I’m very hopeful that I’ve just overlooked something, is to have a timing based pathfinding. So we have this player, and he has x milliseconds to move to the next spot. That way, even if he misses his spot, the logic will move him towards the next spot anyway. There is one major problems with this approach: I would need to manually figure out the proper timings for every job, and even every individual player. Too much time to get to the next spot, and they will stop over-top of their spot. Too little time, and they won’t do their job properly. Additionally, and this is just a hunch, but it appears to be less flexible to additional logic, such as finding defenders to block or what have you.
Problem 2, the importance of sticking to his path decreasing over time, implies that we need logic that makes the defenders look more and more blockable to the lineman over time. I first thought about doing pathfinding through this system, where the player, in this case a lineman, is attracted to his laid out path, as well as any blockable defenders. It didn’t work though, since the linemen would just move in a weird direction somewhere in between the two.
However, having an attraction system works perfectly to solve this problem. We have the lineman slowly less attracted to his path. Then, at some point he will become more attracted to a defensive player. At that point, he now moves to the defensive player and tries to block him out.
3) It’s actually not enough to make players move to a certain spot. What we need is for them to TRY to move to a certain spot. This is the really hard part that gives me nightmares. It’s also the fun part where I get to play around with a lot of stuff and really make stats such as weight, strength, anchoring, run blocking and others actually matter to the outcome of the play.
I’m not even close to solving this one, but imagine a defensive player, who is engaged with a blocker, but is trying to get to the quarterback. It doesn’t make sense to have him move to the quarterback. He needs to try to move to the quarterback, and take everything else into account. The way to solve this for every position I’m afraid boils down to focusing on one part of the game and implementing it, then moving on to the next tiny subset of behavior, and so on and so forth. Imagine how complex it gets when we need to make a linebacker try to avoid the blocker and then tackle the running back behind him.
4) Honestly, this is a problem that isn’t worth solving now, since I’ll be changing the logic so much doing the above that this might get fixed on the way there.
This was very long and rambling, but I hope it was somewhat educational. I know it’s only 10:24 but I’m very tired now and will be going to bed. I will probably edit this in the morning.