Форум программистов, компьютерный форум, киберфорум
Python: GUI, графика
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
1 / 1 / 0
Регистрация: 29.12.2020
Сообщений: 51

Игра

28.02.2021, 20:08. Показов 5157. Ответов 0
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Игрок в ней ходит по сетке размером N_X на N_Y с шагом step. Ему нужно добраться до выхода, причем начальное положение игрока и выхода определяется случайно.

Шаблон программы уже есть:

Python
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
import tkinter
import random
 
 
def move_wrap(obj, move):
    canvas.move(obj, move[0], move[1])
    # Здесь нужно сделать так, чтобы ушедший
    # "за экран" игрок выходил с другой стороны
 
 
def check_move():
    if canvas.coords(player) == canvas.coords(exit):
        label.config(text="Победа!")
 
 
def key_pressed(event):
    if event.keysym == 'Up':
        move_wrap(player, (0, -step))
    # Здесь нужно дописать то, что нужно,
    # чтобы все остальные клавиши работали
    check_move()
 
 
master = tkinter.Tk()
 
step = 60
N_X = 10
N_Y = 10
canvas = tkinter.Canvas(master, bg='blue',
                        width=step * N_X, height=step * N_Y)
 
player_pos = (random.randint(0, N_X - 1) * step,
              random.randint(0, N_Y - 1) * step)
exit_pos = (random.randint(0, N_X - 1) * step,
            random.randint(0, N_Y - 1) * step)
 
player = canvas.create_oval((player_pos[0], player_pos[1]),
                            (player_pos[0] + step, player_pos[1] + step), 
                            fill='green')
exit = canvas.create_oval((exit_pos[0], exit_pos[1]),
                          (exit_pos[0] + step, exit_pos[1] + step), 
                          fill='yellow')
 
label = tkinter.Label(master, text="Найди выход")
label.pack()
canvas.pack()
master.bind("<KeyPress>", key_pressed)
master.mainloop()
Пока есть одна проблема: когда игрок находит выход, ничего не происходит. Он может гулять и дальше. Чтобы исправить это, можно связать с событием какую-нибудь другую функцию. Пусть эта функция ничего не делает. Определим ее и добавим в функцию check_move одну строчку:
Python
1
2
3
4
5
6
7
8
def do_nothing(x):
    pass
 
 
def check_move():
    if canvas.coords(player) == canvas.coords(exit):
        label.config(text="Победа!")
        master.bind("<KeyPress>", do_nothing)
Функция do_nothing принимает на вход один аргумент. Функции, которые используются в команде bind, тоже всегда получают на вход один аргумент — описание события. Если бы мы определили функцию do_nothing() без параметров, то в процессе выполнения программы получили бы ошибку.

Теперь, попадая к выходу, игрок теряет управление, и нам остается только закрыть окно. Наверное, стоит добавить кнопку, которая позволит ему начать сначала.

Создание кнопки

Кнопка создается командой tkinter.Button(...)

В качестве параметров ей нужно передать окно, в котором будет создаваться кнопка; текст, который будет написан на кнопке и функцию, которая вызывается при ее нажатии.

Например так:

Python
1
2
3
restart = tkinter.Button(master, text="Начать заново",
                         command=prepare_and_start)
restart.pack()
Теперь стоит перенести в отдельную функцию код, подготавливающий игровое поле:

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
def prepare_and_start():
    global player, exit
    player_pos = (random.randint(1, N_X - 1) * step,
                  random.randint(1, N_Y - 1) * step)
    exit_pos = (random.randint(1, N_X - 1) * step,
                random.randint(1, N_Y - 1) * step)
    player = canvas.create_oval(
        (player_pos[0], player_pos[1]), 
        (player_pos[0] + step, player_pos[1] + step), 
        fill='green')
    exit = canvas.create_oval(
        (exit_pos[0], exit_pos[1]), 
        (exit_pos[0] + step, exit_pos[1] + step), 
        fill='yellow')
    label.config(text="Найди выход!")
    master.bind("<KeyPress>", key_pressed)
