Различия

Показаны различия между двумя версиями страницы.

Ссылка на это сравнение

Предыдущая версия справа и слеваПредыдущая версия
Следующая версия
Предыдущая версия
products:laboratory_iot:exp53 [2020/06/11 21:15] labuser29products:laboratory_iot:exp53 [2024/12/13 20:01] (текущий) – [Эксперимент 53. Классы ящиков, человека и цели] labuser30
Строка 2: Строка 2:
  
 В прошлом эксперименте мы подключили TFT дисплей, создали игровую карту в виде двумерного массива и отобразили ее на экране. Теперь давайте поймем какие вообще объекты задействованы в игровом процессе. В прошлом эксперименте мы подключили TFT дисплей, создали игровую карту в виде двумерного массива и отобразили ее на экране. Теперь давайте поймем какие вообще объекты задействованы в игровом процессе.
-Как мы уже поняли, это стены, ящики, кладовщик и цели, куда нужно перетащить ящики.+Как мы уже поняли, это стены, ящики, кладовщик и цели, куда нужно перетащить ящики. Теперь нужно описать каждый из классов. 
 + 
 +=== Класс ящика === 
 +Начнем с класса ящика. Главные свойства ящика, это его координаты на карте и его состояние — находится он на цели или нет. 
 + 
 +<code python> 
 +class Box: 
 +    def __init__(self, tft, x, y): 
 +        self.tft = tft 
 +        self.x = x 
 +        self.y = y 
 +        self.picture = 'box.bmp' 
 +        self.picture_onGate = 'boxngate.bmp' 
 +        self.onGate = False 
 +        self.draw() 
 + 
 +    def draw(self): 
 +        if (self.onGate): 
 +            self.tft.draw_bmp(self.x * 16,self.y * 16,  self.picture_onGate) 
 +        else: 
 +            self.tft.draw_bmp(self.x * 16,self.y * 16, self.picture) 
 + 
 +    def setOnGate(self, state): 
 +        self.onGate = state 
 + 
 +    def getOnGate(self): 
 +        return self.onGate 
 + 
 +    def getPos(self): 
 +        return (self.x, self.y) 
 + 
 +    def setPos(self, x, y): 
 +        self.x = x 
 +        self.y = y 
 +        self.draw() 
 +</code> 
 + 
 +В конструктор мы передаем такие параметры как объект дисплея, координата x, координата y. Координата ящика указывается не в пикселях, а в клетках игрового поля. В самом конструкторе мы задаем имя спрайта для ящика на цели ''self.picture_onGate = 'boxngate.bmp''' и вне цели ''self.picture = 'box.bmp'''. Свойство ''onGate'' как раз описывает состояние ящика. В конце конструктор вызывает метод отрисовки ''draw''
 + 
 +Метод ''draw()'' предназначена для отрисовки ящика. Если ящик находится на цели, то функция отображает спрайт ''self.picture_onGate'', иначе ''self.picture''. Координата ящика указывается не в пикселях, а в клетках игрового поля, поэтому для отображения картинки ее необходимо пересчитать в пиксели. Для этого координата умножается на размер ящика в пикселях. 
 + 
 +Метод ''setOnGate()'' служит для установки свойства нахождения на цели. А метод ''getOnGate()'' для чтения этого свойства. 
 + 
 +Метод ''getPos'' возвращает текущие координаты ящика. А метод ''setPos'' устанавливает новые координаты ящика, после чего перерисовывает его на новом месте. 
 + 
 +=== Класс цели === 
 +Класс цели намного проще. Цель никуда не перемещается и свойств не имеет. Цель имеет только координаты и должна отображаться на экране с помощью своего спрайта. 
 + 
 +<code python> 
 +class Gate: 
 +    def __init__(self, tft, x, y): 
 +        self.tft = tft 
 +        self.x = x 
 +        self.y = y 
 +        self.picture = 'gate.bmp' 
 +        self.draw() 
 + 
 +    def draw(self): 
 +        self.tft.draw_bmp(self.x * 16,self.y * 16, self.picture) 
 + 
 +    def getPos(self): 
 +        return (self.x, self.y) 
 +</code> 
 + 
 +Метод ''draw()'' служит для отрисовки спрайта цели в заданных координатах. Так как координаты цели задаются не в пикселях, а в клетках поля, необходимо пересчитать их в пиксели для отображения. Поэтому координаты в клетках умножаются на размер клетки — 16. 
 + 
 +=== Класс кладовщика === 
 +Кладовщик также имеет координаты своего нахождения на поле и имеет свой спрайт. 
 + 
 +<code python> 
 +class Man: 
 +    def __init__(self, tft, x, y): 
 +        self.tft = tft 
 +        self.x = x 
 +        self.y = y 
 +        self.picture = 'man.bmp' 
 +        self.draw() 
 + 
 +    def draw(self): 
 +        self.tft.draw_bmp(self.x * 16,self.y * 16, self.picture) 
 + 
 +    def getPos(self): 
 +        return (self.x, self.y) 
 + 
 +    def setPos(self, x, y): 
 +        self.tft.rect(self.x * 16, self.y * 16, 16, 16, tft.COLOR_BLACK) 
 +        self.x = x 
 +        self.y = y 
 +        self.draw() 
 +</code> 
 + 
 +Конструктор и методы ''draw()'' и ''getPos()'' аналогичны одноименным методам предыдущих классов, поэтому не будем повторно заострять на них внимание. Небольшая разница есть в методе ''setPos()''. Отличие заключается в том, что при изменении координаты кладовщика на игровом поле, мы не только рисуем его в новом месте, но и стираем в предыдущем. Это делается с помощью рисования черного прямоугольника по старым координатам кладовщика. Если "старого" кладовщика не закрасить, то он никуда не исчезнет, а просто появится еще один в новом месте. Но почему же мы не закрашивали "старые" ящики при смене их координат? Потому что ящик изменяет координаты только когда его толкает кладовщик. И он сам оказывается на старом месте ящика и закрашивает его собой. 
 + 
 +Класса стен не будет. Мы будем пользоваться нашим двумерным массивом в котором уже описали план уровня. 
 + 
 +Теперь, когда мы имеем лабиринт и классы для ящика, кладовщика и цели, самое время отобразить это все на дисплее. 
 + 
 +==== Схема эксперимента ==== 
 +Схема не изменилась. 
 + 
 +{{ :products:esp-iot:exp26_mont.png?direct&600 |}} 
 +//Рисунок 1. Монтажная схема эксперимента с 8 выводами// 
 + 
 +{{ :products:esp-iot:exp26_mont_11pin.png?direct&600 |}} 
 + 
 +//Рисунок 2. Монтажная схема эксперимента с 11 выводами// 
 +==== Программный код эксперимента ==== 
 + 
 +<file python Exp53.py[enable_line_numbers="2", start_line_numbers_at="1"]> 
 +from machine import Pin, SPI 
 +from tft import TFT_GREEN 
 +_init() 
 +machine.freq(160000000) 
 + 
 + 
 +dc  = Pin(4, Pin.OUT) #a0 
 +cs  = Pin(2, Pin.OUT) 
 +rst = Pin(5, Pin.OUT) 
 +spi = SPI(1, baudrate=40000000, polarity=0, phase=0) 
 + 
 +# TFT object, this is ST7735R green tab version 
 +tft = TFT_GREEN(128, 160, spi, dc, cs, rst, rotate=0) 
 + 
 +Map = [ 
 +    [1,1,0,1,1,1,0,1], 
 +    [0,1,1,1,1,1,1,0], 
 +    [1,1,0,0,0,1,1,1], 
 +    [0,1,0,1,0,1,0,1], 
 +    [0,1,0,0,0,1,0,1], 
 +    [1,1,1,1,0,0,0,1], 
 +    [1,0,0,0,0,0,0,1], 
 +    [1,0,0,0,1,0,0,1], 
 +    [1,0,0,0,1,1,1,1], 
 +    [1,1,1,1,1,0,0,0] 
 +
 + 
 +Gates = [] 
 +Boxes = [] 
 + 
 +class Box: 
 +    def __init__(self, tft, x, y): 
 +        self.tft = tft 
 +        self.x = x 
 +        self.y = y 
 +        self.picture = 'box.bmp' 
 +        self.picture_onGate = 'boxngate.bmp' 
 +        self.onGate = False 
 +        self.draw() 
 + 
 +    def draw(self): 
 +        if (self.onGate): 
 +            self.tft.draw_bmp(self.x * 16,self.y * 16,  self.picture_onGate) 
 +        else: 
 +            self.tft.draw_bmp(self.x * 16,self.y * 16, self.picture) 
 + 
 +    def setOnGate(self, state): 
 +        self.onGate = state 
 + 
 +    def getOnGate(self): 
 +        return self.onGate 
 + 
 +    def getPos(self): 
 +        return (self.x, self.y) 
 + 
 +    def setPos(self, x, y): 
 +        self.x = x 
 +        self.y = y 
 +        self.draw() 
 + 
 +class Gate: 
 +    def __init__(self, tft, x, y): 
 +        self.tft = tft 
 +        self.x = x 
 +        self.y = y 
 +        self.picture = 'gate.bmp' 
 +        self.draw() 
 + 
 +    def draw(self): 
 +        self.tft.draw_bmp(self.x * 16,self.y * 16, self.picture) 
 + 
 +    def getPos(self): 
 +        return (self.x, self.y) 
 + 
 +class Man: 
 +    def __init__(self, tft, x, y): 
 +        self.tft = tft 
 +        self.x = x 
 +        self.y = y 
 +        self.picture = 'man.bmp' 
 +        self.draw() 
 + 
 +    def draw(self): 
 +        self.tft.draw_bmp(self.x * 16,self.y * 16, self.picture) 
 + 
 +    def getPos(self): 
 +        return (self.x, self.y) 
 + 
 +    def setPos(self, x, y): 
 +        self.tft.rect(self.x * 16, self.y * 16, 16, 16, tft.COLOR_BLACK) 
 +        self.x = x 
 +        self.y = y 
 +        self.draw() 
 + 
 +# init TFT 
 +tft.initr(tft.BGR) # tft.initr(tft.RGB) #Если вместо синего цвета отображается красный, а вместо красного синий 
 +tft.clear(tft.COLOR_BLACK) #b, g, r 
 + 
 +x = 0 
 +y = 0 
 + 
 +for row in Map: 
 +    for col in row: 
 +        if col: 
 +            tft.draw_bmp(x * 16, y * 16,'brick.bmp'
 +        x+=1 
 +    x=0 
 +    y+=1 
 + 
 +Boxes.append(Box(tft, 3,4)) 
 +Boxes.append(Box(tft, 4,6)) 
 +Boxes.append(Box(tft, 2,7)) 
 + 
 +Gates.append(Gate(tft, 6,3)) 
 +Gates.append(Gate(tft, 6,4)) 
 +Gates.append(Gate(tft, 6,5)) 
 + 
 +man = Man(tft, 5, 6) 
 +</file> 
 + 
 +Для хранения объектов целей и ящиков создаем массивы: 
 +<code python[enable_line_numbers="2", start_line_numbers_at="28"]> 
 +Gates = [] 
 +Boxes = [] 
 +</code> 
 + 
 +Создаем три объекта ящиков с координатами 3,4; 4,6 и 2,7: 
 +<code python[enable_line_numbers="2", start_line_numbers_at="110"]> 
 +Boxes.append(Box(tft, 3,4)) 
 +Boxes.append(Box(tft, 4,6)) 
 +Boxes.append(Box(tft, 2,7)) 
 +</code> 
 + 
 +Оператор ''append'' добавляет элементы в конец массива.  
 + 
 +Создаем объекты целей: 
 +<code python[enable_line_numbers="2", start_line_numbers_at="114"]> 
 +Gates.append(Gate(tft, 6,3)) 
 +Gates.append(Gate(tft, 6,4)) 
 +Gates.append(Gate(tft, 6,5)) 
 +</code> 
 + 
 +Создаем кладовщика: 
 +<code python[enable_line_numbers="2", start_line_numbers_at="118"]> 
 +man = Man(tft, 5, 6) 
 +</code> 
 + 
 +Теперь мы имеем игровое поле с лабиринтом, кладовщика, ящики и цели. В следующем эксперименте мы научим кладовщика двигаться при нажатиях на кнопки.