def load_room(self, num_of_room): # загрузка комнаты на экран self.base = [] level = self.rooms[num_of_room].structure() empty = Image.open('Sprites/ground/idle/00.png') wall = Image.open('Sprites/wall/idle/00.png') background = Image.new('RGB', (len(level[0]) * TILE, len(level) * TILE), (255, 255, 255)) # собираем из маленьких изображений пустых клетов и стен # одно большое изображение поля чтобы потом отображать только его for i in range(len(level)): for k in range(len(level[i])): if level[i][k] == 'W': self.base.append(Wall((k, i))) background.paste(wall, (k * TILE, i * TILE)) else: self.base.append(Empty((k, i))) background.paste(empty, (k * TILE, i * TILE)) self.background = pygame.image.fromstring(background.tobytes(), background.size, background.mode) self.top_panel = Panel(self.player, 0) # создаем верхнюю self.bottom_panel = Panel(None, 550) # и нижнюю панели self.buttons = [ # создаем кнопки Button('game/panel/exit', (550, 10), 'menu'), Button('game/panel/inventory', (450, 10), 'inventory'), Button('game/panel/save', (500, 10), 'save'), ]
def init_panel(self): self.p = Panel((AppSettings.anim_size[2], AppSettings.anim_size[3])) self.p.draw = self.draw self.p.setup_ui = self.setup_ui self.p.keyPressEvent = self.keyPressEvent self.p.init() return self.p
def init_panel(self): self.p = Panel(AppSettings.scene_size) self.p.draw = self.draw self.p.setup_ui = self.setup_ui self.p.init() self.p.mousePressEvent = self.mousePressEvent self.p.keyPressEvent = self.keyPressEvent return self.p
def init_panel(self): self.p = Panel(AppSettings.timeline_size) self.p.draw = self.draw self.p.setup_ui = self.setup_ui self.p.init() # turns off default IO self.p.mouseReleaseEvent = self.empty self.p.mouseMoveEvent = self.empty self.p.wheelEvent = self.empty self.p.keyPressEvent = self.keyPressEvent return self.p
class Animation(AppElementSpawnable): # ------------------------------------------------------------------------ # # Functions that will update all instances (useful for update ticks) @staticmethod def evaluate_frame(frame): for inst in Animation._instances: inst.p.update() @staticmethod def mocap_reset(): for inst in Animation._instances: inst.update_motion_menu() def update_motion_menu(self): m = [(name, self.set_motion_curve_fn(name), False, False) for name in MocapHandle().get_names()] self.motion_menu.setMenu(Widgets.menu(self.p, m)) # # ------------------------------------------------------------------------ # # ------------------------------------------------------------------------ # # -- def __init__(self, ref_toon, ref_name): # Motion self.ref_toon = ref_toon self.ref_name = ref_name self.mc_handle = "" # Algorithms self.params = Graph.params self.preprocess_curve = [] self.keyframes = [] self.splines = [] # Metrics self.metric_map = MetricMap() # Display, and other self.image_save_index = 0 self.display = Graph.draw_type[Graph.draw_type_default] def setup_ui(self): x = 10 inc = 100 self.joint_display_name = Widgets.label(self.p, self.ref_name, (x, 4)) self.mc_handle_label = Widgets.label(self.p, self.mc_handle, (x, 24)) x += 50 # -------------------------------------------------------------------- # # Menus m = [("None", self.empty, False, False)] self.motion_menu = Widgets.button_menu(self.p, "Motion", m, (x, 0)) self.update_motion_menu() x += inc # Application of curve m = [ ("Clear", self.clear_motion, False, False), ("tx", self.apply_curve_fn("tx"), False, False), ("ty", self.apply_curve_fn("ty"), False, False), ("rz", self.apply_curve_fn("rz"), False, False), ] Widgets.button_menu(self.p, "Apply", m, (x, 0)) x += inc # Grepping curvers from existing toon m = [ ("tx", self.grep_curve_fn("tx"), False, False), ("ty", self.grep_curve_fn("ty"), False, False), ("rz", self.grep_curve_fn("rz"), False, False), ] Widgets.button_menu(self.p, "Grep", m, (x, 0)) x += inc # Display menu m = [(key, self.toggle_display_fn(key), True, self.display[key]) for key in self.display.keys()] Widgets.button_menu(self.p, "Display", m, (x, 0)) x += inc # Algorithms menu m = [ ("Subdivide", self.subdivide, False, False), ("Douglas Peucker", self.douglas_peucker, False, False), ("Salient Points 1D", self.salient_points_1d, False, False), ("Salient Points FT", self.salient_points_ft, False, False), ("Salient Points it", self.salient_points_iter, False, False), ("Polyline", self.polyline, False, False), ("Flat tangents", self.flat_tangents, False, False), ("One-pass", self.cubic, False, False), ("Reset", self.reset_simplification, False, False), ("Save Graph", self.save_graph, False, False), ] Widgets.button_menu(self.p, "Simplify", m, (x, 0)) x += inc # # -------------------------------------------------------------------- # # -------------------------------------------------------------------- # # Sliders x = 100 y = AppSettings.anim_size[3] - 150 inc = 20 self.sliders = {} for key in self.params.keys(): if key != "": slider = Widgets.slider( self.p, key, self.update_slider_fn(key), mm=(1, 20), xy=(x, y), v=self.params[key] ) self.sliders[key] = slider y += inc # # -------------------------------------------------------------------- # # -------------------------------------------------------------------- # # Metric map x = AppSettings.anim_size[2] - 100 y = AppSettings.anim_size[3] * 0.5 m = self.metric_map.m self.metric_map_handle = {} for key in m.keys(): inner_m = m[key] l = Widgets.label(self.p, key, xy=(x - 50, y)) y += 20 self.metric_map_handle[key] = {} for inner_key in inner_m: l = Widgets.label(self.p, inner_key, xy=(x, y)) y += 20 self.metric_map_handle[key][inner_key] = l # # -------------------------------------------------------------------- # # # ------------------------------------------------------------------------ # # ------------------------------------------------------------------------ # # Key map def keyPressEvent(self, e): # Switch focus to current selection if self.p.query_key("e", e.key()): index, joint = Scene().get_selected() self.ref_toon = index self.ref_name = joint.name self.joint_display_name.setText(self.ref_name) # Fast save graph if self.p.query_key("s", e.key()): self.image_save_index += 1 index = self.image_save_index self.save_graph("%s/%s" % (AppSettings.default_graph_save_dir, "fast_save_" + str(index)) + ".svg") # Reset fast index if self.p.query_key("q", e.key()): self.image_save_index = 0 # Auto displays display_presets = ["1", "2", "3", "4", "5", "6"] for key in display_presets: if self.p.query_key(key, e.key()): self.toggle_display_type(key) # Algorithm hotkeys if self.p.query_key("y", e.key()): self.subdivide() if self.p.query_key("u", e.key()): self.douglas_peucker() if self.p.query_key("i", e.key()): self.salient_points_1d() if self.p.query_key("o", e.key()): self.salient_points_ft() if self.p.query_key("p", e.key()): self.salient_points_iter() if self.p.query_key("j", e.key()): self.cubic() if self.p.query_key("k", e.key()): self.flat_tangents() if self.p.query_key("l", e.key()): self.polyline() # Camera controls if self.p.query_key("x", e.key()): self.p.toggle_camera_lock() if self.p.query_key("c", e.key()): self.p.store_camera() if self.p.query_key("v", e.key()): self.p.recover_camera() # Quit hotkey if self.p.query_key("esc", e.key()): self.p.window_obj.close() self.p.update() # # ------------------------------------------------------------------------ # # ------------------------------------------------------------------------ # # Panel stuff def init_panel(self): self.p = Panel((AppSettings.anim_size[2], AppSettings.anim_size[3])) self.p.draw = self.draw self.p.setup_ui = self.setup_ui self.p.keyPressEvent = self.keyPressEvent self.p.init() return self.p def draw(self, d): sd = -AppSettings.anim_size[2] * 0.4 ed = +AppSettings.anim_size[2] * 0.4 sh = -AppSettings.anim_size[3] * 0.4 eh = +AppSettings.anim_size[3] * 0.4 s = Timeline().start_frame f = Timeline().end_frame def lerp_over_drawing(p_i): x, y = p_i t = (x - s) / float(f - s) return sd + t * (ed - sd) def y_scaling(p_i): x, y = p_i return y * self.params["y"] def curve_as_points(color, curve, offset=0.0, sizable=False): s = 1.0 if sizable: s = self.params["mocap"] d.fill(color, a=125) d.stroke((0, 0, 0), a=0) for i in range(len(curve)): x = lerp_over_drawing(curve[i]) y = y_scaling(curve[i]) + offset d.circle((x, y), s) def curve_as_polyline(color, curve): d.fill((0, 0, 0), a=0) d.stroke(color, a=125) for i in range(len(curve)): x1 = lerp_over_drawing(curve[i - 1]) x2 = lerp_over_drawing(curve[i]) y1 = y_scaling(curve[i - 2]) y2 = y_scaling(curve[i - 1]) d.line((x1, y1), (x2, y2)) def curve_as_steps(color, curve): d.fill((0, 0, 0), a=0) d.stroke(color, a=125) for i in range(len(curve)): x1 = lerp_over_drawing(curve[i - 1]) x2 = lerp_over_drawing(curve[i]) y1 = y_scaling(curve[i - 2]) y2 = y_scaling(curve[i - 1]) d.line((x1, y1), (x2, y1)) d.line((x2, y1), (x2, y2)) def curve_as_tangents(color, curve, tvs): d.fill((0, 0, 0), a=0) d.stroke(color, a=125) for i in range(len(curve)): tv = curve[i] + tvs[i] x1 = lerp_over_drawing(curve[i]) y1 = y_scaling(curve[i]) x2 = lerp_over_drawing(tv) y2 = y_scaling(tv) dv = np.array([x2 - x1, y2 - y1]) dv = dv / np.linalg.norm(dv) * self.params["vector_size"] x2 = x1 + dv[0] y2 = y1 + dv[1] d.line((x1, y1), (x2, y2)) def curve_as_normals(color, curve, tvs): d.fill((0, 0, 0), a=0) d.stroke(color, a=125) for i in range(len(curve)): tv = curve[i] + tvs[i] x1 = lerp_over_drawing(curve[i]) y1 = y_scaling(curve[i]) x2 = lerp_over_drawing(tv) y2 = y_scaling(tv) dv = np.array([x2 - x1, y2 - y1]) dv = dv / np.linalg.norm(dv) * self.params["vector_size"] x2 = x1 - dv[1] y2 = y1 + dv[0] d.line((x1, y1), (x2, y2)) def keyframes_as_dots(color, curve, keyframes): d.fill((0, 0, 0), a=0) d.stroke(color, a=255) d.fill(color, a=255) d.stroke((0, 0, 0), a=0) for k in keyframes: x = lerp_over_drawing(curve[k]) y = y_scaling(curve[k]) d.circle((x, y), 3) def spline_as_curves(color, interps): d.fill(color, a=255) d.stroke((0, 0, 0), a=0) for interp in interps: x = lerp_over_drawing(interp) y = y_scaling(interp) d.circle((x, y), 2) def spline_as_cubic(color, controls): d.fill((0, 0, 0), a=0) d.stroke(color, a=255) controls_scaled = [[lerp_over_drawing(c), y_scaling(c)] for c in controls] d.bezier(controls_scaled) def spline_as_handles(color, controls): controls_scaled = [[lerp_over_drawing(c), y_scaling(c)] for c in controls] p0, p1, p2, p3 = controls_scaled d.fill(color, a=255) d.stroke(color, a=255) d.line(p0, p1) d.line(p2, p3) d.stroke((0, 0, 0), a=0) d.box(p1, (5, 5)) d.box(p2, (5, 5)) if self.display["axis"]: d.fill((0, 0, 0), a=0) d.stroke(Colors.null, a=125) x = AppSettings.anim_size[2] * 0.5 d.line((-x, 0), (+x, 0)) x = lerp_over_drawing(s) d.line((x, sh), (x, eh)) x = lerp_over_drawing(f) d.line((x, sh), (x, eh)) if self.display["time"]: d.fill((0, 0, 0), a=0) d.stroke(Colors.time_marker, a=125) x = lerp_over_drawing(Timeline().current_frame) d.line((x, sh), (x, eh)) # Motion curves if self.mc_handle != "": curve = MocapHandle().get_curve(self.mc_handle) if self.display["mocap_dots"]: curve_as_points(Colors.mocap, curve, sizable=True) if self.display["mocap_lines"]: curve_as_polyline(Colors.mocap, curve) if self.display["mocap_steps"]: curve_as_steps(Colors.mocap, curve) if self.display["preprocess"] and self.preprocess_curve != []: curve_as_points(Colors.preprocess, self.preprocess_curve) if self.display["tangents"] and self.preprocess_curve != []: tvs = TangentApprox.from_motion_curve(self.preprocess_curve) curve_as_tangents(Colors.tangents, self.preprocess_curve, tvs) if self.display["normals"] and self.preprocess_curve != []: tvs = TangentApprox.from_motion_curve(self.preprocess_curve) curve_as_normals(Colors.normals, self.preprocess_curve, tvs) if self.display["keyframes"]: keyframes_as_dots(Colors.keyframes, self.preprocess_curve, self.keyframes) if self.display["splines"]: for spline in self.splines: spline_as_cubic(Colors.splines, spline.list_controls()) if self.display["handles"]: for spline in self.splines: spline_as_handles(Colors.handles, spline.list_controls()) # # ------------------------------------------------------------------------ # # ------------------------------------------------------------------------ # # Menu callbacks def save_meta_data(self, filepath): curve = MocapHandle().get_curve(self.mc_handle) keyframes = self.keyframes spline_handles = [s.list_controls()[1:3] for s in self.splines] meta_data = { "motion": { "file": MocapHandle().last_loaded, "name": self.ref_name, "curve_key": self.mc_handle, "curve": curve.tolist(), }, "simplify": {"keyframes": keyframes, "splines": spline_handles}, "metric": self.metric_map.m, } f = open(filepath, "w") f.write(json.dumps(meta_data, sort_keys=True, indent=4, separators=(",", ": "))) f.close() def save_graph(self, filepath=""): if filepath == "": filepath = Dialogs.save_file(self.p, AppSettings.demuddle_dir)[0] data_fp = filepath + ".meta.json" self.p.paintImage(filepath) self.save_meta_data(data_fp) def set_motion_curve_fn(self, name): def fn(): self.mc_handle = name self.mc_handle_label.setText(self.mc_handle) return fn def clear_motion(self): # TODO implement this # Scene().command_delete_motion(self.ref_toon, self.ref_name) self.p.update() def apply_curve_fn(self, target): def fn(): Scene().command_add_motion(self.ref_toon, self.ref_name, target, self.mc_handle) self.p.update() return fn def grep_curve_fn(self, target): def fn(): mobj = Scene().command_get_motion(self.ref_toon, self.ref_name, target) if mobj != None: self.mc_handle = "%s, %s" % (mobj.ref_name, mobj.ref_dof) self.mc_handle_label.setText(self.mc_handle) self.p.update() return fn def update_slider_fn(self, key): def fn(v): self.params[key] = v return fn # # ------------------------------------------------------------------------ # # ------------------------------------------------------------------------ # # Simplification def subdivide(self): curve = MocapHandle().get_curve(self.mc_handle) preprocess = Subdivide() preprocess.update_curve(curve) preprocess.update(self.params) self.preprocess_iters = preprocess.get_iters() self.preprocess_curve = preprocess.get_result() Scene().set_status("Curve preproccesed (Subdivision)", "normal") self.p.update() def douglas_peucker(self): curve = self.preprocess_curve keyframer = DouglasPeucker() keyframer.update_curve(curve) keyframer.update(self.params) self.keyframes = keyframer.get_keyframes() Scene().set_status("Keyframe selected (Douglas Peucker)", "normal") self.p.update() def salient_points_1d(self): curve = self.preprocess_curve keyframer = SalientPoints1D() keyframer.update_curve(curve) keyframer.learn() self.keyframer = keyframer Scene().set_status("zerotable (Salient Points, 1D)", "normal") self.p.update() def salient_points_ft(self): curve = self.preprocess_curve keyframer = SalientPointsFlatTangents() keyframer.update_curve(curve) keyframer.learn() self.keyframer = keyframer Scene().set_status("zerotable (Salient Points, FT)", "normal") self.p.update() def salient_points_iter(self): self.keyframer.update(self.params) self.keyframes = self.keyframer.get_keyframes() Scene().set_status("Keyframe selected (Salient Points, iter)", "normal") self.p.update() def polyline(self): curve = self.preprocess_curve keyframes = self.keyframes segments = zip(keyframes[:-1], keyframes[1:]) self.splines = [] for (k1, k2) in segments: spline_obj = PolyLine() spline_obj.update_curve(curve[k1 : k2 + 1]) spline_obj.update(self.params) spline_obj.run() self.splines.append(spline_obj) self.update_metric_map() Scene().set_status("Interpolated (polyline)", "normal") self.p.update() def flat_tangents(self): curve = self.preprocess_curve keyframes = self.keyframes segments = zip(keyframes[:-1], keyframes[1:]) self.splines = [] for (k1, k2) in segments: spline_obj = FlatTangent() spline_obj.update_curve(curve[k1 : k2 + 1]) spline_obj.update(self.params) spline_obj.run() self.splines.append(spline_obj) self.update_metric_map() Scene().set_status("Interpolated (flat spline)", "normal") self.p.update() def cubic(self): curve = self.preprocess_curve keyframes = self.keyframes segments = zip(keyframes[:-1], keyframes[1:]) self.splines = [] for (k1, k2) in segments: spline_obj = OnePass() spline_obj.update_curve(curve[k1 : k2 + 1]) spline_obj.update(self.params) spline_obj.run() self.splines.append(spline_obj) self.update_metric_map() Scene().set_status("Interpolated (cubic spline)", "normal") self.p.update() def reset_simplification(self): self.mc_handle = "" self.preprocess_curve = [] self.keyframes = [] self.splines = [] Scene().set_status("keyframes deleted", "normal") self.p.update() # # ------------------------------------------------------------------------ # # ------------------------------------------------------------------------ # # Metrics def update_metric_map(self): # Make a curve from spline pieces approx = [] approx_length = 0 for spline in self.splines: approx += spline.interps_nearest()[:-1] approx_length += spline.get_length() approx += [self.splines[-1].interps_nearest()[-1]] # Measure errors a = [v for v in self.preprocess_curve] b = [v for v in approx] self.metric_map.m["distance"]["normOne"] = Distance.normOne(a, b) self.metric_map.m["distance"]["normTwo"] = Distance.normTwo(a, b) self.metric_map.m["distance"]["normInf"] = Distance.normInf(a, b) self.metric_map.m["distance"]["meanSqu"] = Distance.meanSqu(a, b) # Measure lengths self.metric_map.m["length"]["original"] = 0 # TODO implement data length self.metric_map.m["length"]["simplified"] = approx_length # Record numbers of critical points c_org = len(Critical.local_minima(a) + Critical.local_maxima(a)) c_simp = len(Critical.local_minima(b) + Critical.local_maxima(b)) self.metric_map.m["critical"]["original"] = c_org self.metric_map.m["critical"]["simplified"] = c_simp # Save data to map m = self.metric_map_handle for key in m.keys(): inner_m = m[key] for inner_key in inner_m: v = self.metric_map.m[key][inner_key] inner_m[inner_key].setText("%s, %2.2f" % (inner_key, v)) # # ------------------------------------------------------------------------ # # ------------------------------------------------------------------------ # # Display stuff def toggle_display_fn(self, item): def fn(*args): self.display[item] = self.display[item] == False self.p.update() return fn def toggle_display_type(self, index): self.display = Graph.draw_type[index] self.p.update()
class Timeline(AppElementSingle): def __init__(self): self.current_frame = 1 self.start_frame = 1 self.end_frame = 2 self.time_last = -1 self.frame_rate = AppSettings.standard_fps self.playing = False # ------------------------------------------------------------------------ # # App element default def setup_ui(self): x = 30 frame_range = (self.start_frame, self.end_frame) self.fps = Widgets.int_roller(self.p, self.frame_rate, self.update_frame_rate, AppSettings.fps_range, xy=(x, 2)) x += 52 Widgets.button(self.p, "<-", self.play_backward, (x, 0)) x += 90 Widgets.button(self.p, "||", self.play_stop, (x, 0)) x += 90 Widgets.button(self.p, "->", self.play_forward, (x, 0)) x += 100 self.frame_roller = Widgets.int_roller( self.p, self.current_frame, self.set_current_frame, frame_range, xy=(x, 2) ) x += 50 self.ticker = Widgets.ticker(self.p, self.tick) self.update_frame_rate() def keyPressEvent(self, e): if self.p.query_key("-", e.key()): self.tweak(-1) if self.p.query_key("=", e.key()): self.tweak(+1) def init_panel(self): self.p = Panel(AppSettings.timeline_size) self.p.draw = self.draw self.p.setup_ui = self.setup_ui self.p.init() # turns off default IO self.p.mouseReleaseEvent = self.empty self.p.mouseMoveEvent = self.empty self.p.wheelEvent = self.empty self.p.keyPressEvent = self.keyPressEvent return self.p def draw(self, d): sd = -AppSettings.timeline_size[0] * 0.4 ed = +AppSettings.timeline_size[0] * 0.4 hh = AppSettings.timeline_size[1] * 0.1 sf = self.start_frame ef = self.end_frame def lerp_drawing_range(frame): t = (frame - sf) / float(ef - sf) return sd + t * (ed - sd) # Timeline graph d.fill((0, 0, 0), a=0) d.stroke(Colors.null, a=125) d.line((sd - 10, 0), (ed + 10, 0)) for frame in range(sf, ef + 1): x = lerp_drawing_range(frame) d.line((x, -hh), (x, +hh)) # Current time marker d.fill(Colors.time_marker, a=200) d.stroke((0, 0, 0), a=0) x = lerp_drawing_range(self.current_frame) d.box((x, 0), (10, hh * 2)) # # ------------------------------------------------------------------------ # # ------------------------------------------------------------------------ # # Widget def tick(self, *args): self.current_frame += 1 * self.playing self.bound_current_frame() self.frame_roller.setValue(self.current_frame) Scene().evaluate_frame(self.current_frame) Animation.evaluate_frame(self.current_frame) self.p.update() # # ------------------------------------------------------------------------ # # ------------------------------------------------------------------------ # # Menu def play_forward(self): self.playing = 1 def play_stop(self): self.playing = 0 def play_backward(self): self.playing = -1 def update_frame_rate(self): self.frame_rate = self.fps.value() self.ticker.start(1000.0 / self.frame_rate) # # ------------------------------------------------------------------------ # # ------------------------------------------------------------------------ # # Playback interface def set_frame_range(self, s, f): self.start_frame = s self.end_frame = f self.n_frames = f - s + 1 self.frame_roller.setMinimum(s) self.frame_roller.setMaximum(f) def set_current_frame(self, frame): self.current_frame = frame self.bound_current_frame() Scene().evaluate_frame(self.current_frame) self.p.update() def bound_current_frame(self): if self.current_frame > self.end_frame: self.current_frame = self.start_frame if self.current_frame < self.start_frame: self.current_frame = self.end_frame def tweak(self, change): self.current_frame += change self.bound_current_frame() Scene().evaluate_frame(self.current_frame) self.p.update()
class Scene(AppElementSingle): # ------------------------------------------------------------------------ # # -- def __init__(self): self.toons = [] self.toon_filepaths = [] self.display = {"axis": True} def setup_ui(self): w = 0 menu = [ ("Load Scene", self.load_scene, False, False), ("Save Scene", self.save_scene, False, False), ("Load Mocap", self.load_mocap, False, False), ] Widgets.button_menu(self.p, "File", menu, (w, 0)) w += 100 menu = [ ("Load", self.load_toon, False, False), ("Examine", self.examine_toon, False, False), ("Offset", self.rotate_toon, False, False), ("Scale", self.scale_toon, False, False), ] Widgets.button_menu(self.p, "Character", menu, (w, 0)) w += 120 menu = [("Axis", self.toggle_display_fn("axis"), True, True)] Widgets.button_menu(self.p, "Display", menu, (w, 0)) w += 120 self.status_bar = Widgets.label( self.p, " Status", (10, AppSettings.scene_size[1] - 20), w=AppSettings.scene_size[0] - 20 ) self.set_status("loaded %s" % self.toon_filepaths, "normal") def mousePressEvent(self, e): if self.p.query_button(2, e.buttons()): self.command_select(e.x(), e.y()) def keyPressEvent(self, e): # Character hotkeys if self.p.query_key("left", e.key()): self.command_modify(Joint.Move_L) if self.p.query_key("right", e.key()): self.command_modify(Joint.Move_R) if self.p.query_key("down", e.key()): self.command_modify(Joint.Move_D) if self.p.query_key("up", e.key()): self.command_modify(Joint.Move_U) if self.p.query_key("a", e.key()): self.command_modify(Joint.Rot_L) if self.p.query_key("d", e.key()): self.command_modify(Joint.Rot_R) # Interface if self.p.query_key("e", e.key()): self.examine_toon() if self.p.query_key("esc", e.key()): Executable.quit() if self.p.query_key("-", e.key()): Timeline().tweak(-1) if self.p.query_key("=", e.key()): Timeline().tweak(+1) # Camera if self.p.query_key("x", e.key()): self.p.toggle_camera_lock() if self.p.query_key("c", e.key()): self.p.store_camera() if self.p.query_key("v", e.key()): self.p.recover_camera() def init_panel(self): self.p = Panel(AppSettings.scene_size) self.p.draw = self.draw self.p.setup_ui = self.setup_ui self.p.init() self.p.mousePressEvent = self.mousePressEvent self.p.keyPressEvent = self.keyPressEvent return self.p def draw(self, d): if self.display["axis"]: d.axis() for t in self.toons: t.draw(d) # # ------------------------------------------------------------------------ # # ------------------------------------------------------------------------ # # Toon API def add_toon_from_file(self, filepath): f = open(filepath, "r") toon = json.loads(f.read()) f.close() t = Toon() for joint in toon["joints"]: joint_obj = t.joint_add(joint["name"], joint["parent"], joint["type"], joint["length"], joint["flip"]) joint_obj.rotation_offset = joint["offset"] joint_obj.pos_scaling = joint["pos_s"] # Update cache and scene self.toon_filepaths.append(filepath) self.toons.append(t) self.p.update() def load_toon(self): filepath = Dialogs.open_file(self.p, AppSettings.toon_dir)[0] if os.path.isfile(filepath): self.add_toon_from_file(filepath) else: Scene().set_status("File selected is not valid", "error") def examine_toon(self): toon_index, selected = self.get_selected() if selected != None: Executable.spawn_window("Motion", AppSettings.anim_size, Animation(toon_index, selected.name).init_panel()) def rotate_toon(self): for t in self.toons: if t.selection_active(): v = Dialogs.int(self.p, "Rotate", "degrees anticlockwise") if v != None: t.modify_rotation_offset(v) def scale_toon(self): for t in self.toons: if t.joint_selected() != None: v = Dialogs.float(self.p, "Scale", "scale character") if v != None: t.modify_position_scaling(v) def get_selected(self): for i in range(len(self.toons)): t = self.toons[i] if t.joint_selected() != None: return i, t.joint_selected() return -1, None def curve_data_on_selected(self): for t in self.toons: if t.selection_active(): return t.sele.get_motion_info() return None def command_select(self, x, y): already_found = False for t in self.toons: if t.selection_cast(x, y, already_found): already_found = True self.p.update() def command_modify(self, t_type): for t in self.toons: t.modify_interactive(t_type) self.p.update() def command_add_motion(self, character, name, target, curve_key): mobj = MocapHandle().generate_motion_obj(curve_key) joint_obj = self.toons[character].joint_by_name(name) joint_obj.add_retarget(target, mobj) self.p.update() def command_get_motion(self, character, name, target): joint_obj = self.toons[character].joint_by_name(name) if target in joint_obj.retargets: return joint_obj.retargets[target].motion else: Scene().set_status("Target not found in joint", "warning") return None def command_delete_motion(self, character, name): joint_obj = self.toons[character].joint_by_name(name) joint_obj.clear_retargets() self.p.update() def evaluate_frame(self, frame): for t in self.toons: t.evaluate_frame(frame) self.p.update() # # ------------------------------------------------------------------------ # # ------------------------------------------------------------------------ # # Loading and saving def load_mocap(self): MocapHandle().load_mocap() def save_scene(self): # cache character info and motions character_motion_maps = [] character_infos = [] for t in self.toons: motion_maps = {} character_info = {} for joint in t.joint_list(): motion_maps[joint.name] = joint.generate_map_from_retargets() character_info[joint.name] = joint.get_info() character_motion_maps.append(motion_maps) character_infos.append(character_info) # organize into scene file scene_file = { "mocap": MocapHandle().last_loaded, "character_filepaths": self.toon_filepaths, "character_info": character_infos, "character_motion_maps": character_motion_maps, } # save filepath = Dialogs.save_file(self.p, AppSettings.save_dir)[0] f = open(filepath, "w") f.write(json.dumps(scene_file, sort_keys=True, indent=4, separators=(",", ": "))) f.close() def load_scene(self, filepath=""): if filepath == "": filepath = Dialogs.open_file(self.p, AppSettings.save_dir)[0] if not os.path.isfile(filepath): Scene().set_status("file selected is not valid.", "warning") return # open f = open(filepath, "r") scene_file = json.loads(f.read()) f.close() # Load mocap (if it was there) if scene_file["mocap"] != "": MocapHandle().load_mocap("%s/%s" % (AppSettings.demuddle_dir, scene_file["mocap"])) # Load characters. for fp in scene_file["character_filepaths"]: self.add_toon_from_file("%s/%s" % (AppSettings.demuddle_dir, fp)) # Apply info and motion onto characters cindex = 0 for cindex in range(len(scene_file["character_motion_maps"])): motion_maps = scene_file["character_motion_maps"][cindex] character_infos = scene_file["character_info"][cindex] for joint_name in motion_maps.keys(): character_info = character_infos[joint_name] motion_map = motion_maps[joint_name] joint_obj = self.toons[cindex].joint_by_name(joint_name) joint_obj.set_info(character_info) joint_obj.generate_retargets_from_map(motion_map) cindex += 1 self.p.update() # # ------------------------------------------------------------------------ # # ------------------------------------------------------------------------ # # Other def toggle_display_fn(self, item): def fn(*args): self.display[item] = self.display[item] == False self.p.update() return fn def set_status(self, message, message_type): self.status_bar.setText(" Status: %s" % message) style = "" if message_type == "normal": style = "QLabel { background-color : #1573BD; color : white; }" elif message_type == "warning": style = "QLabel { background-color : #F6AC41; color : white; }" elif message_type == "error": stlye = "QLabel { background-color : #DE3B3C; color : white; }" else: pass self.status_bar.setStyleSheet(style)
class Dungeon(Element): """класс подземелья""" def __init__(self): super().__init__() self.unused_keys = [] self.first = True self.rooms = {} self.enemies = [] self.objects = [] self.base = [] self.entities = [] self.buttons = [] self.user_name = '' self.con = sqlite3.connect(DATABASE) self.background, self.top_panel, self.bottom_panel = None, None, None self.player = Player((1, 1), 5, 5, 1, 1, 3, 3, 0, 255) self.current_room = 1 self.turn = 1 self.change_room(1) def new(self): self.unused_keys = [] self.rooms = {} self.enemies = [] self.objects = [] self.base = [] self.entities = [] self.buttons = [] self.user_name = '' self.first = True self.background, self.top_panel, self.bottom_panel = None, None, None self.player = Player((1, 1), 5, 5, 1, 1, 3, 3, 0, 255) self.current_room = 1 self.turn = 1 self.change_room(1) def change_room(self, num): # смена комнаты, в которой находится игрок self.enemies = [] self.objects = [] self.base = [] if num not in self.rooms.keys(): # если следующей комнаты не существует self.generate_level(num) else: self.enemies = self.rooms[num].enemies self.objects = self.rooms[num].objects if self.first: # если запустили первый раз self.player.position = (1, 1) self.first = False elif num > self.current_room: # смотрим, откуда пришел игрок self.player.position = self.rooms[num].enter[1], \ self.rooms[num].enter[0] else: self.player.position = self.rooms[num].exit_[1], \ self.rooms[num].exit_[0] self.current_room = num self.entities = [self.player, *self.enemies] self.load_room(self.current_room) def load_room(self, num_of_room): # загрузка комнаты на экран self.base = [] level = self.rooms[num_of_room].structure() empty = Image.open('Sprites/ground/idle/00.png') wall = Image.open('Sprites/wall/idle/00.png') background = Image.new('RGB', (len(level[0]) * TILE, len(level) * TILE), (255, 255, 255)) # собираем из маленьких изображений пустых клетов и стен # одно большое изображение поля чтобы потом отображать только его for i in range(len(level)): for k in range(len(level[i])): if level[i][k] == 'W': self.base.append(Wall((k, i))) background.paste(wall, (k * TILE, i * TILE)) else: self.base.append(Empty((k, i))) background.paste(empty, (k * TILE, i * TILE)) self.background = pygame.image.fromstring(background.tobytes(), background.size, background.mode) self.top_panel = Panel(self.player, 0) # создаем верхнюю self.bottom_panel = Panel(None, 550) # и нижнюю панели self.buttons = [ # создаем кнопки Button('game/panel/exit', (550, 10), 'menu'), Button('game/panel/inventory', (450, 10), 'inventory'), Button('game/panel/save', (500, 10), 'save'), ] def generate_enemies(self, room): patterns = [ ['blue', 2, 2, 1, 1, 2, 2], ['green', 3, 3, 1, 2, 2, 2], ['red', 3, 3, 2, 2, 2, 2], ['purple', 4, 4, 2, 3, 3, 3], ] enemy_number = [0, 0, 0, 0] if room == 1: a = random.randint(2, 4) enemy_number = [a, 4 - a, 0, 0] elif 2 <= room <= 5: a = random.randint(3, 4) enemy_number = [4 - a, a, 0, 0] elif 6 <= room <= 9: a = random.randint(2, 3) enemy_number = [1, a, 3 - a, 0] elif 10 <= room <= 14: a = random.randint(3, 5) enemy_number = [0, 5 - a, a, 0] elif 15 <= room <= 20: a = random.randint(3, 4) enemy_number = [0, 4 - a, a, 1] elif room > 20: a = random.randint(4, 5) enemy_number = [0, 0, 6 - a, a] return [ patterns[i] for i in range(len(patterns)) for _ in range(enemy_number[i]) ] def generate_level(self, num): # генерация уровня игры (карты) closed_cells = [self.player.position] enter = (0, 0) if num != 1: enter = self.rooms[num - 1].enter_from_exit() enemies_options = self.generate_enemies(num) for i in range(len(enemies_options)): # генерация врагов x, y = random.randint(2, 9), random.randint(2, 8) while (x, y) in closed_cells: x, y = random.randint(2, 9), random.randint(2, 8) self.enemies.append(Enemy((x, y), *enemies_options[i])) closed_cells.append((x, y)) for i in range(random.randint(6, 7)): # генерация коробок x, y = random.randint(2, 8), random.randint(2, 7) while (x, y) in closed_cells: x, y = random.randint(2, 8), random.randint(2, 7) self.objects.append(Box((x, y))) closed_cells.append((x, y)) a, b = (0, 2) for i in range(random.randint(a, b)): # генерация зельев для здоровья x, y = random.randint(1, 9), random.randint(2, 8) while (x, y) in closed_cells: x, y = random.randint(1, 9), random.randint(2, 8) self.objects.append(Chest((x, y), 'potion', 'green')) closed_cells.append((x, y)) exit_ = random.choice([(random.randint(2, 8), 11), (9, random.randint(2, 9))]) if num > 6: # генерация зельев для повышения силы или количества ходов if not random.randint(0, 2): x, y = random.randint(1, 9), random.randint(2, 8) while (x, y) in closed_cells: x, y = random.randint(1, 9), random.randint(2, 8) self.objects.append( Chest((x, y), 'potion', random.choice(['red', 'blue']))) closed_cells.append((x, y)) if not random.randint(0, 2) and len(self.unused_keys) < 6: # генерация двери, если неиспользованных ключей меньше 6 door_color = random.choice(['red', 'blue', 'green']) x, y = random.randint(1, 9), random.randint(1, 8) while (x, y) in closed_cells: x, y = random.randint(2, 9), random.randint(2, 8) self.objects.append(Chest((x, y), 'key', door_color)) self.unused_keys.append(door_color) if not random.randint(0, 2) and self.unused_keys: # добавится ли дверь в текущую комнату self.objects.append( Door((exit_[1], exit_[0]), self.unused_keys.pop( random.randint(0, len(self.unused_keys) - 1)))) self.rooms[num] = Room(exit_, self.enemies, self.objects, num, enter) def load(self, user_name): # загрузка игры с базы cur = self.con.cursor() self.user_name = user_name player = cur.execute(f"""SELECT room_num, hit_points, max_hit_points, damage, max_damage, action_points, max_action_points, posX, posY, experience, max_experience FROM users WHERE user_name = '{user_name}'""").fetchone() # все харастеристикик игрока self.unused_keys = list( map( lambda i: i[0], cur.execute(f"""SELECT type FROM inventory WHERE user = '******' AND used = 'False'"""))) self.player = Player((player[-4], player[-3]), *player[1:-4], *player[-2:]) # игрок self.player.inventory = list( map( lambda i: i[0], cur.execute(f"""SELECT type FROM inventory WHERE user = '******' AND used = 'True'"""))) self.current_room = player[0] rooms = cur.execute(f"""SELECT id, number, enter_posX, enter_posY, exit_posX, exit_posY FROM rooms WHERE user = '******'""").fetchall() self.rooms = {} for room_id, number, *positions in rooms: # все комнаты подземелья enemies = cur.execute(f"""SELECT color, hit_points, max_hit_points, action_points, max_action_points, damage, max_damage, posX, posY FROM entities WHERE room_id = {room_id}""").fetchall() list_of_enemies = [] list_of_objects = [] # все враги на карте for color, hit, m_hit, act, m_act, dam, m_dam, x, y in enemies: list_of_enemies.append( Enemy((x, y), color, hit, m_hit, dam, m_dam, act, m_act)) objects = cur.execute(f"""SELECT type, posX, posY, inside, color, stage FROM objects WHERE room_id = {room_id}""").fetchall() for type_, x, y, inside, color, stage in objects: # все объекты на карте if type_ == 1: # коробки list_of_objects.append(Box((x, y))) elif type_ == 2: # сундуки list_of_objects.append( Chest((x, y), *reversed(inside.split('_')))) if stage: list_of_objects[-1].touch() else: # двери list_of_objects.append(Door((x, y), color)) self.rooms[number] = Room(positions[-2:], list_of_enemies, list_of_objects, number, positions[:2]) self.enemies = self.rooms[self.current_room].enemies self.entities = [self.player, *self.enemies] self.objects = self.rooms[self.current_room].objects self.load_room(player[0]) def save_room(self, n): # сохранение 1 комнаты в базе cur = self.con.cursor() room_id = cur.execute(f"""SELECT id FROM rooms WHERE number = {n} and user = '******'""").fetchone()[0] room = self.rooms[n] for enemy in room.enemies: if enemy.alive: cur.execute(f"""INSERT INTO entities(hit_points, max_hit_points, action_points, max_action_points, damage, max_damage, posX, posY, room_id, color) values({enemy.hit_points[0]}, {enemy.hit_points[1]}, {enemy.action_points[0]}, {enemy.action_points[1]}, {enemy.damage[0]}, {enemy.damage[1]}, {enemy.position[0]}, {enemy.position[1]}, {room_id}, '{enemy.color}')""") for obj in room.objects: # объекты комнаты if obj.name == 'box': cur.execute(f"""INSERT INTO objects(type, posX, posY, room_id) values(1, {obj.position[0]}, {obj.position[1]}, {room_id})""") elif obj.stage == 0: # если объект активен if obj.name == 'chest': cur.execute(f"""INSERT INTO objects(type, posX, posY, room_id, inside) values(2, {obj.position[0]}, {obj.position[1]}, {room_id}, '{obj.inside.name}')""") elif obj.name == 'door': cur.execute(f"""INSERT INTO objects(type, posX, posY, room_id, color) values(3, {obj.position[0]}, {obj.position[1]}, {room_id}, '{obj.color}')""") elif obj.stage == 1 and obj.name == 'chest': if obj.name == 'chest': cur.execute(f"""INSERT INTO objects(type, posX, posY, room_id, inside, stage) values(2, {obj.position[0]}, {obj.position[1]}, {room_id}, '{obj.inside.name}', 1)""") self.con.commit() def update_base(self): # обновление базы (если имя пользователя уже вводилось) cur = self.con.cursor() cur.execute(f"""UPDATE users SET room_num = {self.current_room}, hit_points = {self.player.hit_points[0]}, max_hit_points = {self.player.hit_points[1]}, action_points = {self.player.action_points[0]}, max_action_points = {self.player.action_points[1]}, damage = {self.player.damage[0]}, max_damage = {self.player.damage[1]}, posX = {self.player.position[0]}, posY = {self.player.position[1]}, experience = '{self.player.experience[0]}', max_experience = '{self.player.experience[1]}' WHERE user_name = '{self.user_name}'""") self.con.commit() cur.execute("""DELETE FROM inventory WHERE user = '******'""") # удаление старого инвентаря for obj in self.player.inventory: cur.execute(f"""INSERT INTO inventory(user, type, used) values('{self.user_name}', '{obj}', 'True')""") for obj in self.unused_keys: cur.execute(f"""INSERT INTO inventory(user, type, used) values('{self.user_name}', '{obj}', 'False')""") self.con.commit() for n, room in self.rooms.items(): # если в комнату заходили, то есть могли изменяться # положения врагов, объектов и тд room_id = cur.execute(f"""SELECT id FROM rooms WHERE number = {n} and user = '******'""").fetchone()[0] cur.execute(f"""DELETE FROM entities WHERE room_id = {room_id}""") self.con.commit() cur.execute(f"""DELETE FROM objects WHERE room_id = {room_id}""") self.con.commit() self.save_room(n) def save(self, user_name): # функция сохранения базы cur = self.con.cursor() self.user_name = user_name if not self.user_name else self.user_name cur.execute(f"""INSERT INTO users(user_name, room_num, hit_points, max_hit_points, action_points, max_action_points, damage, max_damage, posX, posY, experience, max_experience) values('{self.user_name}', {self.current_room}, {self.player.hit_points[0]}, {self.player.hit_points[1]}, {self.player.action_points[0]}, {self.player.action_points[1]}, {self.player.damage[0]},{self.player.damage[1]}, {self.player.position[0]}, {self.player.position[1]}, '{self.player.experience[0]}', '{self.player.experience[1]}')""") # добавление нового пользователя со всеми характеристиками self.con.commit() for obj in self.player.inventory: # добавление инвентаря игрока cur.execute(f"""INSERT INTO inventory(user, type, used) values('{self.user_name}', '{obj}', 'True')""") for obj in self.unused_keys: # добавляются неиспользованные ключи cur.execute(f"""INSERT INTO inventory(user, type, used) values('{self.user_name}', '{obj}', 'False')""") for n, room in self.rooms.items(): cur.execute(f"""INSERT INTO rooms(number, enter_posX, enter_posY, exit_posX, exit_posY, user) values({n}, {room.enter[0]}, {room.enter[1]}, {room.exit_[0]}, {room.exit_[1]}, '{self.user_name}')""") self.con.commit() self.save_room(n) # добавление каждой комнаты в базу def get(self, coordinates, diff=(0, 0)): """Возвращает объект по координатам""" for obj in [*self.entities, *self.objects, *self.base]: if obj.position == (coordinates[0] + diff[1], coordinates[1] + diff[0]): if getattr(obj, 'alive', True): return obj def player_move(self, button): """Движение игрока""" # словарь вида {кнопка: (смещение на X и Y)} buttons_keys = { pygame.K_LEFT: (0, -1), pygame.K_RIGHT: (0, 1), pygame.K_UP: (-1, 0), pygame.K_DOWN: (1, 0) } if any([ i.animator.animation not in ['idle', 'die'] for i in self.enemies ]): # если враги еще совершают какие-то действия, то игрок стоит return if self.player.animator.animation != 'idle': # если игрок совершает какое-то действие, то # мы не начинаем новое действие return if button not in buttons_keys.keys(): return # если нажали на неизвестную кнопку # проверяем на нахождение в телепорте self.player.interaction_teleport(self) # взаимодействуем с объектом obj = self.get(self.player.position, buttons_keys[button]) obj_name = obj.name if hasattr(obj, 'name') else None self.player.interaction(self, buttons_keys[button]) if obj_name == 'enemy' and not obj.alive: self.player.experience[0] += 2 if self.player.experience[0] > self.player.experience[1]: config.NEXT_WINDOW = 'win' def enemies_move(self): """Движение врагов""" if self.player.animator.animation != 'idle': return # если игрок что-то делает, то враги не начинают новых действий options = [(-1, 0), (1, 0), (0, -1), (0, 1)] res = [] blocked_cells = [] for enemy in self.enemies: if not enemy.alive: # текущий враг метрв, то переходим к следущему врагу continue if enemy.animator.animation != 'idle': res.append(True) # если враг уже совершает действие, # то переходим к следущему врагу continue checking = [] for i in options: checking.append( self.get(enemy.position, i).name in ('player', 'empty')) if not any(checking): # если врагу некуда идти res.append(False) continue player_pos = self.player.position enemy_pos = enemy.position diff = (0, 0) if random.randint(0, 1): # генерация ходов врага # враг пытается приблизиться к игроку if enemy_pos[0] != player_pos[0]: diff = (0, -1) if enemy_pos[0] > player_pos[0] else (0, 1) elif enemy_pos[1] != player_pos[1]: diff = (-1, 0) if enemy_pos[1] > player_pos[1] else (1, 0) else: if enemy_pos[1] != player_pos[1]: diff = (-1, 0) if enemy_pos[1] > player_pos[1] else (1, 0) elif enemy_pos[0] != player_pos[0]: diff = (0, -1) if enemy_pos[0] > player_pos[0] else (0, 1) while (enemy_pos[0] + diff[0], enemy_pos[1] + diff[1]) in blocked_cells or \ self.get(enemy_pos, diff).name not in ('empty', 'player'): diff = options[random.randint(0, len(options) - 1)] blocked_cells.append( (enemy_pos[0] + diff[0], enemy_pos[1] + diff[1])) # добавляем результат взаимодействия с список res.append(enemy.interaction(self, diff)) if not any(res): # если у всех врагов закончились очки действий self.turn = 1 # передаем ход игроку for enemy in self.enemies: # обновляем очки действий у врагов enemy.action_points[0] = enemy.action_points[1] def show(self, surf): """Отображение на поверхность""" if self.turn == 2: self.enemies_move() surf.blit(self.background, apply((0, 0))) # отображаем поле for entity in self.entities: # отображаем существ entity.show(surf) for obj in self.objects: # отображаем объекты obj.show(surf) self.top_panel.show(surf) # отображаем верхнюю self.bottom_panel.show(surf) # и нижнюю панели for elem in self.buttons: # отображаем кнопки elem.show(surf) def button_down(self, mouse_pos): """Нажатие мыши""" # получаем объект, на который нажали obj = self.get( (mouse_pos[0] // TILE, (mouse_pos[1] - PANEL_HEIGHT) // TILE)) if isinstance(obj, Enemy) and obj.alive: # если нажали на врага self.bottom_panel.change_target(obj) # меняем цель нижней панели else: self.bottom_panel.change_target(None) for elem in self.buttons: # проверяем нажатие на кнопки elem.button_down(mouse_pos) def key_down(self, key): """Нажатие на клавиатуру""" for elem in self.buttons: elem.key_down(key) if self.turn == 1: # если ход игрока self.player_move(key) # то вызываем функцию движения игрока