Advertisement
Nikmosi

ii_laba_4

Mar 16th, 2023
525
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 10.68 KB | None | 0 0
  1. import tkinter
  2. import random
  3.  
  4. step = 60
  5. N_X = 10
  6. N_Y = 10
  7.  
  8. CURRENT_LEVEL = 0  # текущий уровень сложности
  9. N_ENEMIES = 4  # Число врагов
  10. N_FIRES = 6  # Число клеток, заполненных огнем
  11. PLAYER_HEALTH = 10  # Здоровье игрока
  12. PLAYER_MAX_HEALTH = 10  # максимальный уровнь здоровья игрока
  13. ENEMY_DAMAGE = 1  # урон от врагов
  14. FIRE_DAMAGE = 2  # урон от огня
  15. GUN_SIZE = step / 5  # размер оружия
  16. fires = []  # список номеров огней на канвасе
  17. enemies = []  # список (враз, способ движения врага)
  18. spawners = []  # позоции спавнеров
  19. GUN_DIRECTION = (step, 0)  # направлени оружия
  20. SPAWN_SIZE = 10  # размер спавнера
  21. ENEMY_SAPAWN_CHANCE = 0.1  # Шанс появления противника на сповнере
  22.  
  23.  
  24. def try_spawn_enemy():  # попробовать заспавнить врага на спавне
  25.     player_pos = oval_cord_to_pos(canvas.coords(player))
  26.     enemy_pos = random.choice(spawners)
  27.     if is_value_equal(enemy_pos, player_pos):
  28.         return
  29.     enemy = canvas.create_oval(
  30.         (enemy_pos[0], enemy_pos[1]),
  31.         (enemy_pos[0] + step, enemy_pos[1] + step),
  32.         fill='white')
  33.     enemies.append((enemy, random.choice([always_right, random_move, move_to_player])))
  34.  
  35.  
  36. def level_up():  # Поднять уровнь сложности
  37.     global N_X, N_Y, CURRENT_LEVEL, PLAYER_HEALTH, PLAYER_MAX_HEALTH, ENEMY_DAMAGE, FIRE_DAMAGE, N_ENEMIES, N_FIRES
  38.     if CURRENT_LEVEL < 5:
  39.         CURRENT_LEVEL += 1
  40.         N_X += 2
  41.         N_Y += 2
  42.         canvas.config(width=step * N_X, height=step * N_Y)
  43.         PLAYER_HEALTH += 5
  44.         PLAYER_MAX_HEALTH += 5
  45.         ENEMY_DAMAGE += 1
  46.         FIRE_DAMAGE *= 2
  47.         N_ENEMIES += 3
  48.         N_FIRES += 3
  49.     prepare_and_start()
  50.  
  51.  
  52. def level_down():  # уменьшить уровень сложности
  53.     global N_X, N_Y, CURRENT_LEVEL, PLAYER_HEALTH, PLAYER_MAX_HEALTH, ENEMY_DAMAGE, FIRE_DAMAGE, N_ENEMIES, N_FIRES
  54.     if CURRENT_LEVEL > 0:
  55.         CURRENT_LEVEL -= 1
  56.         N_X -= 2
  57.         N_Y -= 2
  58.         canvas.config(width=step * N_X, height=step * N_Y)
  59.         PLAYER_HEALTH -= 5
  60.         PLAYER_MAX_HEALTH -= 5
  61.         ENEMY_DAMAGE -= 1
  62.         FIRE_DAMAGE //= 2
  63.         N_ENEMIES -= 3
  64.         N_FIRES -= 3
  65.     prepare_and_start()
  66.  
  67.  
  68. def get_format_player_health():  # вернуть форматированное здоровье игрока
  69.     global PLAYER_HEALTH, PLAYER_MAX_HEALTH
  70.     left = ''.join(['#' for _ in range(PLAYER_HEALTH)])
  71.     right = ''.join('_' for _ in range((PLAYER_MAX_HEALTH - PLAYER_HEALTH)))
  72.     return f"[ {left}{right} ]"
  73.  
  74.  
  75. def is_value_equal(l1, l2) -> bool:  # сравнение списков по значению
  76.     if len(l1) != len(l2):
  77.         return False
  78.     return all(map(lambda a: a[0] == a[1], zip(l1, l2)))
  79.  
  80.  
  81. def oval_cord_to_pos(cord):  # координаты центра овала
  82.     return (cord[0] + cord[2]) / 2, (cord[1] + cord[3]) / 2
  83.  
  84.  
  85. def is_empty(pos) -> bool:  # проверяет пустая ли позиция
  86.     taked = [canvas.coords(player),
  87.              canvas.coords(exit),
  88.              *map(lambda a: canvas.coords(a), fires),
  89.              *map(lambda a: canvas.coords(a[0]), enemies)]
  90.     taked = filter(lambda a: len(a) > 0, taked)
  91.     taked = map(oval_cord_to_pos, taked)
  92.     return not any(map(lambda a: is_value_equal(a, pos), taked))
  93.  
  94.  
  95. def always_right(pos):
  96.     return step, 0
  97.  
  98.  
  99. def random_move(pos):
  100.     return random.choice([(step, 0), (-step, 0), (0, step), (0, -step)])
  101.  
  102.  
  103. def sign(value):  # возрващает знак числа
  104.     return 1 if value > 0 else -1
  105.  
  106.  
  107. def move_to_player(pos):  # возвращает направление движения к игроку
  108.     player_pos = oval_cord_to_pos(canvas.coords(player))
  109.     y = step * sign(player_pos[1] - pos[1])
  110.     x = step * sign(player_pos[0] - pos[0])
  111.     if pos[0] == player_pos[0]:
  112.         return 0, y
  113.     if pos[1] == player_pos[1]:
  114.         return x, 0
  115.     return random.choice([(x, 0), (0, y)])
  116.  
  117.  
  118. def prepare_and_start():
  119.     global player, exit, fires, enemies, gun, GUN_SIZE, PLAYER_HEALTH, GUN_DIRECTION, SPAWN_SIZE
  120.     canvas.delete("all")
  121.     PLAYER_HEALTH = PLAYER_MAX_HEALTH
  122.     player_pos = (random.randint(1, N_X - 1) * step,
  123.                   random.randint(1, N_Y - 1) * step)
  124.     gun_pos = list(player_pos)
  125.     gun_pos[0] += GUN_DIRECTION[0] / 2 + step / 2
  126.     gun_pos[1] += GUN_DIRECTION[1] / 2 + step / 2
  127.     exit_pos = (random.randint(1, N_X - 1) * step,
  128.                 random.randint(1, N_Y - 1) * step)
  129.     player = canvas.create_oval(
  130.         (player_pos[0], player_pos[1]),
  131.         (player_pos[0] + step, player_pos[1] + step),
  132.         fill='green')
  133.     gun = canvas.create_oval(
  134.         (gun_pos[0], gun_pos[1]),
  135.         (gun_pos[0] + GUN_SIZE, gun_pos[1] + GUN_SIZE),
  136.         fill='cyan')
  137.     canvas.move(gun, - GUN_SIZE / 2, - GUN_SIZE / 2)
  138.     exit = canvas.create_oval(
  139.         (exit_pos[0], exit_pos[1]),
  140.         (exit_pos[0] + step, exit_pos[1] + step),
  141.         fill='yellow')
  142.     fires = []
  143.     for i in range(N_FIRES):
  144.         fire_pos = (random.randint(1, N_X - 1) * step,
  145.                     random.randint(1, N_Y - 1) * step)
  146.         if not is_empty(fire_pos):
  147.             continue
  148.         fire = canvas.create_oval(
  149.             (fire_pos[0], fire_pos[1]),
  150.             (fire_pos[0] + step, fire_pos[1] + step),
  151.             fill='red')
  152.         fires.append(fire)
  153.     enemies = []
  154.     for i in range(N_ENEMIES):
  155.         enemy_pos = (random.randint(0, N_X - 1) * step,
  156.                      random.randint(0, N_Y - 1) * step)
  157.         if is_value_equal(enemy_pos, player_pos):
  158.             continue
  159.         canvas.create_oval(
  160.             (enemy_pos[0] + step / 2 - SPAWN_SIZE, enemy_pos[1] + step / 2 - SPAWN_SIZE),
  161.             (enemy_pos[0] + step / 2 + SPAWN_SIZE, enemy_pos[1] + step / 2 + SPAWN_SIZE),
  162.             fill='black')
  163.         enemy = canvas.create_oval(
  164.             (enemy_pos[0], enemy_pos[1]),
  165.             (enemy_pos[0] + step, enemy_pos[1] + step),
  166.             fill='white')
  167.         enemies.append((enemy, random.choice([always_right, random_move, move_to_player])))
  168.         spawners.append(enemy_pos)
  169.     label.config(text="Найди выход!")
  170.     label_level.config(text=f"Текущий уровень сложности: {CURRENT_LEVEL}")
  171.     master.bind("<KeyPress>", key_pressed)
  172.  
  173.  
  174. def do_nothing(event):
  175.     pass
  176.  
  177.  
  178. def move_wrap(obj, move):
  179.     obj_cord_s = canvas.coords(obj)
  180.     obj_cord = list(oval_cord_to_pos(obj_cord_s))
  181.     obj_cord[0] += move[0]
  182.     obj_cord[1] += move[1]
  183.  
  184.     x_mod = 0
  185.     y_mod = 0
  186.  
  187.     if obj_cord[0] < 0:
  188.         x_mod = 1
  189.     if obj_cord[1] < 0:
  190.         y_mod = 1
  191.     if obj_cord[0] > canvas.winfo_width():
  192.         x_mod = -1
  193.     if obj_cord[1] > canvas.winfo_height():
  194.         y_mod = -1
  195.  
  196.     canvas.coords(obj,
  197.                   obj_cord_s[0] + N_X * step * x_mod,
  198.                   obj_cord_s[1] + N_Y * step * y_mod,
  199.                   obj_cord_s[2] + N_X * step * x_mod,
  200.                   obj_cord_s[3] + N_Y * step * y_mod)
  201.     canvas.move(obj, move[0], move[1])
  202.  
  203.  
  204. def check_move():
  205.     global PLAYER_HEALTH, ENEMY_DAMAGE, FIRE_DAMAGE, ENEMY_SAPAWN_CHANCE
  206.     if canvas.coords(player) == canvas.coords(exit):
  207.         label.config(text="Победа!")
  208.         master.bind("<KeyPress>", do_nothing)
  209.     for f in fires:
  210.         if canvas.coords(player) == canvas.coords(f):
  211.             PLAYER_HEALTH -= FIRE_DAMAGE
  212.     for e in enemies:
  213.         if canvas.coords(player) == canvas.coords(e[0]):
  214.             PLAYER_HEALTH -= ENEMY_DAMAGE
  215.     if PLAYER_HEALTH <= 0:
  216.         label.config(text="Ты проиграл!")
  217.         master.bind("<KeyPress>", do_nothing)
  218.     label_health.config(text=get_format_player_health())
  219.  
  220.  
  221. def set_gun_to(direction):  # поставить оружие в сообветивии с направлением
  222.     global GUN_DIRECTION
  223.     if is_value_equal(direction, (0, 0)):
  224.         return
  225.     GUN_DIRECTION = direction
  226.     player_pos = oval_cord_to_pos(canvas.coords(player))
  227.     x = player_pos[0] + direction[0] / 2
  228.     y = player_pos[1] + direction[1] / 2
  229.     canvas.coords(gun, x, y, x + GUN_SIZE, y + GUN_SIZE)
  230.     canvas.move(gun, - GUN_SIZE / 2, - GUN_SIZE / 2)
  231.  
  232.  
  233. def shoot():  # стрельба в направлении оружия
  234.     player_pos = oval_cord_to_pos(canvas.coords(player))
  235.     shoot_pos = [player_pos[i] + GUN_DIRECTION[i] for i in range(2)]
  236.     matches = filter(lambda e: is_value_equal(oval_cord_to_pos(canvas.coords(e[0])), shoot_pos), enemies)
  237.     for i in matches:
  238.         enemies.remove(i)
  239.         canvas.delete(i[0])
  240.  
  241.  
  242. def key_pressed(event):
  243.     direction = (0, 0)
  244.     if event.keysym == 'w':
  245.         direction = (0, -step)
  246.     if event.keysym == 'a':
  247.         direction = (-step, 0)
  248.     if event.keysym == 's':
  249.         direction = (0, step)
  250.     if event.keysym == 'd':
  251.         direction = (step, 0)
  252.  
  253.     move_wrap(player, direction)
  254.     set_gun_to(direction)
  255.  
  256.     if event.keysym == 'space':
  257.         shoot()
  258.  
  259.     for enemy in enemies:
  260.         direction = enemy[1](oval_cord_to_pos(canvas.coords(enemy[0])))  # вызвать функцию перемещения у "врага"
  261.         move_wrap(enemy[0], direction)  # произвести  перемещение
  262.  
  263.     if random.randint(1, 100) / 100 < ENEMY_SAPAWN_CHANCE and N_ENEMIES > len(enemies):
  264.         try_spawn_enemy()
  265.  
  266.     # Здесь нужно дописать то, что нужно,
  267.     # чтобы все остальные клавиши работали
  268.     check_move()
  269.  
  270.  
  271. master = tkinter.Tk()
  272.  
  273. canvas = tkinter.Canvas(master, bg='blue',
  274.                         width=step * N_X, height=step * N_Y)
  275.  
  276. restart = tkinter.Button(master, text="Начать заново!",
  277.                          command=prepare_and_start)
  278. label_level_up = tkinter.Button(master, text="Увеличить уровень сложности",
  279.                                 command=level_up)
  280. label_level_down = tkinter.Button(master, text="Уменьшить уровень сложности",
  281.                                   command=level_down)
  282. label = tkinter.Label(master, text="Найди выход")
  283. label_level = tkinter.Label(master, text=f"Текущий уровень сложности: {CURRENT_LEVEL}")
  284. label_health = tkinter.Label(master, text=get_format_player_health())
  285.  
  286. prepare_and_start()
  287. restart.pack()
  288. label_level_up.pack()
  289. label_level_down.pack()
  290. label.pack()
  291. label_level.pack()
  292. label_health.pack()
  293. canvas.pack()
  294. master.mainloop()
  295.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement