Sunday, 27 September 2015

Shot Prediction

Phew. After a long, exhausting day taking a refresher course on geometry/vectors, we have a shot prediction calculation to give the goalie some diving AI.

Thanks to Mr Chong for his article:

The goalie isn't programmed yet, but the important thing is we can predict where the shot is going to cross the goal line (or any other line for that matter):

Here's some code:

1:  Point CollisionDetector::predict_intersection(const Point& position, const Math::Vector3 &direction, const Line &line, bool right_normal){  
2:   Point intersection;  
4:   // head of ball is position  
5:   Point ball_head = position;  
6:   // tail of ball is position plus direction  
7:   Point ball_tail(position.x + direction.x, position.y + direction.y);  
9:   // head of line is start of line  
10:   Point line_head(line.x, line.y);  
11:   // tail of line is end of line  
12:   Point line_tail(line.x + line.w, line.y);  
14:   Math::Vector3 vball(ball_tail.x - ball_head.x, ball_tail.y - ball_head.y);  
15:   Math::Vector3 vline(line_tail.x - line_head.x, line_tail.y - line_head.y);  
17:   // toV2b is vector from point to start of line  
18:   double perp1 = vball.perpProduct(vline.normalised());  
19:   Math::Vector3 toV2b(line_head.x - ball_head.x, line_head.y - ball_head.y);  
20:   double perp2 = toV2b.perpProduct(vline.normalised());  
22:   /*  
23:   * length is calculated from the similar triangles ratio  
24:   * it is later used as magnitude for a vector  
25:   * that points in v1's direction  
26:   */  
27:   double length = perp2 / perp1 * vball.magnitude();  
28:   Math::Vector3 length_v1 = vball;  
29:   length_v1 = length_v1 * length;  
31:   /*  
32:   * extend to locate the exact location of collision point  
33:   */  
34:   intersection.x = ball_head.x + length_v1.x;  
35:   intersection.y = ball_head.y + length_v1.y;  
37:   return intersection;  
38:  }  

Friday, 25 September 2015

The Behaviour Stack

A bit of technical stuff.

So the game was designed from the beginning with a focus on the AI sub system. I wanted it to be
flexible enough to add some really interesting AI later, both to make the game more challenging to play (and develop!) and also to make cpu v cpu matches more meaningful in a career mode.

Taking advantage of the state machine pattern, the player is a state machine in itself and it has states such as "running," "dribbling" etc. with only react to outside conditions and update the player animation. For example, if the player's velocity is non zero, he automatically goes into the running state. This merely loads in the correct animation frames and updates the animation each frame. Likewise, the running state transitions into the dribbling state if the ball is under the players control. The only difference is that the ball is knocked forward on contact.

This has nothing to do with AI so far.

The player *has a* brain object. The brain is responsible for surveying the game environment (and team instructions) to make decisions and trigger "behaviours." A behaviour is a locomotion controller such as "seek," "interpose" or "jump."

For example, the seek behaviour is triggered when the brain wants the player to run to a specific location on the pitch. It is only the behaviour object which has privileges to directly update the player's velocity property.

A special vase in the behaviour space is the jump behaviour. Since the jump behaviour must set the players z velocity, it is correctly placed in the AI::Locomotion space, but can create an unwanted side effect if the brain decides to initiate a seek behaviour before the player has come back to earth. We then end up with a player floating around in mid air (as pointed out before, for playability reasons, the player does not react like a regular physical object, merely a sprite moving around the screen with no acceleration or outside forces and therefore there is no gravity applied to him to correct the problem).

The solution for this was to think in terms of real world objects (OO ftw). What's really going on is that your brain knows it wants to run somewhere, but you can't execute the physical movements (behaviour/locomotion) necessary to achieve the goal whilst you are in the middle of the jump.

So now the brain manages a queue of behaviours and each behaviour object has a method to check "canStop()." Most behaviours are able to stop immediately, but in the case of the jump behaviour, it will only return true when the player is back on the ground again. When false is returned, the brain adds the behaviour to the queue and, each update, if there is anything in the queue it will try to switch tot he next behaviour in the queue.

Thursday, 24 September 2015

Goalie Jump

The goalkeeper can now do his first variety of basic save - a straight jump in the air.


Turns out there was a wee glitch in the camera (see previous vids) where it stuttered with small ball movements. It's a bit smoother now:

Tuesday, 22 September 2015

Hybrid Gameplay

Edit, lets put the video first. Most people don't read this shit anyway ;)

So, the idea is to have a dribbling system that combines the scheme from Sensi with that of Kickoff.

On of the big differences between the two games was that kickoff had a kind of pinball, very difficult to master, dribbling system whilst in sensi the ball generally stuck to your feet as you ran.

In Kickoff, the player knocked the ball forward on impact and it was not possible (except for very specific and skillful situations) to turn whilst running with the ball, but in sensi you could weave around at will without losing the ball.

This was probably the biggest difference between the games and a huge bone of contention between the respective "fan boys." With the dust settled, lets look back with impartiality.

