7 from kivy.app import App
8 from kivy.core.window import Window
9 from kivy.uix.widget import Widget
10 from kivy.logger import Logger, LoggerHistory
11 from kivy.uix.relativelayout import RelativeLayout
12 from kivy.uix.scrollview import ScrollView
13 from kivy.graphics import Color, Rectangle
14 from kivy.utils import platform
16 from erdslangetjie.level import LevelList
17 from erdslangetjie.player import ThePlayer, Nemesis
18 from erdslangetjie.constants import TILE_SIZE, QUIET
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
227 title = "Peter's thread snake"
230 self.levels = LevelList()
231 super(GameApp, self).__init__()
234 root = ScrollView(size_hint=(None, None))
238 from kivy.base import EventLoop
239 window = EventLoop.window
240 if platform() == 'android':
241 window.fullscreen = True
242 self.root.size = window.size
243 game = GameWindow(self.levels, self.root)
245 self.root.add_widget(game)
246 # Ensure the player is visible
247 self.root.scroll_x = 0
248 self.root.scroll_y = 0
254 """ Erdslangetjie, a maze game of eluding nemesis
257 for hdlr in Logger.handlers[:]:
258 if not isinstance(hdlr, LoggerHistory):
259 Logger.removeHandler(hdlr)