-
Notifications
You must be signed in to change notification settings - Fork 21
/
Copy pathmain.py
108 lines (94 loc) · 5.31 KB
/
main.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
from ursina import *
class Game(Ursina):
def __init__(self):
super().__init__()
window.fullscreen = True
Entity(model='quad', scale=60, texture='white_cube', texture_scale=(60, 60), rotation_x=90, y=-5,
color=color.light_gray) # plane
Entity(model='sphere', scale=100, texture='textures/sky0', double_sided=True) # sky
EditorCamera()
camera.world_position = (0, 0, -15)
self.model, self.texture = 'models/custom_cube', 'textures/rubik_texture'
self.load_game()
def load_game(self):
self.create_cube_positions()
self.CUBES = [Entity(model=self.model, texture=self.texture, position=pos) for pos in self.SIDE_POSITIONS]
self.PARENT = Entity()
self.rotation_axes = {'LEFT': 'x', 'RIGHT': 'x', 'TOP': 'y', 'BOTTOM': 'y', 'FACE': 'z', 'BACK': 'z'}
self.cubes_side_positons = {'LEFT': self.LEFT, 'BOTTOM': self.BOTTOM, 'RIGHT': self.RIGHT, 'FACE': self.FACE,
'BACK': self.BACK, 'TOP': self.TOP}
self.animation_time = 0.5
self.action_trigger = True
self.action_mode = True
self.message = Text(origin=(0, 19), color=color.black)
self.toggle_game_mode()
self.create_sensors()
self.random_state(rotations=3) # initial state of the cube, rotations - number of side turns
def random_state(self, rotations=3):
[self.rotate_side_without_animation(random.choice(list(self.rotation_axes))) for i in range(rotations)]
def rotate_side_without_animation(self, side_name):
cube_positions = self.cubes_side_positons[side_name]
rotation_axis = self.rotation_axes[side_name]
self.reparent_to_scene()
for cube in self.CUBES:
if cube.position in cube_positions:
cube.parent = self.PARENT
exec(f'self.PARENT.rotation_{rotation_axis} = 90')
def create_sensors(self):
'''detectors for each side, for detecting collisions with mouse clicks'''
create_sensor = lambda name, pos, scale: Entity(name=name, position=pos, model='cube', color=color.dark_gray,
scale=scale, collider='box', visible=False)
self.LEFT_sensor = create_sensor(name='LEFT', pos=(-0.99, 0, 0), scale=(1.01, 3.01, 3.01))
self.FACE_sensor = create_sensor(name='FACE', pos=(0, 0, -0.99), scale=(3.01, 3.01, 1.01))
self.BACK_sensor = create_sensor(name='BACK', pos=(0, 0, 0.99), scale=(3.01, 3.01, 1.01))
self.RIGHT_sensor = create_sensor(name='RIGHT', pos=(0.99, 0, 0), scale=(1.01, 3.01, 3.01))
self.TOP_sensor = create_sensor(name='TOP', pos=(0, 1, 0), scale=(3.01, 1.01, 3.01))
self.BOTTOM_sensor = create_sensor(name='BOTTOM', pos=(0, -1, 0), scale=(3.01, 1.01, 3.01))
def toggle_game_mode(self):
'''switching view mode or interacting with Rubik's cube'''
self.action_mode = not self.action_mode
msg = dedent(f"{'ACTION mode ON' if self.action_mode else 'VIEW mode ON'}"
f" (to switch - press middle mouse button)").strip()
self.message.text = msg
def toggle_animation_trigger(self):
'''prohibiting side rotation during rotation animation'''
self.action_trigger = not self.action_trigger
def rotate_side(self, side_name):
self.action_trigger = False
cube_positions = self.cubes_side_positons[side_name]
rotation_axis = self.rotation_axes[side_name]
self.reparent_to_scene()
for cube in self.CUBES:
if cube.position in cube_positions:
cube.parent = self.PARENT
eval(f'self.PARENT.animate_rotation_{rotation_axis}(90, duration=self.animation_time)')
invoke(self.toggle_animation_trigger, delay=self.animation_time + 0.11)
def reparent_to_scene(self):
for cube in self.CUBES:
if cube.parent == self.PARENT:
world_pos, world_rot = round(cube.world_position, 1), cube.world_rotation
cube.parent = scene
cube.position, cube.rotation = world_pos, world_rot
self.PARENT.rotation = 0
def create_cube_positions(self):
self.LEFT = {Vec3(-1, y, z) for y in range(-1, 2) for z in range(-1, 2)}
self.BOTTOM = {Vec3(x, -1, z) for x in range(-1, 2) for z in range(-1, 2)}
self.FACE = {Vec3(x, y, -1) for x in range(-1, 2) for y in range(-1, 2)}
self.BACK = {Vec3(x, y, 1) for x in range(-1, 2) for y in range(-1, 2)}
self.RIGHT = {Vec3(1, y, z) for y in range(-1, 2) for z in range(-1, 2)}
self.TOP = {Vec3(x, 1, z) for x in range(-1, 2) for z in range(-1, 2)}
self.SIDE_POSITIONS = self.LEFT | self.BOTTOM | self.FACE | self.BACK | self.RIGHT | self.TOP
def input(self, key):
if key in 'mouse1 mouse3' and self.action_mode and self.action_trigger:
for hitinfo in mouse.collisions:
collider_name = hitinfo.entity.name
if (key == 'mouse1' and collider_name in 'LEFT RIGHT FACE BACK' or
key == 'mouse3' and collider_name in 'TOP BOTTOM'):
self.rotate_side(collider_name)
break
if key == 'mouse2':
self.toggle_game_mode()
super().input(key)
if __name__ == '__main__':
game = Game()
game.run()