TanksField.py 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279
  1. #
  2. # TanksField.py
  3. #
  4. # Field for tanks game
  5. #
  6. import math as Math
  7. import itertools
  8. from PlayerTank import PlayerTank
  9. from AITank import AITank
  10. from Level import Level
  11. from Bullet import Bullet
  12. class TanksField:
  13. def __init__(self, canvas, nrtanks = 1):
  14. self.canvas = canvas
  15. self.bullets = []
  16. self.bulletSpeed = 10
  17. self.tanks = []
  18. self.tanks_map = {}
  19. self.width = int(self.canvas['width'])
  20. self.height = int(self.canvas['height'])
  21. self.createLevel()
  22. self.createTanks(nrtanks)
  23. self.level_running = True
  24. def createLevel(self):
  25. self.level = Level(self)
  26. self.level.addObstacles([(2,3),(3,2),(3,3),(3,4),(3,5),(4,1),(4,2),(4,3),(4,4),(5,2),
  27. (7,7),(8,7),(9,7),(7,8),(8,8),(9,8),(7,9),(8,9),(8,10),(9,9),(9,10),(9,11),(10,8),(10,9),(10,10),(10,11),(11,9),(11,10),(11,11),
  28. (11,0),(12,0),(12,1),(13,0),(13,1),(13,2),(13,3),(14,0),(14,1),(14,2),(14,3),(15,0),(15,1),(15,2),(16,0),(16,1),(16,2),(17,0),(17,1),(18,0),(19,0),(19,1),
  29. (17,7),(17,8),(16,6),(16,7),(16,8),(15,8),(15,9)])
  30. def createTanks(self,nrtanks):
  31. self.team_counts = [0,0]
  32. data = {}
  33. #Controlled player
  34. data["tankLength"] = 20
  35. data["tankWidth"] = 14
  36. data["cannonLength"] = 20
  37. data["cannonFront"] = 3
  38. data["cannonBack"] = 8
  39. data["x"] = 30
  40. data["y"] = 30
  41. data["angle"] = Math.pi*1.75
  42. data["moveSpeed"] = 3
  43. data["rotateSpeed"] = 3
  44. data["cannonSpeed"] = 4
  45. data["health"] = 80
  46. data["damage"] = 10
  47. data["reloadTime"] = 0.5
  48. data["team"] = 0
  49. data['color-fill'] = "DarkOliveGreen4"
  50. self.player = PlayerTank(self, data)
  51. self.tanks.append(self.player)
  52. self.tanks_map[self.player.getImage()] = self.player
  53. self.team_counts[data["team"]] += 1
  54. #AI
  55. if nrtanks != 0 :
  56. #1
  57. data["x"] = self.width - 30
  58. data["y"] = self.height - 30
  59. data["angle"] = Math.pi*0.75
  60. data["team"] = 1
  61. data['color-fill'] = "cornsilk4"
  62. enemy = AITank(self, data)
  63. self.tanks.append(enemy)
  64. self.tanks_map[enemy.getImage()] = enemy
  65. self.team_counts[data["team"]] += 1
  66. if nrtanks > 1 :
  67. #2
  68. data["x"] = self.width - 75
  69. data["y"] = 75
  70. data["angle"] = 3*Math.pi/2
  71. enemy = AITank(self, data)
  72. self.tanks.append(enemy)
  73. self.tanks_map[enemy.getImage()] = enemy
  74. self.team_2_count += 1
  75. self.team_counts[data["team"]] += 1
  76. #End
  77. self.canvas.tag_raise("cannon")
  78. self.canvas.tag_raise("health")
  79. def update(self, delta):
  80. for tank in self.tanks: tank.update(delta)
  81. for bullet in self.bullets: bullet.update()
  82. self.tankCollision()
  83. self.bulletCollision()
  84. for tank in self.tanks : tank.draw()
  85. for bullet in self.bullets: bullet.draw()
  86. #check if game over
  87. if self.level_running :
  88. for c in self.team_counts :
  89. if c == 0 :
  90. self.level_running = False
  91. def addBullet(self, x, y, team, direction, damage, radius):
  92. self.bullets.append(Bullet(x, y, team, self.bulletSpeed, direction, damage, radius, self.canvas))
  93. def bulletCollision(self):
  94. for bullet in self.bullets :
  95. x = bullet.getX()
  96. y = bullet.getY()
  97. radius = bullet.getRadius()
  98. hits = self.canvas.find_overlapping(x-radius,y-radius,x+radius,y+radius)
  99. for hit in hits:
  100. if "tank" in self.canvas.gettags(hit) :
  101. if self.tanks_map[hit].getTeam() != bullet.getTeam() :
  102. if self.tanks_map[hit].doDamage(bullet.getDamage()) :
  103. dead_tank = self.tanks_map.pop(hit)
  104. self.team_counts[dead_tank.team] -= 1
  105. self.tanks.remove(dead_tank)
  106. bullet.destroy()
  107. if "obstacle" in self.canvas.gettags(hit) :
  108. bullet.destroy()
  109. if (x > self.width) or (x < 0) or (y > self.height) or (y < 0) :
  110. bullet.destroy()
  111. self.bullets[:] = [bullet for bullet in self.bullets if not bullet.getExploded()]
  112. def tankCollision(self):
  113. #between tanks
  114. for (tank_a,tank_b) in itertools.combinations(self.tanks,2) :
  115. result = self.collisionBetweenRectangles(tank_a, tank_b)
  116. if result : #There is a collision
  117. (smallestOverlap,axis) = result
  118. direction = (tank_b.getX() - tank_a.getX(), tank_b.getY() - tank_a.getY())
  119. #check the direction of the axis between the tank and the object
  120. if (axis[0] * direction[0] + axis[1] * direction[1]) > 0 : #If not pointing the right way, invert (MTV rectangles)
  121. axis = (-axis[0],-axis[1])
  122. correct_xoffset = Math.ceil((axis[0] * smallestOverlap) / 2.0)
  123. correct_yoffset = Math.ceil((axis[1] * smallestOverlap) / 2.0)
  124. tank_a.moveTank(correct_xoffset, correct_yoffset)
  125. for tank in self.tanks :
  126. corrections = []
  127. #between tank and obstacles
  128. for obstacle in self.level.obstacles :
  129. result = self.collisionBetweenRectangles(tank, obstacle)
  130. if result : #There is a collision
  131. (smallestOverlap,axis) = result
  132. direction = (obstacle.getX() - tank.getX(), obstacle.getY() - tank.getY())
  133. #check the direction of the axis between the tank and the object
  134. if (axis[0] * direction[0] + axis[1] * direction[1]) > 0 : #If not pointing the right way, invert (MTV rectangles)
  135. axis = (-axis[0],-axis[1])
  136. correct_xoffset = (axis[0] * smallestOverlap)
  137. correct_yoffset = (axis[1] * smallestOverlap)
  138. corrections.append((correct_xoffset, correct_yoffset))
  139. #between tanks and borders
  140. corrections.extend(self.checkBoundaryMove(tank))
  141. xCor = 0
  142. yCor = 0
  143. for (x,y) in corrections :
  144. xCor += x
  145. yCor += y
  146. tank.moveTank(xCor, yCor)
  147. def checkBoundaryMove(self,tank) :
  148. corrections = []
  149. for (x,y) in tank.getCoords() :
  150. if (x > self.width) :
  151. corrections.append((self.width-x,0))
  152. if (x < 0) :
  153. corrections.append((0-x,0))
  154. if (y > self.height) :
  155. corrections.append((0,self.height-y))
  156. if (y < 0) :
  157. corrections.append((0,0-y))
  158. return corrections
  159. def collisionBetweenRectangles(self,rec1,rec2):
  160. smallestOverlap = 0
  161. axis = (0,0)
  162. r1 = rec1.getRadius()
  163. r2 = rec2.getRadius()
  164. x1 = rec1.getX()
  165. x2 = rec2.getX()
  166. y1 = rec1.getY()
  167. y2 = rec2.getY()
  168. dsqrd = (y2-y1) * (y2-y1) + (x2-x1) * (x2-x1)
  169. if (dsqrd < (r1+r2)*(r1+r2)) :
  170. smallestOverlap = 10000
  171. coords1 = rec1.getCoords()
  172. coords2 = rec2.getCoords()
  173. axiss = [(coords1[1][0] - coords1[0][0],coords1[1][1] - coords1[0][1]),(coords1[1][0] - coords1[2][0],coords1[1][1] - coords1[2][1]),
  174. (coords2[0][0] - coords2[3][0], coords2[0][1] - coords2[3][1]), ( coords2[0][0] - coords2[1][0], coords2[0][1] - coords2[1][1])]
  175. for (x,y) in axiss :
  176. rec1projected=[]
  177. rec2projected=[]
  178. xn = x/Math.sqrt(x*x+y*y)
  179. yn = y/Math.sqrt(x*x+y*y)
  180. for point in range(4) :
  181. rec1projected.append((xn*coords1[point][0]) + (yn*coords1[point][1]))
  182. for point in range(4) :
  183. rec2projected.append((xn*coords2[point][0]) + (yn*coords2[point][1]))
  184. maxrec1 = max(rec1projected)
  185. minrec1 = min(rec1projected)
  186. maxrec2 = max(rec2projected)
  187. minrec2 = min(rec2projected)
  188. if minrec1 < minrec2 :
  189. overlap = maxrec1 - minrec2
  190. else :
  191. overlap = maxrec2 - minrec1
  192. if overlap > 0 :
  193. if (overlap < smallestOverlap ) :
  194. smallestOverlap = overlap
  195. axis = (xn,yn)
  196. continue
  197. return False
  198. return (smallestOverlap,axis)
  199. return False
  200. def getSightedEnemies(self, tank, range = -1):
  201. xpos2 = tank.getX()
  202. ypos2 = tank.getY()
  203. in_range = []
  204. for enemy in self.tanks :
  205. if tank.getTeam() != enemy.getTeam() :
  206. xpos1 = enemy.getX()
  207. ypos1 = enemy.getY()
  208. distance = ( (xpos1 - xpos2) ** 2 + (ypos1 - ypos2) ** 2 ) ** 0.5
  209. if range < 0 or range > distance :
  210. sighted = True
  211. for obstacle in self.level.obstacles :
  212. if lineIntersectsObstacle(xpos1,ypos1,xpos2,ypos2,obstacle) :
  213. sighted = False
  214. continue
  215. if sighted : in_range.append(((xpos1,ypos1),distance))
  216. return in_range
  217. def lineIntersectsObstacle(xpos1,ypos1,xpos2,ypos2,obstacle) :
  218. width = obstacle.getWidth()
  219. halfwidth = width/2
  220. left = obstacle.getX()- halfwidth
  221. top = obstacle.getY() - halfwidth
  222. height = width
  223. minX = xpos1
  224. maxX = xpos2
  225. if xpos1 > xpos2 :
  226. minX = xpos2
  227. maxX = xpos1
  228. if maxX > (left + width) : maxX = left + width
  229. if minX < left : minX = left
  230. if minX > maxX : return False
  231. minY = ypos1
  232. maxY = ypos2
  233. dx = xpos2 - xpos1
  234. if Math.fabs(dx) > 0.0000001 :
  235. a = (ypos2 - ypos1) / dx
  236. b = ypos1 - a * xpos1
  237. minY = a * minX + b
  238. maxY = a * maxX + b
  239. if minY > maxY :
  240. tmp = maxY
  241. maxY = minY
  242. minY = tmp
  243. if maxY > (top + height) : maxY = top + height
  244. if minY < top : minY = top
  245. if minY > maxY : return False
  246. return True