It is my view that sensi appealed to younger and casual players (a much bigger market) as it was immediately gratifying to play. That's not to say it didn't have depth, it certainly can be claimed that it achieved the goal of that age old mantra: "easy to play, hard to master."

Kickoff, however, was the most infuriating experience until you really got good at the game. The ball was very difficult to control and scoring was almost impossible. But once you mastered it, boy that game was so gratifying. Scoring a goal against your buddy actually meant something. In your face!!!! It also had a somehow elegant gameplay side-effect that the faster you ran with the ball, the harder it was to control and the more likely you were to lose it (just like real footy).

Anyway, the idea with senseless, is to make a dribbling mechanic that falls somewhere in the middle. We'll have the nice "physical" aspect of the ball as it's knocked forward with every touch but, depending on the skill of the player, you will still be able to turn and weave freely if you time it right.  Players with a higher rating for dribbling will knock the ball forward a shorter distance, and will be more like to keep the ball under control after turning. Perhaps players like Messi will have the ball stuck to their feet like in sensi.

Sunday, 20 September 2015

Ball Physics

Just tweaking the ball physics. Looks and, more importantly, feels great!


An interesting development aid - almost the whole pitch on screen! :)

Saturday, 19 September 2015

Aftertouch Reimplemented

Good enough to kick on with the match engine!

Short Passing Tweaked

Tweaked the receiving player to connect with the pass better.

Short Passing

The idea is that by tapping the fire button, you can pass to the nearest player. This gets around the 8 direction limitation for a slick passing game.

Friday, 18 September 2015

Importance of Air Resistance

A while ago I saw a great lecture/presentation by Dino Dini (creator of Kick Off etc) and he made a comment about the importance of air resistance. Didn't quite understand what he was getting at. I do now!

The ball is being kicked with the same force in both videos. Without simulating air resistance, you can't get a realistic long/high goalkeeper kick without the ball flying off the pitch (or bouncing once and then flying off too quickly for players to react).

So, according to Dino, games that didn't simulate air resistance had to hard code a fake vertical bounce to keep the ball in play. Interesting stuff (for a nerd).

Thursday, 17 September 2015

Just a Kickabout

Footy Games

While we were all arguing over FIFA and PES, the best footy game was released in Japan, in 2004!!!

I give you Football Kingdom. Just check out the net physics on this thing! Ten years ago!

Compare with FIFA 2005:

Website Bugfix

The ratings popup on the database website now works with more than one table on the page. Woot. (user/pass: guest)

Has Anything Changed?

Wednesday, 16 September 2015

Dev Debug Features (or "I Has Made Progress Bar!!111oneone")

Just a couple of interesting devel features to track the fire press for shot types, and drop the ball on the screen with the mouse.

The flickering is just from the capture app, honest!


Under the hood, the progress bar is simply a "draw rect" and "fill rect" call, so it's extremely fast.

Thursday, 10 September 2015

Mouse Mat

With a good optical/laser mouse, I'd always thought the mouse pad was obsolete. Wrong! A good pad makes a hell of a difference, and not just for gaming.

I decided to try out a Razer Goliathus and now I'd never go back! Absolutely fantastic. Highly recommend you give this a try.

Personally, I prefer the control edition.

Ron Gilbert

Just before he created the greatest adventure game of all time, Ron Gilbert wrote this:


Decoupling the Physics

Proof of concept (see

The point is to keep the gameplay speed consistent regardless of how fast the users PC can render the graphics. So, as a test, the game should run at the same speed with monitor VSYNC turned on and off. VSYNC turned on kind of emulates a PC with lower rendering rates.

Not only would it mess the game up on different PC's, but it would make online play impossible!

You can see the problem when the loop depends on the frame rate:

Here it is decoupled:

A nod to Glenn Fiedler for a great article on the topic:

Here's the game loop:

1:    //  
2:    // calculate timing metrics  
3:    //  
4:    double new_time = SDL_GetTicks();  
5:    double frame_time = (new_time - current_time) /1000;  
7:    if ( frame_time > target_frame_time)  
8:      frame_time = target_frame_time;  
10:    current_time = new_time;  
11:    accumulator += frame_time;  
13:    //  
14:    // update physics as many times as possible in remaining frame time  
15:    //  
16:    while ( accumulator >= physics_step ){  
17:      getDefaultCamera()->update( physics_step );  
18:      for( unsigned int i = 0; i < physics_list.size(); ++i ) {  
20:        physics_list[i]->update( physics_step );  
21:      }  
22:      accumulator -= physics_step;  
23:    }  
25:    //  
26:    // do rendering  
27:    //  
28:    translate( getDefaultCamera()->getViewport().x, getDefaultCamera()->getViewport().y );
29:    render();  

Wednesday, 9 September 2015

Saturday, 5 September 2015

Goalkeeper Positioning

Finally got around to giving the goalie some movement and "rushing out" AI.

thumbnail for sharing