Это старая версия документа!


Эксперимент 55. Игровая логика. "Сокобан"

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

Схема эксперимента

Схема эксперимента не изменилась.

Рисунок 1. Монтажная схема эксперимента

Программный код эксперимента

Exp55.py
  1. from machine import Pin, SPI
  2. from tft import TFT_GREEN
  3. _init()
  4. machine.freq(160000000)
  5.  
  6. dc = Pin(4, Pin.OUT)
  7. cs = Pin(2, Pin.OUT)
  8. rst = Pin(5, Pin.OUT)
  9. spi = SPI(1, baudrate=40000000, polarity=0, phase=0)
  10.  
  11. tft = TFT_GREEN(128, 160, spi, dc, cs, rst, rotate=0)
  12.  
  13. Map = [
  14. [1,1,0,1,1,1,0,1],
  15. [0,1,1,1,1,1,1,0],
  16. [1,1,0,0,0,1,1,1],
  17. [0,1,0,1,0,1,0,1],
  18. [0,1,0,0,0,1,0,1],
  19. [1,1,1,1,0,0,0,1],
  20. [1,0,0,0,0,0,0,1],
  21. [1,0,0,0,1,0,0,1],
  22. [1,0,0,0,1,1,1,1],
  23. [1,1,1,1,1,0,0,0]
  24. ]
  25.  
  26. Gates = []
  27. Boxes = []
  28.  
  29. class Box:
  30. def __init__(self, tft, x, y):
  31. self.tft = tft
  32. self.x = x
  33. self.y = y
  34. self.picture = 'box.bmp'
  35. self.picture_onGate = 'boxngate.bmp'
  36. self.onGate = False
  37. self.draw()
  38.  
  39. def draw(self):
  40. if (self.onGate):
  41. self.tft.draw_bmp(self.x * 16,self.y * 16, self.picture_onGate)
  42. else:
  43. self.tft.draw_bmp(self.x * 16,self.y * 16, self.picture)
  44.  
  45. def setOnGate(self, state):
  46. self.onGate = state
  47.  
  48. def getOnGate(self):
  49. return self.onGate
  50.  
  51. def getPos(self):
  52. return (self.x, self.y)
  53.  
  54. def setPos(self, x, y):
  55. self.x = x
  56. self.y = y
  57. self.draw()
  58.  
  59. class Gate:
  60. def __init__(self, tft, x, y):
  61. self.tft = tft
  62. self.x = x
  63. self.y = y
  64. self.picture = 'gate.bmp'
  65. self.draw()
  66.  
  67. def draw(self):
  68. self.tft.draw_bmp(self.x * 16,self.y * 16, self.picture)
  69.  
  70. def getPos(self):
  71. return (self.x, self.y)
  72.  
  73. class Man:
  74. def __init__(self, tft, x, y):
  75. self.tft = tft
  76. self.x = x
  77. self.y = y
  78. self.picture = 'man.bmp'
  79. self.draw()
  80.  
  81. def draw(self):
  82. self.tft.draw_bmp(self.x * 16,self.y * 16, self.picture)
  83.  
  84. def getPos(self):
  85. return (self.x, self.y)
  86.  
  87. def setPos(self, x, y):
  88. self.tft.rect(self.x * 16, self.y * 16, 16, 16, tft.COLOR_BLACK)
  89. self.x = x
  90. self.y = y
  91. self.draw()
  92.  
  93. class Button:
  94. def __init__(self, p, pressSate):
  95. self.pin = Pin(p, Pin.IN)
  96. self.pressSate = pressSate
  97. self.oldState = 0
  98.  
  99. def onPress(self):
  100. state = self.pin.value()
  101. if state != self.oldState:
  102. self.oldState = state
  103. if state == self.pressSate:
  104. return True
  105. return False
  106.  
  107. tft.initr()
  108. tft.clear(tft.COLOR_BLACK)
  109.  
  110. x = 0
  111. y = 0
  112.  
  113. for row in Map:
  114. for col in row:
  115. if col:
  116. tft.draw_bmp(x * 16, y * 16,'brick.bmp')
  117. x+=1
  118. x=0
  119. y+=1
  120.  
  121. Boxes.append(Box(tft, 3,4))
  122. Boxes.append(Box(tft, 4,6))
  123. Boxes.append(Box(tft, 2,7))
  124.  
  125. Gates.append(Gate(tft, 6,3))
  126. Gates.append(Gate(tft, 6,4))
  127. Gates.append(Gate(tft, 6,5))
  128.  
  129. man = Man(tft, 5, 6)
  130.  
  131. btnUp = Button(16, 1)
  132. btnDown = Button(15, 1)
  133. btnLeft = Button(12, 1)
  134. btnRight = Button(0, 0)
  135.  
  136. def canMove(x,y):
  137. if (Map[y][x]):
  138. return False
  139. else:
  140. return True
  141.  
  142. def feelBox(x,y):
  143. for B in Boxes:
  144. if B.getPos() == (x,y):
  145. return B
  146. return False
  147.  
  148. def boxFeelGate(x,y):
  149. for G in Gates:
  150. if G.getPos() == (x,y):
  151. return True
  152. return False
  153.  
  154. while True:
  155. mPos = man.getPos()
  156. newPos = (-1,-1)
  157.  
  158. if btnUp.onPress():
  159. newPos = (mPos[0], mPos[1]-1)
  160. newPosNext = (mPos[0], mPos[1]-2)
  161.  
  162. if btnDown.onPress():
  163. newPos = (mPos[0], mPos[1]+1)
  164. newPosNext = (mPos[0], mPos[1]+2)
  165.  
  166. if btnLeft.onPress():
  167. newPos = (mPos[0]-1, mPos[1])
  168. newPosNext = (mPos[0]-2, mPos[1])
  169.  
  170. if btnRight.onPress():
  171. newPos = (mPos[0]+1, mPos[1])
  172. newPosNext = (mPos[0]+2, mPos[1])
  173.  
  174. if newPos != (-1,-1):
  175. B = feelBox(newPos[0], newPos[1])
  176. if B and canMove(newPosNext[0], newPosNext[1]):
  177. if boxFeelGate(newPosNext[0], newPosNext[1]):
  178. B.setOnGate(True)
  179. else:
  180. B.setOnGate(False)
  181. B.setPos(newPosNext[0], newPosNext[1])
  182. man.setPos(newPos[0], newPos[1])
  183. if not B and canMove(newPos[0], newPos[1]):
  184. man.setPos(newPos[0], newPos[1])
  185.  
  186. for G in Gates:
  187. gPos = G.getPos()
  188. if not (feelBox(gPos[0], gPos[1])) and gPos != man.getPos():
  189. G.draw()
  190.  
  191. win = 1
  192. for B in Boxes:
  193. if (not B.getOnGate()):
  194. win = 0
  195. break
  196.  
  197. if (win):
  198. tft.draw_bmp(0, 16, 'win.bmp')
  199. raise SystemExit