diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/README.md b/README.md index d9f3f7c..d146a87 100644 --- a/README.md +++ b/README.md @@ -8,9 +8,9 @@ - You can change the direction of rotation of the side by pressing the middle mouse button - You can randomly shuffle the cube by clicking on the sensor under it - **_You must install Ursian to use this app (pip install ursina)_** + - The possibility of recording several commands at once and playing them together **(new)** **In development:** - - The possibility of recording several commands at once and playing them together - Adding standard formulas for speedcubing - Timer @@ -29,6 +29,12 @@ _for example: if you spin cubic and now look at the side in which center is red - push red sencor near you - now all rotations will be understandable - it's like you're looking at this side_ - To randomly shuffle the cube - click on the white sensor _(Random)_ under cube + - About command mode: + - to enter in it   -> press 'r' + - to go out       -> f + - to write       -> same (dawsqe) + - to write "-"     -> g _(when you write '-' -> next rotate will be in another side (counterclockwise or clockwise)_ + - to delete      -> h diff --git a/confic.py b/confic.py new file mode 100644 index 0000000..619ab62 --- /dev/null +++ b/confic.py @@ -0,0 +1,35 @@ +model_cube = 'models/custom_cube' +texture_cube = 'textures/rubik_texture' +text_sky = 'sky_sunset' +tex_wh = 'white_cube' +random_texture = 'textures/random' + +comand_text_1 = 'Now is NOT command mode' +comand_text_2 = 'Now is writing command mode' +button_text = 'play last command' + +alfa_text = ''' + To rotate side -> push\n + Right (r) -> d + Left (l) -> a + Upp (u) -> w + Down (d) -> s + Front (f) -> q + Bottom (b) -> s + + About command mode: + to enter -> r + to out -> f + to write -> same + to write "-" -> g + to delete -> h''' + +randomizing_constant = 50 + +text_size_const = 1080 +sphere_scale = 400 +quad_scale = 50 +button_scale = 0.05 +s_s = 0.5 # sensors_scale + +start_animation_time =0.3 \ No newline at end of file diff --git a/main.py b/main.py index 7d33cf1..8232f9d 100644 --- a/main.py +++ b/main.py @@ -1,13 +1,14 @@ from ursina import * +from confic import * class Game(Ursina): def __init__(self): super().__init__() # window.fullscreen = True - Entity(model='sphere', scale=400, texture='sky_sunset', double_sided=True) # задаёт внешнюю сферу - Entity(model='quad', scale=50, texture='white_cube', texture_scale=(50, 50), rotation_x=90, y=-5, - color=color.light_gray) # задаёт плоскость, важна для наглядности + Entity(model='sphere', scale=sphere_scale, texture=text_sky, double_sided=True) # задаёт внешнюю сферу + Entity(model='quad', scale=quad_scale, texture=tex_wh, texture_scale=(quad_scale, quad_scale), rotation_x=90, + y=-5, color=color.light_gray) # задаёт плоскость, важна для наглядности EditorCamera() # даёт управление камерой self.load_game() @@ -26,33 +27,34 @@ def load_game(self): self.PARENT = Entity() self.creating() - self.CUBES = [Entity(model='models/custom_cube', texture='textures/rubik_texture', position=pos) for pos + self.CUBES = [Entity(model=model_cube, texture=texture_cube, position=pos) for pos in self.SIDE_POSITIONS] # создание самих кубиков - self.trans_to_front() # задание отсчёта для поворотов + self.trans_to_front() # задание отсчёта для поворотов - self.animation_time = 0.3 + self.animation_time = start_animation_time self.action_trigger = True # для отсутствия наложения действий друг на друга self.mode_of_spin = False # для смены направления вращения сторон + self.comand = '' + self.comand_trigger = False + self.comand_message = Text(text='', x=0, y=-0.40, color=color.black) + self.instr_mode_comand = Text(text=comand_text_1, x=0, y=-0.43, color=color.black) + b = Button(text=button_text, color=color.light_gray, scale=button_scale, y=-0.45, x=-0.14) + b.fit_to_text() + b.on_click = self.play_last_comand + self.message = Text(origin=(-0.5, 19), color=color.black) # подсказка для смены направления вращения self.switch_mode() - Text.default_resolution = 1080 * Text.size - - alfa = dedent(''' - To rotate side -> push\n - Right -> d - Left -> a - Upp -> w - Down -> s - Front -> q - Bottom -> s''').strip() + Text.default_resolution = text_size_const * Text.size + + alfa = dedent(alfa_text).strip() self.instuction = Text(text=alfa, x=0.6, y=0.4, color=color.black) # подсказка клавиш для поворотов self.create_sensors() # создание точек для смены стороны вращения - def randomizing(self, k=50): # случайное перемешивание кубика + def randomizing(self, k=randomizing_constant): # случайное перемешивание кубика [self.rand_func(random.choice(list(self.rotation_axes_all_cube))) for i in range(k)] def rand_func(self, side_name): @@ -65,27 +67,27 @@ def rand_func(self, side_name): cube.parent = self.PARENT exec(f'self.PARENT.rotation_{rotation_axis[1]} = 90') - def create_sensors(self): # создание сенсоров для смены стороны вращения + перемешивание + def create_sensors(self): # создание сенсоров для смены стороны вращения + перемешивание - create_sensor = lambda name, pos, scale, texture: Entity(name=name, position=pos, model='sphere', texture=texture, + create_sensor = lambda name, pos, scale, texture: Entity(name=name, position=pos, model='sphere', + texture=texture, scale=scale, collider='box') - self.random_st_sensor = create_sensor(name='LEFT', pos=(-6, -2, 0), scale=(0.5, 0.5, 0.5), + self.random_st_sensor = create_sensor(name='LEFT', pos=(-6, -2, 0), scale=(s_s, s_s, s_s), texture='textures/blue') - self.random_st_sensor = create_sensor(name='FRONT', pos=(0, -2, -6), scale=(0.5, 0.5, 0.5), + self.random_st_sensor = create_sensor(name='FRONT', pos=(0, -2, -6), scale=(s_s, s_s, s_s), texture='textures/red') - self.random_st_sensor = create_sensor(name='RIGHT', pos=(6, -2, 0), scale=(0.5, 0.5, 0.5), + self.random_st_sensor = create_sensor(name='RIGHT', pos=(6, -2, 0), scale=(s_s, s_s, s_s), texture='textures/green') - self.random_st_sensor = create_sensor(name='BACK', pos=(0, -2, 6), scale=(0.5, 0.5, 0.5), + self.random_st_sensor = create_sensor(name='BACK', pos=(0, -2, 6), scale=(s_s, s_s, s_s), texture='textures/orange') self.random_st_sensor = Entity(name='RANDOM', position=(0, -4.99, 0), rotation_x=90, model='quad', - texture='textures/random', - scale=(1, 1), collider='box') + texture=random_texture, scale=(1, 1), collider='box') def switch_mode(self): # смена направления вращения self.mode_of_spin = not self.mode_of_spin msg = (f"{'Normal spin mode' if self.mode_of_spin else 'UNNormal spin mode ON'}" - f" (to switch - press middle mouse button)").strip() + f" (to switch - press middle mouse button)").strip() self.message.text = msg def switch_trigger(self): @@ -107,29 +109,40 @@ def rotation(self, side_name): # основная функция вращени eval(f'self.PARENT.animate_rotation_{rotation_axis[1]}(-90, duration=self.animation_time)') invoke(self.switch_trigger, delay=self.animation_time + 0.05) - def trans_to_left(self): # смена центра вращения - self.rotation_axes_all_cube = {'LEFT': '0z', 'RIGHT': '1z', 'TOP': '1y', 'BOTTOM': '0y', 'FRONT': '0x', - 'BACK': '1x'} - self.cubes_side_positons = {'BACK': self.RIGHT, 'BOTTOM': self.BOTTOM, 'RIGHT': self.FRONT, 'FRONT': self.LEFT, - 'LEFT': self.BACK, 'TOP': self.TOP} - - def trans_to_right(self): # смена центра вращения - self.rotation_axes_all_cube = {'LEFT': '1z', 'RIGHT': '0z', 'TOP': '1y', 'BOTTOM': '0y', 'FRONT': '1x', - 'BACK': '0x'} - self.cubes_side_positons = {'LEFT': self.FRONT, 'BOTTOM': self.BOTTOM, 'RIGHT': self.BACK, 'FRONT': self.RIGHT, - 'BACK': self.LEFT, 'TOP': self.TOP} - def trans_to_front(self): # смена центра вращения self.rotation_axes_all_cube = {'LEFT': '0x', 'RIGHT': '1x', 'TOP': '1y', 'BOTTOM': '0y', 'FRONT': '1z', 'BACK': '0z'} self.cubes_side_positons = {'LEFT': self.LEFT, 'BOTTOM': self.BOTTOM, 'RIGHT': self.RIGHT, 'FRONT': self.FRONT, 'BACK': self.BACK, 'TOP': self.TOP} - def trans_to_back(self): # смена центра вращения - self.rotation_axes_all_cube = {'LEFT': '1x', 'RIGHT': '0x', 'TOP': '1y', 'BOTTOM': '0y', 'FRONT': '0z', - 'BACK': '1z'} - self.cubes_side_positons = {'BACK': self.FRONT, 'BOTTOM': self.BOTTOM, 'RIGHT': self.LEFT, 'FRONT': self.BACK, - 'LEFT': self.RIGHT, 'TOP': self.TOP} + def trans_to(self, side): + if side == 'LEFT': + self.rotation_axes_all_cube['LEFT'] = '0z' + self.rotation_axes_all_cube['RIGHT'] = '1z' + self.rotation_axes_all_cube['FRONT'] = '0x' + self.rotation_axes_all_cube['BACK'] = '1x' + self.cubes_side_positons['LEFT'] = self.BACK + self.cubes_side_positons['RIGHT'] = self.FRONT + self.cubes_side_positons['FRONT'] = self.LEFT + self.cubes_side_positons['BACK'] = self.RIGHT + elif side == 'RIGHT': + self.rotation_axes_all_cube['LEFT'] = '1z' + self.rotation_axes_all_cube['RIGHT'] = '0z' + self.rotation_axes_all_cube['FRONT'] = '1x' + self.rotation_axes_all_cube['BACK'] = '0x' + self.cubes_side_positons['LEFT'] = self.FRONT + self.cubes_side_positons['RIGHT'] = self.BACK + self.cubes_side_positons['FRONT'] = self.RIGHT + self.cubes_side_positons['BACK'] = self.LEFT + elif side == 'BACK': + self.rotation_axes_all_cube['LEFT'] = '1x' + self.rotation_axes_all_cube['RIGHT'] = '0x' + self.rotation_axes_all_cube['FRONT'] = '0z' + self.rotation_axes_all_cube['BACK'] = '1z' + self.cubes_side_positons['LEFT'] = self.RIGHT + self.cubes_side_positons['RIGHT'] = self.LEFT + self.cubes_side_positons['FRONT'] = self.BACK + self.cubes_side_positons['BACK'] = self.FRONT def reparent_to_scene(self): # привязка к мировой сцене для поворотов for cube in self.CUBES: @@ -141,39 +154,120 @@ def reparent_to_scene(self): # привязка к мировой сцене д cube.rotation = world_rot self.PARENT.rotation = 0 + def switch_command_trigger(self): + self.comand_trigger = not self.comand_trigger + if not self.comand_trigger: + self.instr_mode_comand.text = comand_text_1 + else: + self.instr_mode_comand.text = comand_text_2 + + def upd_text_message(self): + self.comand_message.text = 'last comand = ' + self.comand[::2] + + def rotation_bez_animation(self, side_name, norm=True): + self.action_trigger = False + rotation_axis = self.rotation_axes_all_cube[side_name] + positions = self.cubes_side_positons[side_name] + + self.reparent_to_scene() + + for cube in self.CUBES: + if cube.position in positions: + cube.parent = self.PARENT + if (rotation_axis[0] == '1') == norm: + exec(f'self.PARENT.rotation_{rotation_axis[1]} = 90') + else: + exec(f'self.PARENT.rotation_{rotation_axis[1]} =-90') + + def play_last_comand(self): + if not self.action_trigger: + return + norm = True + for elem in self.comand[::2]: + if elem == 'l': + self.rotation_bez_animation('LEFT', norm) + norm = True + elif elem == 'r': + self.rotation_bez_animation('RIGHT', norm) + norm = True + elif elem == 't': + self.rotation_bez_animation('TOP', norm) + norm = True + elif elem == 'b': + self.rotation_bez_animation('BACK', norm) + norm = True + elif elem == 'd': + self.rotation_bez_animation('BOTTOM', norm) + norm = True + elif elem == 'f': + self.rotation_bez_animation('FRONT', norm) + norm = True + elif elem == '-': + norm = not norm + self.action_trigger = True + def input(self, key, is_raw=False): - if key in 'mouse1' and self.action_trigger: # проверка на взаимодействие с сенсорами - for hitinfo in mouse.collisions: - collider_name = hitinfo.entity.name - if key == 'mouse1' and collider_name == 'RANDOM': - self.randomizing() - break - elif key == 'mouse1' and collider_name == 'LEFT': - self.trans_to_left() - elif key == 'mouse1' and collider_name == 'FRONT': - self.trans_to_front() - elif key == 'mouse1' and collider_name == 'RIGHT': - self.trans_to_right() - elif key == 'mouse1' and collider_name == 'BACK': - self.trans_to_back() - break - - if key == 'd' and self.action_trigger: # вращение в зависимсости от нажатия клавиш - self.rotation('RIGHT') - if key == 'a' and self.action_trigger: - self.rotation('LEFT') - if key == 'w' and self.action_trigger: - self.rotation('TOP') - if key == 's' and self.action_trigger: - self.rotation('BOTTOM') - if key == 'q' and self.action_trigger: - self.rotation('FRONT') - if key == 'e' and self.action_trigger: - self.rotation('BACK') - - if key == 'mouse2': # смена направления вращения - self.switch_mode() - super().input(key) + if self.comand_trigger: + if key == 'a': + self.comand += 'l' + elif key == 'd': + self.comand += 'r' + elif key == 'w': + self.comand += 't' + elif key == 's': + self.comand += 'd' + elif key == 'q': + self.comand += 'f' + elif key == 'e': + self.comand += 'b' + elif key == 'g': + self.comand += '-' + elif key == 'h': + self.comand = self.comand[:len(self.comand) - 1] + self.upd_text_message() + if key == 'f': + # print('inswitch') + # print(self.comand) + self.switch_command_trigger() + super().input(key) + else: + if key in 'mouse1' and self.action_trigger: # проверка на взаимодействие с сенсорами + for hitinfo in mouse.collisions: + collider_name = hitinfo.entity.name + if key == 'mouse1' and collider_name == 'RANDOM': + self.randomizing() + break + elif key == 'mouse1' and collider_name == 'LEFT': + self.trans_to('LEFT') + elif key == 'mouse1' and collider_name == 'FRONT': + self.trans_to_front() + elif key == 'mouse1' and collider_name == 'RIGHT': + self.trans_to('RIGHT') + elif key == 'mouse1' and collider_name == 'BACK': + self.trans_to('BACK') + break + + if key == 'd' and self.action_trigger: # вращение в зависимсости от нажатия клавиш + self.rotation('RIGHT') + if key == 'a' and self.action_trigger: + self.rotation('LEFT') + if key == 'w' and self.action_trigger: + self.rotation('TOP') + if key == 's' and self.action_trigger: + self.rotation('BOTTOM') + if key == 'q' and self.action_trigger: + self.rotation('FRONT') + if key == 'e' and self.action_trigger: + self.rotation('BACK') + + if key == 'r' and self.action_trigger: # сообщение - теперь вы вводите команду + # print('switch') + self.comand = '' + self.switch_command_trigger() + + if key == 'mouse2': # смена направления вращения + self.switch_mode() + super().input(key) if __name__ == '__main__':