Команда bind работает с функциями, получающими ровно один аргумент — событие.

Поскольку наша программа невелика, мы решим эту проблему за счет глобальных переменных.

Основной код программы теперь выглядит так:

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
step = 60  # Размер клетки
N_X = 10
N_Y = 10   # Размер сетки
master = tkinter.Tk()
label = tkinter.Label(master, text="Найди выход")
label.pack()
canvas = tkinter.Canvas(master, bg='blue', 
                        height=N_X * step, width=N_Y * step)
canvas.pack()
restart = tkinter.Button(master, text="Начать заново",
                         command=prepare_and_start)
restart.pack()
prepare_and_start()
master.mainloop()
При попытке запустить новую программу появляется новая проблема: после нажатия Начать заново игрок и «выход» не исчезают. Нужно добавить в функцию prepare_and_start удаление всех старых объектов. К счастью, это можно сделать одной командой: canvas.delete("all"). надо добавить ее в программу.

В игру уже можно играть, но игроку чересчур легко живется: он даже проиграть не может! надо добавить препятствия: например, огонь, в который нельзя наступать.

Для этого придется переписать функцию prepare_and_start:
Python
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
def prepare_and_start():
    global player, exit, fires
    canvas.delete("all")    
    player_pos = (random.randint(1, N_X - 1) * step,
                  random.randint(1, N_Y - 1) * step)
    exit_pos = (random.randint(1, N_X - 1) * step,
                random.randint(1, N_Y) * step)
    player = canvas.create_oval(
        (player_pos[0], player_pos[1]), 
        (player_pos[0] + step, player_pos[1] + step), 
        fill='green')
    exit = canvas.create_oval(
        (exit_pos[0], exit_pos[1]), 
        (exit_pos[0] + step, exit_pos[1] + step), 
        fill='yellow')
    N_FIRES = 6  # Число клеток, заполненных огнем
    fires = []
    for i in range(N_FIRES):
        fire_pos = (random.randint(1, N_X - 1) * step,
                    random.randint(1, N_Y - 1) * step)
        fire = canvas.create_oval(
            (fire_pos[0], fire_pos[1]), 
            (fire_pos[0] + step, fire_pos[1] + step), 
            fill='red')
        fires.append(fire)
    label.config(text="Найди выход!")
    master.bind("<KeyPress>", key_pressed)
И функцию, проверяющую результат хода:
Python
1
2
3
4
5
6
7
8
def check_move():
    if canvas.coords(player) == canvas.coords(exit):
        label.config(text="Победа!")
        master.bind("<KeyPress>", do_nothing)
    for f in fires:
        if canvas.coords(player) == canvas.coords(f):
            label.config(text="Ты проиграл!")
            master.bind("<KeyPress>", do_nothing)
Игра уже почти как настоящая. Осталось два штриха:

Улучшить графику и
Добавить еще врагов
Добавление графики

На холст (Canvas) можно добавить любую картинку. В зависимости от типа изображения код будет немного варьироваться, мы будем рассматривать работу с изображениями в формате gif. Сначала картинку нужно загрузить с помощью функции tkinter.PhotoImage, а затем создать на холсте:

player_pic = tkinter.PhotoImage(file="doctor.gif")
player = canvas.create_image((player_pos[0], player_pos[1]),
image=player_pic, anchor='nw')
Параметр anchor='nw' означает, что в указанную первым параметром координату помещается левый верхний (буквально — северо-западный, по-английски — north-west) угол картинки. Если этот параметр не указать, то картинка будет центрирована по заданной координате. Можно добавить картинки для всех объектов в основную часть кода и в функцию prepare_and_start().

В основную часть кода:

Python
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
player_pic = tkinter.PhotoImage(file="https://www.cyberforum.ru/images/doctor.gif")
exit_pic = tkinter.PhotoImage(file="https://www.cyberforum.ru/images/tardis.gif")
fire_pic = tkinter.PhotoImage(file="https://www.cyberforum.ru/images/fire.gif")
enemy_pic = tkinter.PhotoImage(file="https://www.cyberforum.ru/images/dalek.gif")
И в функцию prepare_and_start:
 
def prepare_and_start():
    global player, exit, fires
    canvas.delete("all")
    player_pos = (random.randint(1, N_X - 1) * step,
                  random.randint(1, N_Y - 1) * step)
    player = canvas.create_image(
        (player_pos[0], player_pos[1]), image=player_pic, anchor='nw')
    exit_pos = (random.randint(1, N_X - 1) * step,
                random.randint(1, N_Y - 1) * step)
    exit = canvas.create_image(
        (exit_pos[0], exit_pos[1]), image=exit_pic, anchor='nw')
    N_FIRES = 6  # Число клеток, заполненных огнем
    fires = []
    for i in range(N_FIRES):
        fire_pos = (random.randint(1, N_X - 1) * step,
                    random.randint(1, N_Y - 1) * step)
        # fire = canvas.create_oval((fire_pos[0],fire_pos[1]), 
        # (fire_pos[0] + step, fire_pos[1] + step), fill='red')
        fire = canvas.create_image(
            (fire_pos[0], fire_pos[1]), image=fire_pic, anchor='nw')
        fires.append(fire)
    label.config(text="Найди выход!")
    master.bind("<KeyPress>", key_pressed)
Картинки можно выбрать свои — они должны быть в формате gif и иметь размер step*step пикселей. Желательно так же делать их на прозрачном фоне.

Ну и последний штрих. Добавить настоящих врагов, которые тоже могут двигаться. Создадим их в функции prepare_and_start(), немного модифицировав последнюю:
Python
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
def prepare_and_start():
    global player, exit, fires, enemies
    canvas.delete("all")
    player_pos = (random.randint(0, N_X - 1) * step,
                  random.randint(0, N_Y - 1) * step)
    player = canvas.create_image(player_pos, image=player_pic, anchor='nw')
    exit_pos = (random.randint(0, N_X - 1) * step, 
                random.randint(0, N_Y - 1) * step)
    exit = canvas.create_image(exit_pos, image=exit_pic, anchor='nw')
    N_FIRES = 6 #Число клеток, заполненных огнем
    fires = []
    for i in range(N_FIRES):
        fire_pos = (random.randint(0, N_X - 1) * step, 
                    random.randint(0, N_Y - 1) * step)
        fire = canvas.create_image(fire_pos, image=fire_pic, anchor='nw')
        fires.append(fire)
    N_ENEMIES = 4 #Число врагов
    enemies = []
    for i in range(N_ENEMIES):
        enemy_pos = (random.randint(0, N_X - 1) * step, 
                     random.randint(0, N_Y - 1) * step)
        enemy = canvas.create_image(enemy_pos, image=enemy_pic, anchor='nw')
        enemies.append((enemy, random.choice([always_right, random_move])))
    label.config(text="Найди выход!")
    master.bind("<KeyPress>", key_pressed)
Каждый враг в нашей программе будет представлен парой (объект на Canvas + функция движения). Определим для начала две таких функции:

Python
1
2
3
4
5
6
def always_right():
    return (step, 0)
 
 
def random_move():
    return random.choice([(step, 0), (-step, 0), (0, step), (0, -step)])
Модифицируем функцию key_pressed: ее нужно дополнить перемещением врагов — вот таким фрагментом кода:

Python
1
2
3
for enemy in enemies:
    direction = enemy[1]() # вызвать функцию перемещения у "врага"
    move_wrap(enemy[0], direction) # произвести  перемещение
Кроме того, нужно переписать функцию check_move:
Python
1
2
3
4
5
6
7
8
9
10
11
12
def check_move():
    if canvas.coords(player) == canvas.coords(exit):
        label.config(text="Победа!")
        master.bind("<KeyPress>", do_nothing)
    for f in fires:
        if canvas.coords(player) == canvas.coords(f):
            label.config(text="Ты проиграл!")
            master.bind("<KeyPress>", do_nothing)
    for e in enemies:
        if canvas.coords(player) == canvas.coords(e[0]):
            label.config(text="Ты проиграл!")
            master.bind("<KeyPress>", do_nothing)
