Example changed
[galtack.git] / galtack_loadable.py
blobe791381bbe6cd602d07154bd8701d2d64eb18f44
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3 """
4 GalTacK runtime-loadable module.
5 """
6 # Copyright (C) 2007 Michael Carter
7 # Copyright (C) 2007 Felix Rabe <public@felixrabe.textdriven.com>
8 # Copyright (C) 2007 Phil Hassey (originator of ld488 code)
10 # WARNING: This code contains bits from the Ludum Dare version of Galcon,
11 # which is licensed under the GNU GPL. Watch out for "ld488" markers.
12 # This file is under the GNU GPL license for now.
14 # This matter has not yet been discussed with Phil Hassey. I, Felix Rabe,
15 # do not want any legal grey area in the code, so the whole project might
16 # change from MIT license to GPL license, or Phil gives his blessing to
17 # include those bits in MIT-licensed code.
19 #### IGNORE THIS PART:
21 # Permission is hereby granted, free of charge, to any person obtaining a
22 # copy of this software and associated documentation files (the
23 # "Software"), to deal in the Software without restriction, including
24 # without limitation the rights to use, copy, modify, merge, publish,
25 # distribute, sublicense, and/or sell copies of the Software, and to permit
26 # persons to whom the Software is furnished to do so, subject to the
27 # following conditions:
29 # The above copyright notice and this permission notice shall be included
30 # in all copies or substantial portions of the Software.
32 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
33 # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
34 # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
35 # IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
36 # CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
37 # OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
38 # THE USE OR OTHER DEALINGS IN THE SOFTWARE.
40 #### ... UP TILL HERE
42 # Recommended line length or text width: 75 characters.
44 from galtack_client import *
47 class GaltackUniverseView(DrawingArea):
48 """
49 GalTacK universe canvas.
50 """
52 def __init__(self):
53 super(GaltackUniverseView, self).__init__()
54 self.reset()
55 self.connect("expose-event", self.__cb_expose_event)
56 self.set_size_request(640, 480)
58 def reset(self):
59 self.planet_info_list = []
61 def __cb_expose_event(self, widget, event):
62 x, y, w, h = self.allocation
63 cr = self.window.cairo_create()
65 # background
66 cr.rectangle(0, 0, w, h)
67 cr.set_source_rgba(0.1, 0.0, 0.2, 1)
68 cr.fill()
70 e = cr.font_extents()
71 fascent, fdescent, fheight, fxadvance, fyadvance = e
73 # planets
74 for planet_info in self.planet_info_list:
75 cr.set_source_rgba(1, 1, 1, 1)
76 px, py = planet_info.x, planet_info.y
77 cr.arc(px, py, planet_info.radius, 0, PI2)
78 cr.fill()
80 txt = "%u" % planet_info.num
81 e = cr.text_extents(txt)
82 xbearing, ybearing, width, height, xadvance, yadvance = e
83 cr.move_to(px + 0.5 - xbearing - width / 2,
84 py + 0.5 - fdescent + fheight / 2)
85 cr.set_source_rgba(1, 0, 0, 1)
86 cr.show_text(txt)
88 def redraw(self):
89 if self.window is not None:
90 self.window.invalidate_rect(self.allocation, False)
91 return False
94 class GaltackUniverseWindow(WindowF12RawConsoleMixin):
95 """
96 A Window displaying a view of the GalTacK universe.
97 """
99 def __init__(self):
100 super(GaltackUniverseWindow, self).__init__()
101 self.set_title("Universe Window - GalTacK")
102 self.universe_view = self(GaltackUniverseView())
105 class LoadableController(object):
107 Provide some shortcuts for interactive use.
110 def __init__(self, galtack_client, *a, **kw):
111 self.gc = galtack_client
112 self.uw = GaltackUniverseWindow()
113 self.uv = self.uw.universe_view
115 def __call__(self, *a):
116 self.gc.send_commands(a)
118 @staticmethod
119 def __stabilize_planet_pos(planet_pos_list):
120 FPS = 32 # ld488: cnst.py:11
121 BORDER = 40 # ld488: level.py:27
122 PADDING = 8 # ld488: level.py:28
123 # ld488: level.py:89
124 for n in xrange(0,FPS):
125 top = BORDER
126 left = PADDING
127 right = SW-left*2
128 bottom = SH-top*2
129 for i, (p, x, y) in enumerate(planet_pos_list):
130 rad = p.radius
131 x = min(max(x, left + rad), right - rad)
132 y = min(max(y, top + rad), bottom - rad)
133 planet_pos_list[i] = (p, x, y)
134 self.__planet_flock_loop(planet_pos_list)
136 @staticmethod
137 def __planet_flock_loop(planet_pos_list): # ld488: flock.pyp:55
138 import math
139 ## First 'for' loop unnecessary, as "p->loop = 0" in:
140 ## ld488: flock.pyp:128
141 for n, (ap, ax, ay) in enumerate(planet_pos_list):
142 for m, (bp, bx, by) in enumerate(planet_pos_list[n+1:]):
143 dx = bx - ax
144 dy = by - ay
145 r = ap.radius + bp.radius
146 if abs(dx) > r or abs(dy) > r:
147 continue
148 dist = math.sqrt(dx*dx + dy*dy)
149 if dist < r:
150 ## no targets (but what about the part with index 0?)
151 if dist == 0:
152 dist = 1
153 dx = 1
154 ## w = weight and a->w == b->w == 100000 for
155 ## planets: ld488: flock.pyp:130.
156 ## Here, we cancel down to a->w == b->w == 1
157 w = 2.0
158 mx = (ax + bx) / w
159 my = (ay + by) / w
160 ax = mx - ((r * dx) / (dist * w))
161 ay = my - ((r * dy) / (dist * w))
162 bx = mx + ((r * dx) / (dist * w))
163 by = my + ((r * dy) / (dist * w))
165 def update(self):
166 if self.gc.u64data is None:
167 planets = []
168 else:
169 planets = self.gc.u64data.planets
170 planet_pos_list = []
171 for p in planets:
172 planet_pos_list.append((p, p.x, p.y))
173 self.__stabilize_planet_pos(planet_pos_list)
174 self.uv.planet_info_list = planets
175 self.uv.redraw()
178 def run_loadable(*a, **kw):
179 return LoadableController(*a, **kw)