public Form1() { InitializeComponent(); // Sequence of events with the bubble engine is somewhat important when operating with groups // - Add engines first // - Then map engines group associations // - THEN add the impact bubbles to respective engines EngineId1 = myBubbles.AddEngine(); myBubbles.SetEngineTimerTrace(EngineId1, BubbleUtil.NativeTimerTraceCallback); EngineId2 = myBubbles.AddEngine(); myBubbles.SetEngineTimerTrace(EngineId2, BubbleUtil.NativeTimerTraceCallback); EngineGroupId = myBubbles.AddEngineGroup(EngineId1); myBubbles.AddEngineToGroup(EngineGroupId, EngineId2); MakeNewBubbleButton(); Util.ShowBang += new EventHandler <ShowBangEventArgs>(Util_ShowBang); // Both engines are associated with the same group. We will add new bubbles to either engine1 or // engine2, alternating between the two. Then the collision detection work is split with each engine // reporting on its bubbles, but comparing its workload over all bubbles in its engines group. Util.StartEngine(myBubbles, EngineId1, 200); Util.StartEngine(myBubbles, EngineId2, 200); bool paused = false; this.Deactivate += new EventHandler(delegate(object sender, EventArgs e) { if (paused) { return; } paused = true; Util.PauseAll(myBubbles, true); ButtonMoveTimer.Stop(); }); this.Activated += new EventHandler(delegate(object sender, EventArgs e) { if (paused == false) { return; } paused = false; ButtonMoveTimer.Start(); Util.PauseAll(myBubbles, false); }); ButtonMoveTimer.Interval = 100; ButtonMoveTimer.Tick += new EventHandler(ButtomMoveTimer_Tick); ButtonMoveTimer.Enabled = true; System.Windows.Forms.Timer invalidateCheck = new System.Windows.Forms.Timer() { Interval = 200, Enabled = true }; invalidateCheck.Tick += new EventHandler(delegate(object sender, EventArgs e) { foreach (BangButton but in ButtonList) { but.Invalidate(); } }); }