-
-
Notifications
You must be signed in to change notification settings - Fork 98
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
273: Add Two Phase Updates feature r=pathunstrom a=astronouth7303 Felt like writing a two-phase update system. This is so much easier to use with #263 that it's a soft requirement. This assumes that events signaled are queued and handled after all of the current event handlers are called. This skipped our usual discussion phase of things, where we debate designs first. Given that, feel free to completely rip this apart. Co-authored-by: Jamie Bliss <jamie@ivyleav.es>
- Loading branch information
Showing
5 changed files
with
142 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,4 +9,5 @@ tools to have when making games. | |
:maxdepth: 2 | ||
:caption: Included Features | ||
|
||
animation | ||
animation | ||
twophase |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
Two Phase Updates | ||
================= | ||
|
||
.. automodule:: ppb.features.twophase | ||
|
||
|
||
.. autoclass:: Commit | ||
|
||
.. autoclass:: TwoPhaseMixin | ||
:members: | ||
|
||
.. autoclass:: TwoPhaseSystem |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
""" | ||
A simple rendition of the three-body problem. Also demonstrates the use of | ||
two-phase updates. | ||
The three body problem comes from astrophysics. Basically, applying the | ||
gravitaional to three celestial bodies produces a problem that does not have a | ||
perfect mathematical solution, and must be solved through simulations. | ||
""" | ||
|
||
import ppb | ||
from ppb import BaseSprite, Vector | ||
from ppb.features.twophase import TwoPhaseMixin, TwoPhaseSystem | ||
|
||
|
||
class Planet(BaseSprite, TwoPhaseMixin): | ||
#: A constant to apply to gravity | ||
G_CONST = 1 | ||
|
||
velocity = Vector(0, 0) | ||
|
||
def get_bodies(self, scene): | ||
for planet in scene.get(kind=Planet): | ||
yield planet, (planet.position - self.position) | ||
|
||
def on_update(self, event, signal): | ||
# This assumes all planets have the same mass | ||
force = sum( | ||
( | ||
delta / (len(delta) ** 2) | ||
for planet, delta in self.get_bodies(event.scene) | ||
), | ||
Vector(0, 0) | ||
) | ||
|
||
self.velocity += force * self.G_CONST * event.time_delta | ||
|
||
self.stage_changes( | ||
position=self.position + self.velocity * event.time_delta | ||
) | ||
|
||
|
||
def setup(scene): | ||
scene.add(Planet(position=(3, 0), velocity=Vector(0, 1))) | ||
scene.add(Planet(position=(-3, 3), velocity=Vector(1, -1))) | ||
scene.add(Planet(position=(-3, -3), velocity=Vector(-1, 0))) | ||
|
||
|
||
if __name__ == "__main__": | ||
ppb.run(setup, systems=[TwoPhaseSystem]) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
""" | ||
A system for two phase updates: Update, and Commit. | ||
""" | ||
from dataclasses import dataclass | ||
from ppb.systems import System | ||
from ppb.events import EventMixin | ||
|
||
__all__ = 'Commit', | ||
|
||
|
||
@dataclass | ||
class Commit: | ||
""" | ||
Fired after Update. | ||
""" | ||
|
||
|
||
class TwoPhaseSystem(System): | ||
""" | ||
Produces the Commit event. | ||
""" | ||
|
||
def on_update(self, event, signal): | ||
signal(Commit()) | ||
|
||
|
||
class TwoPhaseMixin(EventMixin): | ||
""" | ||
Mixin to apply to objects to handle two phase updates. | ||
""" | ||
|
||
__staged_changes = None | ||
|
||
def stage_changes(self, **kwargs): | ||
""" | ||
Stage changes for the next commit. | ||
These are just properties on the current object to update. | ||
""" | ||
if self.__staged_changes is None: | ||
self.__staged_changes = {} | ||
self.__staged_changes.update(kwargs) | ||
|
||
def on_commit(self, event, signal): | ||
""" | ||
Commit changes previously staged. | ||
""" | ||
changes, self.__staged_changes = self.__staged_changes, {} | ||
if changes: | ||
for name, value in changes.items(): | ||
setattr(self, name, value) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
from ppb import GameEngine, BaseScene | ||
from ppb.testutils import Quitter | ||
from ppb.events import Update | ||
from ppb.features.twophase import TwoPhaseMixin, TwoPhaseSystem, Commit | ||
|
||
|
||
def test_twophase(): | ||
events = [] | ||
|
||
class TestScene(BaseScene, TwoPhaseMixin): | ||
flag = False | ||
|
||
def on_update(self, event, signal): | ||
nonlocal events | ||
self.stage_changes(flag=True) | ||
events.append(type(event)) | ||
|
||
def on_commit(self, event, signal): | ||
nonlocal events | ||
super().on_commit(event, signal) | ||
events.append(type(event)) | ||
|
||
with GameEngine(TestScene, basic_systems=[TwoPhaseSystem, Quitter]) as engine: | ||
engine.signal(Update(time_delta=0.1)) | ||
engine.run() | ||
|
||
assert engine.current_scene.flag | ||
assert events == [Update, Commit] |