7 from kivy.app import App
8 from kivy.core.window import Window
9 from kivy.uix.widget import Widget
10 from kivy.uix.relativelayout import RelativeLayout
11 from kivy.uix.scrollview import ScrollView
12 from kivy.graphics import Color, Rectangle
13 from kivy.utils import platform
15 from erdslangetjie.level import LevelList
16 from erdslangetjie.player import ThePlayer, Nemesis
21 class GameWindow(RelativeLayout):
23 def __init__(self, level_list, view):
24 self.level_list = level_list
25 self.level_obj = self.level_list.get_current_level()
26 self.level_obj.load_tiles()
30 cols, rows = self.level_obj.get_size()
32 super(GameWindow, self).__init__(
33 size=(cols * TILE_SIZE, rows * TILE_SIZE),
34 size_hint=(None, None))
36 self.x_scroll_margin = float(TILE_SIZE) / self.view.size[0]
37 self.y_scroll_margin = float(TILE_SIZE) / self.view.size[1]
39 self.mouse_move = False
41 self.player = ThePlayer()
42 self.nemesis = Nemesis()
43 if not self.level_obj.enter_pos:
44 raise RuntimeError('No entry point')
45 self.player_tile = None
46 self.nemesis_tile = None
48 self.player.pos = self.level_obj.enter_pos
49 if platform() != 'android':
51 self.keyboard = Window.request_keyboard(self._closed, self)
52 self.keyboard.bind(on_key_down=self._on_key_down)
57 tiles = self.level_obj.get_tiles()
59 for tile_line in tiles:
61 for tile in tile_line:
62 node = Widget(size=(TILE_SIZE, TILE_SIZE),
64 size_hint=(None, None))
68 Rectangle(pos=node.pos, size=node.size,
70 self.tiles[(bx, by)] = node
74 def draw_player(self):
76 self.remove_widget(self.player_tile)
77 sprite_pos = (self.player.pos[0] * TILE_SIZE,
78 self.player.pos[1] * TILE_SIZE)
79 self.player_tile = Widget(size=(TILE_SIZE, TILE_SIZE),
81 with self.player_tile.canvas:
83 Rectangle(pos=sprite_pos, size=self.player_tile.size,
84 texture=self.player.get_texture())
85 self.add_widget(self.player_tile)
86 for offset in [(TILE_SIZE - 1, TILE_SIZE - 1),
87 (-TILE_SIZE + 1, TILE_SIZE - 1),
88 (TILE_SIZE - 1, -TILE_SIZE + 1),
89 (-TILE_SIZE + 1, -TILE_SIZE + 1),
90 (0, 2 * TILE_SIZE - 2),
91 (-2 * TILE_SIZE + 2, 0),
92 (2 * TILE_SIZE - 2, 0),
93 (0, -2 * TILE_SIZE + 2),
95 # Aim is to ensure a 'neighbourhood' around the player
96 # is visible if possible
97 check_point = (sprite_pos[0] + offset[0] + TILE_SIZE / 2,
98 sprite_pos[1] + offset[1] + TILE_SIZE / 2)
99 true_point = self.to_parent(*check_point)
100 if check_point[0] < 0:
102 if check_point[1] < 0:
104 if check_point[0] >= self.size[0]:
106 if check_point[1] >= self.size[1]:
108 while not self.included(true_point, 0):
110 if true_point[0] >= self.view.size[0]:
111 self.view.scroll_x += self.x_scroll_margin
112 true_point = self.to_parent(*check_point)
113 #print '-x', self.view.scroll_x, self.view.scroll_y
114 elif true_point[0] < 0:
115 self.view.scroll_x -= self.x_scroll_margin
116 true_point = self.to_parent(*check_point)
117 #print '+x', self.view.scroll_x, self.view.scroll_y
118 elif true_point[1] >= self.view.size[1]:
119 self.view.scroll_y += self.y_scroll_margin
120 true_point = self.to_parent(*check_point)
121 #print '+y', self.view.scroll_x, self.view.scroll_y
122 elif true_point[1] < 0:
123 self.view.scroll_y -= self.y_scroll_margin
124 true_point = self.to_parent(*check_point)
125 #print '-y', self.view.scroll_x, self.view.scroll_y
126 #print true_point, self.view.size
128 def included(self, point, margin):
129 if point[0] < margin:
131 if point[0] >= self.view.size[0] - margin:
133 if point[1] < margin:
135 if point[1] >= self.view.size[1] - margin:
139 def draw_nemesis(self):
140 if not self.nemesis.on_board():
142 if self.nemesis_tile:
143 self.remove_widget(self.nemesis_tile)
144 sprite_pos = (self.nemesis.pos[0] * TILE_SIZE,
145 self.nemesis.pos[1] * TILE_SIZE)
146 self.nemesis_tile = Widget(size=(TILE_SIZE, TILE_SIZE),
148 with self.nemesis_tile.canvas:
150 Rectangle(pos=sprite_pos, size=self.nemesis_tile.size,
151 texture=self.nemesis.get_texture())
152 self.add_widget(self.nemesis_tile)
155 self.keyboard.unbind(on_key_down=self._on_key_down)
157 def _on_key_down(self, keyboard, keycode, text, modifiers):
158 # FIXME - likely portablity issues
160 if keycode[0] == pygame.K_UP:
162 elif keycode[0] == pygame.K_DOWN:
164 elif keycode[0] == pygame.K_LEFT:
166 elif keycode[0] == pygame.K_RIGHT:
169 self.do_move(direction)
171 def do_move(self, direction):
172 self.nemesis.move(self.level_obj)
174 self.player.move(direction, self.level_obj)
178 def check_state(self):
179 if self.level_obj.at_exit(self.player.pos):
181 self.level_obj = self.level_list.advance_to_next_level()
182 self.remove_widget(self.nemesis_tile)
183 self.nemesis.reset_pos()
185 self.level_obj.load_tiles()
186 self.player.pos = self.level_obj.enter_pos
187 self.remove_widget(self.player_tile)
188 self.view.scroll_x = 0
189 self.view.scroll_y = 0
196 elif self.nemesis.pos == self.player.pos:
201 def _calc_mouse_pos(self, pos):
202 pos = self.to_local(*pos)
203 return (int(pos[0] / TILE_SIZE), int(pos[1] / TILE_SIZE))
205 def on_touch_down(self, touch):
206 pos = self._calc_mouse_pos(touch.pos)
207 if pos == self.player.pos:
208 self.mouse_move = True
209 self.mouse_start = pos
211 def on_touch_up(self, touch):
212 self.mouse_move = False
214 def on_touch_move(self, touch):
216 pos = self._calc_mouse_pos(touch.pos)
217 if (pos[0] - self.mouse_start[0] != 0) or (
218 pos[1] - self.mouse_start[1] != 0):
219 direction = (pos[0] - self.mouse_start[0],
220 pos[1] - self.mouse_start[1])
221 self.do_move(direction)
222 self.mouse_start = pos
228 self.levels = LevelList()
229 super(GameApp, self).__init__()
232 root = ScrollView(size=(960, 640), size_hint=(None, None))
233 game = GameWindow(self.levels, root)
235 root.add_widget(game)
236 # Ensure the player is visible
245 """ Erdslangetjie, a maze game of eluding nemesis