Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
The Polling ProblemSpeaker NameDino Dini NHTV University of Applied Sciences
A bit about meI have been designing and programming video games forover 30 years.I am originally from the UK, live in the ...
The focus of this talkA = AutonomousI = InteractiveComputers and their languages are generally good for Aand less good for...
Roman NumbersThe Romans had no symbol for 0.The result was that it held back their development oftechnology and science.
Doing NothingDo we lack an appropriate representation in computerscience for doing nothing?
Turings VisionTuring was a mathematician, and was interested incomputers as a device for solving problems.Mathematically, ...
Data In, Data Out     IMMUTABLE                                COMPUTER                             IMMUTABLE   INPUT DATA...
Its a function, JimComputers were developed to process data in the manner of a function.We would like these to execute in ...
The interactive world is ongoingThe interactive world does not fit this model well.Tasks take time and need to pass inform...
Mutable input dataWe normally do not consider the possibility that the input data could changewhile we perform computation...
Mutable input dataThis is unfortunately common in the real world, and a necessity in effectivegame AI.                  My...
The Polling ProblemQ: What do you get when you try to process unpredictable and timedependent input with a Turing machine?
The Polling ProblemQ: What do you get when you try to process unpredictable and timedependent input with a Turing machine?...
Say "When"             While(true) {                   if(!GlassAcceptablyFull()) {                         // erm... do n...
Say "When"             While(true) {                   if(!GlassAcceptablyFull()) {                         // erm... do n...
Say "When"             While(true) {                   if(!GlassAcceptablyFull() &&                         GetGlassStatus...
Say "When"             // Pourer             While(true) {                   if(!Heard("When!")) {                      Ke...
Say "When"             // Pourer             While(true) {                   if(!Heard("When!")) {                      Ke...
Say "When"             // Pourer             While(true) {                   if(!Heard("When!")) {                      Ke...
Say "When"             // Pourer             While(true) {                   if(!Heard("When!") && !GlassFull()) {        ...
If and WhenIf       ●   A change in state       ●   Dependent on current state       ●   When the If is executedWhen      ...
When?Computers are not really designed for When. They are designed aroundprocedural logic, effectively a series of ifs exe...
When you have MessagesThe typical solution is to use messages, but this does not directly solve thepolling problem.
"When you get the message, do something else"// pseudocodefunction WaitForGlassFill() {     messageHandler = new Handler(O...
You have to keep checking for data changed bymessage handlers// pseudocodefunction WaitForGlassFill() {      int onMessage...
You have to keep checking for data changed bymessage handlers// pseudocodefunction WaitForGlassFill() {      int onMessage...
I wish I could simply say...function WaitForGlassFill() {    SetAnimationState("ObserveFilling");    When(ReceivedMessage(...
I wish I could simply say...function WaitForGlassFill() {    SetAnimationState("ObserveFilling");    When(ReceivedMessage(...
I want reusable behaviours// anything can pause, its a substate// needs to be interruptible!function Pause(int _count) {  ...
I want reusable behavioursfunction WaitForGlassFill() {      SetAnimationState("ObserveFilling");      When(ReceivedMessag...
I want reusable behavioursfunction WaitForGlassFill() {      SetAnimationState("ObserveFilling");       When(ReceivedMessa...
I want reusable behavioursfunction WaitForGlassFill() {      SetAnimationState("ObserveFilling");      When(ReceivedMessag...
I want reusable behavioursfunction WaitForGlassFill() {      SetAnimationState("ObserveFilling");      When(ReceivedMessag...
I want reusable behavioursfunction WaitForGlassFill() {      SetAnimationState("ObserveFilling");       When(ReceivedMessa...
Messages must change the "program counter"function WaitForGlassFill() {      SetAnimationState("ObserveFilling");      Whe...
Messages must change the "program counter"function WaitForGlassFill() {      SetAnimationState("ObserveFilling");      Whe...
Why Game AI is Difficult - Summary●   No direct language support for multitasking●   Where such support exists, there rema...
Why Game AI is Difficult - SummaryPolling would seem to be at the heart of the problem.Solutions should focus on this prob...
Why Game AI is Difficult - SummaryTypical solutions involve the creation of a virtual machine with a separatedomain specif...
Virtual machine solutions                                       Script               Virtual      Virtual   Real          ...
Virtual machine solutions                                             Script               Virtual      Virtual   Real    ...
Traditional: A light switch// With pollingfunction LightSwitch() {      bool lit=false;      while(true) {          if(Swi...
Traditional: A light switch with delayfunction LightSwitch() {      Timer startTime;    bool lit=false;      while(true) {...
Messages: A light switch// Oh nice this is now trivial...// But only because theres no temporal behaviourfunction LightSwi...
Messages: A light switch with delayfunction LightSwitch() {      Timer startTime;      bool lit=false;      When(ReceivedM...
No Polling: A light switch// pseudocode of language supporting coroutines, messages// and state transitionsfunction LightS...
No Polling: A light switch with delay// pseudocode of language supporting coroutines, messages// and state transitionsfunc...
PROC system: A light switch with fadefunction FadeTo(float to) {      do { float d = (to - light.currentBrightness)*0.1f; ...
The PROC system●   Started as coroutine system in 68000 assembler●   Later implemented in C and C++ where messages were ad...
The PROC system●   Implements a HFSM with message handling protocols●   Implementation uses nested coroutines●   Has prove...
PROC system architecture in C# and Unity 3D     IEnumerator method (a PROC)               Control object with a stop flag ...
PROC system message handling                                      Under Attack       Base                                 ...
PROC system message handling                                      Under Attack       Base                                 ...
PROC system message handling                                      Under Attack       Base                                 ...
PROC system message handling                                      Under Attack       Base                                 ...
PROC system message handling                                      Under Attack       Base                                 ...
PROC system message handling                                      Under Attack       Base                                 ...
PROC system message handling                          Under Attack          Base                               Noise heard...
PROC system message handling                           Under Attack          Base                                Noise hea...
Implementation in C# / Unity 3D●   Currently uses a pre-processor●   Message handlers are delegates inside methods that ca...
Conclusion●   At the heart of the difficulty of robust and rich behaviour in games is the    limitations of popular progra...
Conclusion●   The core problem is how to manage the response to input data that    changes over time●   This input data is...
Conclusion●   To solve these problems, which are connected not only with game AI, but    also with the general problems of...
Thank you        Dino Dini        email: dndn1011@gmail.com        Twitter: dndn1011
Upcoming SlideShare
Loading in …5
×

The polling problem

2,430 views

Published on

GDC 2013 AI summit talk

  • Be the first to comment

The polling problem

  1. 1. The Polling ProblemSpeaker NameDino Dini NHTV University of Applied Sciences
  2. 2. A bit about meI have been designing and programming video games forover 30 years.I am originally from the UK, live in the Netherlands andnow teach Video Game Programming at NHTV in Breda(IGAD).I am quite well known in the VG industry outside of theUS for making a series of games concerned with anobscure sport known as Football, not to be confused withthe US popular sport "Handegg".
  3. 3. The focus of this talkA = AutonomousI = InteractiveComputers and their languages are generally good for Aand less good for I.My focus is solving the problem at the programminglanguage level, rather than through the creation ofvirtual machine architectures (such as Behaviour Trees).
  4. 4. Roman NumbersThe Romans had no symbol for 0.The result was that it held back their development oftechnology and science.
  5. 5. Doing NothingDo we lack an appropriate representation in computerscience for doing nothing?
  6. 6. Turings VisionTuring was a mathematician, and was interested incomputers as a device for solving problems.Mathematically, there was no concept of doing nothing.
  7. 7. Data In, Data Out IMMUTABLE COMPUTER IMMUTABLE INPUT DATA ALGORITHM OUTPUT DATAThe program runs. The program terminates, all might be well.The program runs. The program never terminates. Disaster.If the program terminates before it has finished its job, thats an aberration.Why on earth should one want to stop the program, apart from being too impatient to wait?Doing nothing makes no sense; simply do not run the program.
  8. 8. Its a function, JimComputers were developed to process data in the manner of a function.We would like these to execute in zero time.Is the temporal nature of computation merely an inconvenience?
  9. 9. The interactive world is ongoingThe interactive world does not fit this model well.Tasks take time and need to pass information between each otherasynchronously.Computations must contend with mutable input data.
  10. 10. Mutable input dataWe normally do not consider the possibility that the input data could changewhile we perform computations on it... What is the square root of 345 ? OK working on it... Nearly there... Wait, sorry I meant 346... !@@#$@!!
  11. 11. Mutable input dataThis is unfortunately common in the real world, and a necessity in effectivegame AI. My GPS loves to say "Recalculating..."
  12. 12. The Polling ProblemQ: What do you get when you try to process unpredictable and timedependent input with a Turing machine?
  13. 13. The Polling ProblemQ: What do you get when you try to process unpredictable and timedependent input with a Turing machine?A: A polling loop While(!EscapePressed()) { // ugh, there must be a better way if(pathPlanner->ExecSingleStep()) { break; } }
  14. 14. Say "When" While(true) { if(!GlassAcceptablyFull()) { // erm... do nothing??? yield(); } else { Say("When!"); break; } }
  15. 15. Say "When" While(true) { if(!GlassAcceptablyFull()) { // erm... do nothing??? yield(); } else { Say("When!"); break; } }
  16. 16. Say "When" While(true) { if(!GlassAcceptablyFull() && GetGlassStatus() == Normal) { // erm... do nothing??? yield(); } else { Say("When!"); break; } }
  17. 17. Say "When" // Pourer While(true) { if(!Heard("When!")) { KeepPouring(); yield(); } else { StopPouring(); } }
  18. 18. Say "When" // Pourer While(true) { if(!Heard("When!")) { KeepPouring(); yield(); } else { StopPouring(); } }
  19. 19. Say "When" // Pourer While(true) { if(!Heard("When!")) { KeepPouring(); yield(); } else { StopPouring(); } }
  20. 20. Say "When" // Pourer While(true) { if(!Heard("When!") && !GlassFull()) { KeepPouring(); yield(); } else { StopPouring(); } }
  21. 21. If and WhenIf ● A change in state ● Dependent on current state ● When the If is executedWhen ● A change in state ● Dependent on resulting state ● When a specified state change occurs
  22. 22. When?Computers are not really designed for When. They are designed aroundprocedural logic, effectively a series of ifs executed in a sequence.When is actually a more natural way to express responses to timedependent input.
  23. 23. When you have MessagesThe typical solution is to use messages, but this does not directly solve thepolling problem.
  24. 24. "When you get the message, do something else"// pseudocodefunction WaitForGlassFill() { messageHandler = new Handler(OnGlassAcceptablyFull, delegate(Message m) { // code executed on message // Exit from doing nothing // But how? }); SetAnimationState("ObserveFilling"); while(true) { // do nothing Yield(); }}
  25. 25. You have to keep checking for data changed bymessage handlers// pseudocodefunction WaitForGlassFill() { int onMessage=0; bool stopFlag; messageHandler = new Handler(eOnGlassAcceptablyFull, delegate(Message m) { stopFlag = true; onMessage = eOnGlassAcceptablyFull; }); SetAnimationState("ObserveFilling"); while(!stopFlag) { // do nothing Yield(); } switch(onMessage) { // ..etc..
  26. 26. You have to keep checking for data changed bymessage handlers// pseudocodefunction WaitForGlassFill() { int onMessage=0; bool stopFlag; messageHandler = new Handler(eOnGlassAcceptablyFull, delegate(Message m) { stopFlag = true; onMessage = eOnGlassAcceptablyFull; }); SetAnimationState("ObserveFilling"); Hello, Polling while(!stopFlag) { // do nothing Yield(); } switch(onMessage) { // ..etc..
  27. 27. I wish I could simply say...function WaitForGlassFill() { SetAnimationState("ObserveFilling"); When(ReceivedMessage(eOnGlassAcceptablyFull)) { SayWhen(); StartNormalAnimationState(); End; // this will stop this coroutine } DoNothing(); // until coroutine terminated}
  28. 28. I wish I could simply say...function WaitForGlassFill() { SetAnimationState("ObserveFilling"); When(ReceivedMessage(eOnGlassAcceptablyFull)) { SayWhen(); StartNormalAnimationState(); Here I have a trivial case, but maybe I want some End; // this will stop this coroutine other tasks going on here } too, like watching out for a sniper. DoNothing(); // until coroutine terminated}
  29. 29. I want reusable behaviours// anything can pause, its a substate// needs to be interruptible!function Pause(int _count) { int count=_count; while(count-- > 0) { yield; } end;}
  30. 30. I want reusable behavioursfunction WaitForGlassFill() { SetAnimationState("ObserveFilling"); When(ReceivedMessage(eOnGlassAcceptablyFull)) { SayWhen(); StartNormalAnimationState(); end; } while(true) { Pause(Random(25,50)); GlanceAtRandomPointOfInterest(); yield; } }
  31. 31. I want reusable behavioursfunction WaitForGlassFill() { SetAnimationState("ObserveFilling"); When(ReceivedMessage(eOnGlassAcceptablyFull)) { SayWhen(); StartNormalAnimationState(); end; } This needs to be interuptable when WaitForGlassFill handles a while(true) { message and switches Pause(Random(25,50)); task. GlanceAtRandomPointOfInterest(); yield; } }
  32. 32. I want reusable behavioursfunction WaitForGlassFill() { SetAnimationState("ObserveFilling"); When(ReceivedMessage(eOnGlassAcceptablyFull)) { SayWhen(); StartNormalAnimationState(); end; } And what if we want to do something that is not while(true) { instantaneous? Pause(Random(25,50)); GlanceAtRandomPointOfInterest(); yield; } }
  33. 33. I want reusable behavioursfunction WaitForGlassFill() { SetAnimationState("ObserveFilling"); When(ReceivedMessage(eOnGlassAcceptablyFull)) { SayWhen(); Pause(50); StartNormalAnimationState(); end; } while(true) { Pause(Random(25,50)); GlanceAtRandomPointOfInterest(); yield; } }
  34. 34. I want reusable behavioursfunction WaitForGlassFill() { SetAnimationState("ObserveFilling"); When(ReceivedMessage(eOnGlassAcceptablyFull)) { SayWhen(); Pause(50); StartNormalAnimationState(); end; No! Cant do this. It would } cause the calling object to Pause (at best). while(true) { Pause(Random(25,50)); GlanceAtRandomPointOfInterest(); yield; } }
  35. 35. Messages must change the "program counter"function WaitForGlassFill() { SetAnimationState("ObserveFilling"); When(ReceivedMessage(eOnGlassAcceptablyFull)) { SwitchTo(GlassFullEnough); } State(Normal): while(true) { Pause(Random(25,50)); GlanceAtRandomPointOfInterest(); yield; } State(GlassFullEnough): Pause(50); // delay before responding // etc }
  36. 36. Messages must change the "program counter"function WaitForGlassFill() { SetAnimationState("ObserveFilling"); When(ReceivedMessage(eOnGlassAcceptablyFull)) { SwitchTo(GlassFullEnough); This concept is going } against the grain of most State(Normal): programming languages and computer while(true) { architecture. Pause(Random(25,50)); GlanceAtRandomPointOfInterest(); It has to be faked. yield; } State(GlassFullEnough): Pause(50); // delay before responding // etc }
  37. 37. Why Game AI is Difficult - Summary● No direct language support for multitasking● Where such support exists, there remains a lack of semantics for switching execution state synchronously (that is, without polling)● Polling does not scale well● Complex time dependent interactions mean that without a proper methodology behaviours must be kept simple to reduce complexity
  38. 38. Why Game AI is Difficult - SummaryPolling would seem to be at the heart of the problem.Solutions should focus on this problem.
  39. 39. Why Game AI is Difficult - SummaryTypical solutions involve the creation of a virtual machine with a separatedomain specific language or encoding of programs in data structures ratherthan code.
  40. 40. Virtual machine solutions Script Virtual Virtual Real Domain Machine Machine: Machine Specific (C#) Behaviour (C++) Language Trees Multi-tasking support (yield)
  41. 41. Virtual machine solutions Script Virtual Virtual Real Domain Machine Machine: Machine Specific (C#) Behaviour (C++) Language Why cant we just Trees have a single language as the Multi-tasking solution? support (yield)
  42. 42. Traditional: A light switch// With pollingfunction LightSwitch() { bool lit=false; while(true) { if(Switch.state == "Down" && Switch.previousState == "Up") { lit = !lit; SetLightState(lit); } yield; }}
  43. 43. Traditional: A light switch with delayfunction LightSwitch() { Timer startTime; bool lit=false; while(true) { if(Switch.state == "Down" && Switch.previousState == "Up") { if(lit) { lit = false; SetLightState(lit); } else { lit = true; startTime = CurrentTime(); SetLightState(lit); } } if(lit && CurrentTime()-startTime > MaxOnTime) { lit = false; SetLightState(false); } yield; }}
  44. 44. Messages: A light switch// Oh nice this is now trivial...// But only because theres no temporal behaviourfunction LightSwitch() { bool lit=false; When(ReceivedMessage(eSwitchPressed)) { lit != lit; SetLightState(lit); }}
  45. 45. Messages: A light switch with delayfunction LightSwitch() { Timer startTime; bool lit=false; When(ReceivedMessage(eSwitchPressed)) { if(lit) { lit = false; SetLightState(lit); } else { lit = true; startTime = CurrentTime(); SetLightState(lit); } } while(true) { if(lit && CurrentTime()-startTime > MaxOnTime) { lit = false; SetLightState(false); } yield; }}
  46. 46. No Polling: A light switch// pseudocode of language supporting coroutines, messages// and state transitionsfunction LightSwitch() { bool lit=false; while(true) { state UnlitState: when(ReceivedMessage(eSwitchPressed)) { goto state LitState; } lit=false; SetLightState(lit); substate(DoNothing()); state LitState: when(ReceivedMessage(eSwitchPressed)) { goto state UnlitState; } lit=true; SetLightState(lit); substate(DoNothing()); }}
  47. 47. No Polling: A light switch with delay// pseudocode of language supporting coroutines, messages// and state transitionsfunction LightSwitch() { bool lit=false; while(true) { state UnlitState: when(ReceivedMessage(eSwitchPressed)) { goto state LitState; } lit=false; SetLightState(lit); substate(DoNothing()); state LitState: when(ReceivedMessage(eSwitchPressed)) { goto state UnlitState; } lit=true; SetLightState(lit); substate(Pause(50)); // That was easy to add! substate(DoNothing()); }}
  48. 48. PROC system: A light switch with fadefunction FadeTo(float to) { do { float d = (to - light.currentBrightness)*0.1f; light.currentBrightness += d; if(d < 0.001f) { end; } } }function LightSwitch() { Timer startTime; bool lit=false; while(true) { state UnlitState: when(ReceivedMessage(eSwitchPressed)) { goto state LitState; } substate(FadeTo(0)); substate(DoNothing()); state LitState: when(ReceivedMessage(eSwitchPressed)) { goto state UnlitState; } substate(FadeTo(1)); substate(DoNothing());} }
  49. 49. The PROC system● Started as coroutine system in 68000 assembler● Later implemented in C and C++ where messages were added● Most recently implemented in C# in Unity 3D
  50. 50. The PROC system● Implements a HFSM with message handling protocols● Implementation uses nested coroutines● Has proven very effective at managing complex behaviours● A solution within the programming language itself
  51. 51. PROC system architecture in C# and Unity 3D IEnumerator method (a PROC) Control object with a stop flag looped switch statement states Message handlers Message handlers states Message handlers states Message handlers states Straight code Substate iterators (polling for stop flag)
  52. 52. PROC system message handling Under Attack Base Noise heard Patrol Goto next patrol point Goto position
  53. 53. PROC system message handling Under Attack Base Noise heard Patrol Message manager Goto next patrol point Noise heard Goto position
  54. 54. PROC system message handling Under Attack Base Noise heard Patrol Message manager Goto next patrol point Noise heard Goto position
  55. 55. PROC system message handling Under Attack Base Noise heard Patrol Message manager Goto next patrol point Noise heard Goto position
  56. 56. PROC system message handling Under Attack Base Noise heard Patrol Message manager Goto next patrol point Noise heard Terminate Goto position
  57. 57. PROC system message handling Under Attack Base Noise heard Patrol Message manager Goto next patrol point Terminate Noise heard
  58. 58. PROC system message handling Under Attack Base Noise heard Patrol Message manager Investigate Noise Noise heard
  59. 59. PROC system message handling Under Attack Base Noise heard Patrol Message manager Investigate Noise Noise heard …
  60. 60. Implementation in C# / Unity 3D● Currently uses a pre-processor● Message handlers are delegates inside methods that can access local variables of the method● Termination of a task is implemented using a flag which is polled for● However, this polling is hidden
  61. 61. Conclusion● At the heart of the difficulty of robust and rich behaviour in games is the limitations of popular programming languages● Many popular solutions create a virtual machine to avoid these problems, often encoding the behaviours in data structures with domain specific languages.● However, with some small additions to existing languages, this problem could be avoided● Even without such languages, it is possible to create architectures that solve the problem directly within the language (albeit inelegantly).
  62. 62. Conclusion● The core problem is how to manage the response to input data that changes over time● This input data is not only from the player, but also between concurrent tasks● Polling is inescapable, but can be managed
  63. 63. Conclusion● To solve these problems, which are connected not only with game AI, but also with the general problems of scalable multi-tasking programs, you can use this heuristic: "Design your architecture to hide the polling problem as much as possible"
  64. 64. Thank you Dino Dini email: dndn1011@gmail.com Twitter: dndn1011

×