Перейти к содержимому

Как сделать перемещение объекта в python

  • автор:

Перемещение нескольких объектов по клеточному полю.

В предыдущей части урока мы научились рисовать и перемещать по клеточкам один объект. Теперь усложняем задание — вводим несколько объектов и перемещаем их по полю. При перемещении мы должны учитывать, что объекты не должны занимать уже занятые клеточки( налазить друг на друга) и разрешение на перемещение определяется лкм.

Исходники для написания логических игр

И так, раз у нас уже несколько объектов, то я их как обычно сразу заношу в список, для проверки свободно или занято место куда я хочу переместить объект буду использовать двумерный список(изначально пустой).

Первым делом рождаем наши объекты , как экземпляры класса.

hero1 = Sprite(margin,margin,(‘abcd.png’))
hero2 = Sprite(margin+(width +margin),margin,(‘abcd1.png’))
hero3 = Sprite((width +margin)*2+margin,margin,(‘abcd2.png’))

Что мы меняем в классе? 1)Добавляем в функцию выделения объекта мышкой — запрет на перемещение конкрктного объекта, если этого не сделать возникнет ситуация когда можно последовательно активировать несколько объектов и при нажатии клавиши курсора переместятся сразу несколько объектов, а не один.2)Добавляем в класс функцию перемещения с запоминанием первоначального положения нашего объекта(для случая когда перемещение будет отклонено из за занятости клетки), в этой же функции заносим запись, что клетка свободна.Если проверка выявляет, что объект перемещен на занятую клетку, проводим откат назад. 3) Функция записи занятости клеток поля.

class Sprite:
def __init__(self,xpos,ypos,filename):
self.x = xpos
self.y = ypos
self.image=pygame.image.load(filename) # создаем рисунок-загрузка из файла
self.action = False
self.rect = self.image.get_rect() # представляем его прямоугольником

self.w = self.image.get_width() #ширина
self.h = self.image.get_height() #высота
all_s.append(self)

self.row = None
self.column = None
def bum (self): # проверка попадания мышки на объект

if self.x self.action = True# объект активирован
else:
self.action = False# для избежания случая активации одновременно
# двух объектов

def mouv(self): # функция перемещения объекта
a = self.x # первоначальные координаты объекта
b = self.y

if e.key == pygame.K_LEFT:
if self.x >margin and self.action == True:
self.x -= margin+width
self.action = False# запрет на перемещение
grid[ b // (height + margin)][ a // (width + margin)] =0

if e.key == pygame.K_RIGHT:
if self.x <(width +margin)*(n-1)and self.action == True:
self.x += margin+width
self.action = False
grid[ b // (height + margin)][ a // (width + margin)] =0
if e.key == pygame.K_UP:
if self.y >margin and self.action == True:
self.y -=height+margin
self.action = False# запрет на перемещение
grid[ b // (height + margin)][ a // (width + margin)] =0
if e.key == pygame.K_DOWN:
if self.y self.y += height+margin
self.action = False# запрет на перемещение
grid[ b // (height + margin)][ a // (width + margin)] =0
self.column = self.x // (width + margin)
self.row = self.y // (height + margin)
if grid[self.row][self.column] ==1:
self.x = a
self.y = b

def mesto(self):
self.column = self.x // (width + margin)
self.row = self.y // (height + margin)
grid[self.row][self.column] = 1

def render (self ): # отображение обьекта на игровом поле(экране)
screen.blit(self.image,(self.x,self.y))
Для операций проверок занятости клеток поля, а следовательно и правильного перемещения кубиков организуем двумерный список, если клетка свободна — она будет иметь значение 0, если занята 1:

grid = []
for row in range(n):
# заполняем пустую матрицу
# 10 х 10 grid[row,column]
grid.append([])
for column in range(n):
grid[row].append(0)

Полный код программы:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import pygame,sys,os
import random
# Define some colors лкм — рисуем кубик в клетку, пкм — стираем кубик(закрашиваем белым)
BLACK = ( 0, 0, 0)
WHITE = ( 255, 255, 255)
GREEN = ( 0, 255, 0)
RED = ( 255, 0, 0)
pygame.init()
# окно
action = False

n=4# количество клеток квадратного поля игры
width = 48#ширина клетки( и объекта)
height = 48#высота клетки ( и объекта)
playr = None
margin = 5# промежуток между клетками
x=None
y=None
window = pygame.display.set_mode(((width +margin)*n+margin,(height+margin)*n+margin))# создаём окно
pygame.display.set_caption(‘Masha and Misha’) # титул строка
screen = pygame.Surface(((width +margin)*n+margin,(height+margin)*n+margin)) # создаем игровое поле(экран)
all_s = []

class Sprite:
def __init__(self,xpos,ypos,filename):
self.x = xpos
self.y = ypos
self.image=pygame.image.load(filename) # создаем рисунок-загрузка из файла
self.action = False
self.rect = self.image.get_rect() # представляем его прямоугольником

self.w = self.image.get_width() #ширина
self.h = self.image.get_height() #высота
all_s.append(self)

self.row = None
self.column = None
def bum (self):# проверка попадания мышки на объект

if self.x self.action = True# объект активирован
else:
self.action = False# для избежания случая активации одновременно
# двух объектов

def mouv(self):# функция перемещения объекта
a = self.x # первоначальные координаты объекта
b = self.y

if e.key == pygame.K_LEFT:
if self.x >margin and self.action == True:
self.x -= margin+width
self.action = False# запрет на перемещение
grid[ b // (height + margin)][ a // (width + margin)] =0

if e.key == pygame.K_RIGHT:
if self.x <(width +margin)*(n-1)and self.action == True:
self.x += margin+width
self.action = False
grid[ b // (height + margin)][ a // (width + margin)] =0
if e.key == pygame.K_UP:
if self.y >margin and self.action == True:
self.y -=height+margin
self.action = False# запрет на перемещение
grid[ b // (height + margin)][ a // (width + margin)] =0
if e.key == pygame.K_DOWN:
if self.y self.y += height+margin
self.action = False# запрет на перемещение
grid[ b // (height + margin)][ a // (width + margin)] =0
self.column = self.x // (width + margin)
self.row = self.y // (height + margin)
if grid[self.row][self.column] ==1:
self.x = a
self.y = b

def mesto(self):
self.column = self.x // (width + margin)
self.row = self.y // (height + margin)
grid[self.row][self.column] = 1
print grid
def render (self ):# отображение обьекта на игровом поле(экране)
screen.blit(self.image,(self.x,self.y))

hero1 = Sprite(margin,margin,(‘abcd.png’))
hero2 = Sprite(margin+(width +margin),margin,(‘abcd1.png’))
hero3 = Sprite((width +margin)*2+margin,margin,(‘abcd2.png’))

done = True# некая переменная
grid = []
for row in range(n):
# заполняем пустую матрицу
# 10 х 10 grid[row,column]
grid.append([])
for column in range(n):
grid[row].append(0)
while done:# условие существования игрового цикла

screen.fill((0,0,90))
for e in pygame.event.get():# для любого события

if e.type == pygame.QUIT:# если было закрытие окна
sys.exit()
if e.type == pygame.MOUSEBUTTONDOWN : # если событие мышь
if pygame.mouse.get_pressed()[0]:#если была нажата лкм
mp = pygame.mouse.get_pos()
for i in all_s :#
i.bum() # выбор объекта

# Перемещение объекта с помощью курсора
if e.type == pygame.KEYDOWN: # если была нажата клавиша
for i in all_s:
i.mouv()

for row in range(n):# рисуем игровое поле
for column in range(n):
color = WHITE
pygame.draw.rect(screen,
color,
[(margin+width)*column+margin,
(margin+height)*row+margin,
width,
height])

for i in all_s:# запись положения объекта в список grid
i.mesto()

for i in all_s:
i.render()

window.blit(screen,(0,0))# на окне прорисовываем поле игры

pygame.display.flip()# отображаем полностью дисплей(окно)

Обработка ввода и анимации¶

Взаимодействие пользователя с компьютером основано на событиях, любые действия производимые пользователем порождают события — движение мыши, нажатия клавиш, специальных кнопок. Внутри библиотеки PyGame есть инструменты для обратки событий, которые происходят внутри приложений.

Мы с вами уже знакомы с методом получения всех произошедших событий — pygame.event.get() , который возвращает события, произошедшие с последнего обращения.

Помимо событий выхода из приложения pygame.QUIT , есть множество других — например, нажатия клавиш pygame.KEYDOWN или отпускания pygame.KEYUP .

Рассмотрим взаимодействие с событиями на примере небольшой программы, в которой по нажатию клавиш показывается квадрат:

import sys import pygame pygame.init() screen = pygame.display.set_mode((640, 480)) rect = pygame.Rect(40, 40, 120, 120) color = (0, 0, 0) while True: for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit() sys.exit() if event.type == pygame.KEYDOWN: color = (255, 255, 255) pygame.draw.rect(screen, color, rect, 0) pygame.display.flip() 

В данном блоке программа занимется обработкой нажатия клавиш. Сначала мы получаем список всех событий, после чего начинаем последовательно проверять их. Если одно из событий соответствует сигналу к завершению программы, закрываем окно. Если же это нажатие клавиши — перекрашиваем прямоугольник в белый цвет.

При нажатии клавиш

При отпускании клавиш

При нажатии кнопки закрытия программы

При движении мыши

Обработка нажатий клавиш¶

Когда мы нажимаем клавишу, в систему передаётся не только информация о том, что какая-то кнопка нажата, но и её код.

  1. pygame.event.get()
  2. pygame.key.get_pressed()

С первым мы уже знакомы, поэтому стоит внимательнее рассмотреть второй. Он позволяет получить список клавиш, которые нажаты в данный момент в виде кортежа булевых значений. Чтобы узнать нажата ли интересующая нас кнопка, необходимо проверить значение, которе содержится в данном кортеже:

keys = pygame.key.get_pressed() if keys[pygame.K_RETURN]: print("Нажата клавиша enter") 

Перемещение объектов¶

Умея получать от пользователя ввод, мы можем реализовать движения наших фигур на экране:

import sys import pygame pygame.init() screen = pygame.display.set_mode((640, 480)) rect = pygame.Rect(40, 40, 120, 120) while True: for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit() sys.exit() if event.type == pygame.KEYDOWN: if event.key == pygame.K_LEFT: rect.move_ip(-40, 0) elif event.key == pygame.K_RIGHT: rect.move_ip(40, 0) elif event.key == pygame.K_UP: rect.move_ip(0, -40) elif event.key == pygame.K_DOWN: rect.move_ip(0, 40) pygame.draw.rect(screen, (255, 0, 0), rect, 0) pygame.display.flip() 

Для движения объектов используются методы move() и move_ip() , которыми обладают объекты, созданные с помощью функций из pygame.draw . Первый создаёт новую фигуру такого же типа, находящуюся по заданному смещению, второй непосредственно изменяет положение имеющейся фигуры.

Запустив данный код, вы можете заметить, что при перемещении фигуры от неё остаётся “след”. Это связано с тем, что при перемещении объекта, мы его не перемещаем на экране, а рисуем на новом месте поверх старого кадра.

Чтобы избежать данной проблемы, надо добавить вызов метода fill() у нашего экрана, на котором мы рисуем и передать ему цвет, которым надо закрасить фон. Данное действие надо проводить каждый раз перед отрисовкой кадра:

# здесь могла быть ваша проверка событий screen.fill((0, 0, 0)) pygame.draw.rect(screen, (255, 0, 0), rect, 0) pygame.display.flip() 

Использование спрайтов¶

Спрайт — двумерное изображение, используемое в играх.

pygame.image. load ( path ) ¶

Функция для загрузки спрайта из картинки. Path — путь до изображения, возвращает объект типа Surface, который можно использовать для рисования.

Для отрисовки спрайта на экране надо вызвать метод blit() у поверхности на которой производится отрисовка и передать объект спрайта вместе с координатами на которых необходимо отрисовать:

screen = pygame.display.set_mode((640, 480)) sprite = pygame.image.load("sprite.png") screen.blit(sprite, (20, 20)) pygame.quit() 

Анимации¶

В pygame анимации создаются при помощи набора спрайтов, которые последовательно отрисовываются:

animation_set = [pygame.image.load(f"ri>.png") for i in range(1, 6)] window = pygame.display.set_mode((640, 480)) clock = pygame.time.Clock() i = 0 while True: for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit() sys.exit() window.fill((0,0,0)) window.blit(animation_set[i // 12], (100, 20)) i += 1 if i == 60: i = 0 pygame.display.flip() clock.tick(60) 

Создаём список спрайтов, каждый из которых будет отдельным кадром анимации:

animation_set = [pygame.image.load(f"ri>.png") for i in range(1, 6)] 

Создаём часы, для ограничения количества кадров в секунду:

clock = pygame.time.Clock() 

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

i = 0 

Выбор анимации в зависимости от номера кадра и его отрисовка:

window.blit(animation_set[i // 12], (100, 20)) 

Изменение переменной, помогающей выбрать нужный кадр:

i += 1 if i == 60: i = 0 

Ограничение количества кадров в секунду, благодаря чему становится проще просчитывать анимации и синхронизировать события:

clock.tick(60) 

Задания¶

  1. Написать программу, которая будет писать в консоль названия нажатых клавиш. Реализовать поддержку enter, space, w, a, s, d, esc.
  2. С помощью циклов, используя квадрат 10х10 пикселей и его след, нарисовать рамку 100х100 пикселей.
  3. Написать программу, в которой по нажатию клавиш будет двигаться квадрат размером 20х20 пикселей. Учесть, что квадрат не должен выходить за границы экрана.
  4. Доработать программу, чтобы квадрат при каждом движении менял свой цвет на случайный.
  5. Реализовать анимацию движения персонажа. При движении влево или вправо должны показываться соответствующие анимации. Кадры для них взять из архива animations.zip

© Copyright Revision d00c0df4 .

Built with Sphinx using a theme provided by Read the Docs.
Read the Docs v: latest

Versions latest Downloads html On Read the Docs Project Home Builds Free document hosting provided by Read the Docs.

Я не могу понять почему я не могу перемещать объект с помощью мышки на canvas python?

При вызове функции с помощью (bind(», oval)) она рисует овал на холсте canvas
с помощью аргумента event но проблема в том что другая функция не перемещает овал!

код который работает неправильно

import tkinter as tk import sqlite3 as sql root = tk.Tk() canvas = tk.Canvas(root) canvas.pack(fill="both", expand=True) def oval(event):# рисует овал global x1 global y1 global x2 global y2 global shape x1 = event.x + 50 y1 = event.y + 50 x2 = event.x - 50 y2 = event.y - 50 #x1 = 0 #y1 = 0 #x2 = 100 #y2 = 100 shape = canvas.create_oval(x1, y1, x2, y2) def move_oval(event):# перемещает овал global x1 global y1 global x2 global y2 if (x1 = event.x) and (y1 =event.y):# проверка находится ли курсор мышки x1 = event.x - 50 #там где находится овал чтобы переместить его y1 = event.y - 50 x2 = event.x + 50 y2 = event.y + 50 canvas.coords(shape, x1, y1, x2, y2) canvas.bind('', oval) canvas.bind('', move_oval) root.mainloop()

хотя если переменным давать информацию о координатах напрямую то функция move_oval перемещает овал

import tkinter as tk import sqlite3 as sql root = tk.Tk() canvas = tk.Canvas(root) canvas.pack(fill="both", expand=True) def oval(event):# рисует овал global x1 global y1 global x2 global y2 global shape #x1 = event.x + 50 #y1 = event.y + 50 #x2 = event.x - 50 #y2 = event.y - 50 x1 = 0 y1 = 0 x2 = 100 y2 = 100 shape = canvas.create_oval(x1, y1, x2, y2) def move_oval(event):# перемещает овал global x1 global y1 global x2 global y2 if (x1 = event.x) and (y1 =event.y):# проверка находится ли курсор мышки x1 = event.x - 50 #там где находится овал чтобы переместить его y1 = event.y - 50 x2 = event.x + 50 y2 = event.y + 50 canvas.coords(shape, x1, y1, x2, y2) canvas.bind('', oval) canvas.bind('', move_oval) root.mainloop()
  • Вопрос задан более двух лет назад
  • 362 просмотра

Рисование и анимация в TkInter

В процессе работы над вторым проектом мы успели познакомится с библиотекой tkInter. В этом разделе мы научимся рисовать и передвигать объекты, а затем — создадим несложную компьютерную игру. Начнем же! ��

Для рисования в окне tkInter, в него нужно добавить Canvas — холст.

from tkinter import * tk = Tk() # создаем холст размером 640 на 640 пикселей с белым фоном внутри основного окна c = Canvas(tk, width=640, height=640, bg='white') c.pack() # тут будет код для рисования mainloop()

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

Рисуем дом

Начнем с простых геометрических фигур. Вот как устроено рисование прямоугольника:

А вот так — треугольника:

Если совместить вместе, то получится. дом! ��

from tkinter import * tk = Tk() c = Canvas(tk, width=640, height=640, bg='white') c.pack() # рисуем прямоугольник зеленого цвета c.create_rectangle(30, 60, 130, 120, fill='green') # рисуем треугольник (полигон с тремя вершинами) синего цвета c.create_polygon(30, 60, 80, 10, 130, 60, fill='blue') mainloop()

Как сделать его лучше? Напиши программу, которая рисует домик с заданными размером, цветом крыши и первого этажа по нажатию кнопки. Для ввода размеров и цветов используйте Entry. Для очистки canvas можно использовать команду c.delete(«all») .

Деревня

А теперь супер-задание — используй циклы, чтобы нарисовать целую деревню!

Анимация

Теперь мы можем комбинировать геометрические фигуры, но вот только для игры этого недостаточно — объекты должны двигаться! Для начала научимся рисовать овалы:

Для того, чтобы оживить наш рисунок, нам нужно научится перемещать объекты. Для этого используется функция move .

from tkinter import * tk = Tk() c = Canvas(tk, width=640, height=640, bg='white') c.pack() # сохраняем номер соданной фигуры в переменную my_favorite_oval = c.create_oval(0, 0, 50, 50, fill='blue') def moveBall(): # передвигаем наш овал на 10 пикселей по обеим осям c.move(my_favorite_oval, 10, 10) # повторяем через 100 мс (1 секунда) c.after(100, moveBall) # спустя 1 секунду (100 мс) после запуска выполнить moveBall c.after(100, moveBall) mainloop()

Отталкиваемся от стен

Теперь шарик движется, но недолго — очень скоро он вылетает за границу и мы его уже больше не видим. Нужно как то заставить его отталкиваться от стен. Самый простой вариант — просто разворачивать его скорость, как только он касается одной из границ. Коснулись вертикальной границы — умножаем горизонтальную скорость на -1, вертикальной — умножаем вертикальную.

Что дальше?

Отлично, теперь у нас двигается и отталкивается от стен один шарик. Какую игру мы можем из этого сделать? Например, подобие астероидов: космический корабль должен как можно дольше уворачиваться от метеоритов, летающих во всех стороны.

Но вот только для этой игры метеоритов нам понадобится много, а заводить отдельную четверку переменных для каждого из десятка метеоритов — неудобно. Хорошо бы как-то хранить их в одном месте. И так правда можно, для этого используются списки.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *