27
|
1 #############################################################################
|
|
2 #
|
|
3 # Copyright (c) 2010 by Casey Duncan and contributors
|
|
4 # All Rights Reserved.
|
|
5 #
|
|
6 # This software is subject to the provisions of the MIT License
|
|
7 # A copy of the license should accompany this distribution.
|
|
8 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
9 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
10 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
11 #
|
|
12 #############################################################################
|
|
13 """Worlds are environments described by a configuration of components, systems and
|
|
14 renderers. These parts describe the data, behavioral and presentation aspects
|
|
15 of the world respectively.
|
|
16
|
|
17 The world environment is the context within which entities exist. A typical
|
|
18 application consists of one or more worlds containing entities that evolve
|
|
19 over time and react to internal and external interaction.
|
|
20
|
|
21 See :ref:`an example of world configuration in the tutorial <tut-world-example>`.
|
|
22 """
|
|
23
|
|
24 __version__ = '$Id$'
|
|
25
|
|
26 import itertools
|
|
27 import pyglet
|
|
28 from pyglet import gl
|
|
29 from grease.world import *
|
|
30 from grease.impl import Mode
|
|
31
|
|
32 class World(Mode, BaseWorld):
|
|
33 """A coordinated collection of components, systems and entities
|
|
34
|
|
35 A world is also a mode that may be pushed onto a
|
|
36 :class:`grease.mode.Manager`
|
|
37
|
|
38 :param step_rate: The rate of :meth:`step()` calls per second.
|
|
39
|
|
40 :param master_clock: The :class:`pyglet.clock.Clock` interface used
|
|
41 as the master clock that ticks the world's clock. This
|
|
42 defaults to the main pyglet clock.
|
|
43 """
|
|
44
|
|
45 clock = None
|
|
46 """:class:`pyglet.clock` interface for use by constituents
|
|
47 of the world for scheduling
|
|
48 """
|
|
49
|
|
50 time = None
|
|
51 """Current clock time of the world, starts at 0 when the world
|
|
52 is instantiated
|
|
53 """
|
|
54
|
|
55 running = True
|
|
56 """Flag to indicate that the world clock is running, advancing time
|
|
57 and stepping the world. Set running to False to pause the world.
|
|
58 """
|
|
59
|
|
60 def __init__(self, step_rate=60, master_clock=pyglet.clock,
|
|
61 clock_factory=pyglet.clock.Clock):
|
|
62 Mode.__init__(self, step_rate, master_clock, clock_factory)
|
|
63 BaseWorld.__init__(self)
|
|
64
|
|
65 def activate(self, manager):
|
|
66 """Activate the world/mode for the given manager, if the world is already active,
|
|
67 do nothing. This method is typically not used directly, it is called
|
|
68 automatically by the mode manager when the world becomes active.
|
|
69
|
|
70 The systems of the world are pushed onto `manager.event_dispatcher`
|
|
71 so they can receive system events.
|
|
72
|
|
73 :param manager: :class:`mode.BaseManager` instance
|
|
74 """
|
|
75 if not self.active:
|
|
76 for system in self.systems:
|
|
77 manager.event_dispatcher.push_handlers(system)
|
|
78 super(World, self).activate(manager)
|
|
79
|
|
80 def deactivate(self, manager):
|
|
81 """Deactivate the world/mode, if the world is not active, do nothing.
|
|
82 This method is typically not used directly, it is called
|
|
83 automatically by the mode manager when the world becomes active.
|
|
84
|
|
85 Removes the system handlers from the `manager.event_dispatcher`
|
|
86
|
|
87 :param manager: :class:`mode.BaseManager` instance
|
|
88 """
|
|
89 for system in self.systems:
|
|
90 manager.event_dispatcher.remove_handlers(system)
|
|
91 super(World, self).deactivate(manager)
|
|
92
|
|
93 def tick(self, dt):
|
|
94 """Tick the mode's clock, but only if the world is currently running
|
|
95
|
|
96 :param dt: The time delta since the last tick
|
|
97 :type dt: float
|
|
98 """
|
|
99 if self.running:
|
|
100 super(World, self).tick(dt)
|
|
101
|
|
102 def step(self, dt):
|
|
103 """Execute a time step for the world. Updates the world `time`
|
|
104 and invokes the world's systems.
|
|
105
|
|
106 Note that the specified time delta will be pinned to 10x the
|
|
107 configured step rate. For example if the step rate is 60,
|
|
108 then dt will be pinned at a maximum of 0.1666. This avoids
|
|
109 pathological behavior when the time between steps goes
|
|
110 much longer than expected.
|
|
111
|
|
112 :param dt: The time delta since the last time step
|
|
113 :type dt: float
|
|
114 """
|
|
115 dt = min(dt, 10.0 / self.step_rate)
|
|
116 for component in self.components:
|
|
117 if hasattr(component, "step"):
|
|
118 component.step(dt)
|
|
119 for system in self.systems:
|
|
120 if hasattr(system, "step"):
|
|
121 system.step(dt)
|
|
122
|
|
123 def on_draw(self, gl=pyglet.gl):
|
|
124 """Clear the current OpenGL context, reset the model/view matrix and
|
|
125 invoke the `draw()` methods of the renderers in order
|
|
126 """
|
|
127 gl.glClear(gl.GL_COLOR_BUFFER_BIT | gl.GL_DEPTH_BUFFER_BIT)
|
|
128 gl.glLoadIdentity()
|
|
129 BaseWorld.draw_renderers(self) |