0
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
28.02.2021, 20:08
Ответы с готовыми решениями:

Игра викторина
Я пишу простейшую игру, мне нужно, чтобы при нажатии на правильный ответ, появлялось окно что ответ правильный и в основном окне запускался...

Игра викторина
Здравствуйте, помогите пожалуйста сделать викторину на python. from tkinter import * from tkinter import messagebox mainWindow =...

Игра Тетрис
Помогите!!! Хотел написать игру Тетрис. Вот код: #!/usr/bin/python3 # -*- coding: utf-8 -*- import sys, random

0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
28.02.2021, 20:08
Помогаю со студенческими работами здесь

Игра. Доработка 2
Придумайте и реализуйте другие стратегии движения врагов (например, они могут всегда двигаться в сторону игрока). Примечания Данная...

Игра на реакцию
from random import randint from kivy.app import App from kivy.clock import Clock from kivy.uix.button import Button from...

Игра. Доработка 1
Доработайте игру так, чтобы два объекта не могли изначально появиться в одном месте. Базовый код: import tkinter import random ...

Мини игра на Python
Привет всем. Долго не решался попросить помощи, так как мне нравится во всем разбираться самому. Но сессия, сплю по 3 часа, а до дедлайна...

игра быки и коровы
почему в Python 3.4 выдает ошибку в коде, а в Python 2.6 нет. Что не так? # -*- coding: utf-8 -*- from tkinter import ttk import...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
1
Ответ Создать тему
Новые блоги и статьи
Символьное дифференцирование
igorrr37 13.02.2026
/ * Логарифм записывается как: (x-2)log(x^2+2) - означает логарифм (x^2+2) по основанию (x-2). Унарный минус обозначается как ! */ #include <iostream> #include <stack> #include <cctype>. . .
Камера Toupcam IUA500KMA
Eddy_Em 12.02.2026
Т. к. у всяких "хикроботов" слишком уж мелкий пиксель, для подсмотра в ESPriF они вообще плохо годятся: уже 14 величину можно рассмотреть еле-еле лишь на экспозициях под 3 секунды (а то и больше),. . .
И ясному Солнцу
zbw 12.02.2026
И ясному Солнцу, и светлой Луне. В мире покоя нет и люди не могут жить в тишине. А жить им немного лет.
«Знание-Сила»
zbw 12.02.2026
«Знание-Сила» «Время-Деньги» «Деньги -Пуля»
SDL3 для Web (WebAssembly): Подключение Box2D v3, физика и отрисовка коллайдеров
8Observer8 12.02.2026
Содержание блога Box2D - это библиотека для 2D физики для анимаций и игр. С её помощью можно определять были ли коллизии между конкретными объектами и вызывать обработчики событий столкновения. . . .
SDL3 для Web (WebAssembly): Загрузка PNG с прозрачным фоном с помощью SDL_LoadPNG (без SDL3_image)
8Observer8 11.02.2026
Содержание блога Библиотека SDL3 содержит встроенные инструменты для базовой работы с изображениями - без использования библиотеки SDL3_image. Пошагово создадим проект для загрузки изображения. . .
SDL3 для Web (WebAssembly): Загрузка PNG с прозрачным фоном с помощью SDL3_image
8Observer8 10.02.2026
Содержание блога Библиотека SDL3_image содержит инструменты для расширенной работы с изображениями. Пошагово создадим проект для загрузки изображения формата PNG с альфа-каналом (с прозрачным. . .
Установка Qt-версии Lazarus IDE в Debian Trixie Xfce
volvo 10.02.2026
В общем, достали меня глюки IDE Лазаруса, собранной с использованием набора виджетов Gtk2 (конкретно: если набирать текст в редакторе и вызвать подсказку через Ctrl+Space, то после закрытия окошка. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru