# # TanksField.py # # Field for tanks game # import math as Math import itertools from PlayerTank import PlayerTank from AITank import AITank from Level import Level from Bullet import Bullet class TanksField: def __init__(self, canvas, nrtanks = 1): self.canvas = canvas self.bullets = [] self.bulletSpeed = 10 self.tanks = [] self.tanks_map = {} self.width = int(self.canvas['width']) self.height = int(self.canvas['height']) self.createLevel() self.createTanks(nrtanks) self.level_running = True def createLevel(self): self.level = Level(self) self.level.addObstacles([(2,3),(3,2),(3,3),(3,4),(3,5),(4,1),(4,2),(4,3),(4,4),(5,2), (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), (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), (17,7),(17,8),(16,6),(16,7),(16,8),(15,8),(15,9)]) def createTanks(self,nrtanks): self.team_counts = [0,0] data = {} #Controlled player data["tankLength"] = 20 data["tankWidth"] = 14 data["cannonLength"] = 20 data["cannonFront"] = 3 data["cannonBack"] = 8 data["x"] = 30 data["y"] = 30 data["angle"] = Math.pi*1.75 data["moveSpeed"] = 3 data["rotateSpeed"] = 3 data["cannonSpeed"] = 4 data["health"] = 80 data["damage"] = 10 data["reloadTime"] = 0.5 data["team"] = 0 data['color-fill'] = "DarkOliveGreen4" self.player = PlayerTank(self, data) self.tanks.append(self.player) self.tanks_map[self.player.getImage()] = self.player self.team_counts[data["team"]] += 1 #AI if nrtanks != 0 : #1 data["x"] = self.width - 30 data["y"] = self.height - 30 data["angle"] = Math.pi*0.75 data["team"] = 1 data['color-fill'] = "cornsilk4" enemy = AITank(self, data) self.tanks.append(enemy) self.tanks_map[enemy.getImage()] = enemy self.team_counts[data["team"]] += 1 if nrtanks > 1 : #2 data["x"] = self.width - 75 data["y"] = 75 data["angle"] = 3*Math.pi/2 enemy = AITank(self, data) self.tanks.append(enemy) self.tanks_map[enemy.getImage()] = enemy self.team_2_count += 1 self.team_counts[data["team"]] += 1 #End self.canvas.tag_raise("cannon") self.canvas.tag_raise("health") def update(self, delta): for tank in self.tanks: tank.update(delta) for bullet in self.bullets: bullet.update() self.tankCollision() self.bulletCollision() for tank in self.tanks : tank.draw() for bullet in self.bullets: bullet.draw() #check if game over if self.level_running : for c in self.team_counts : if c == 0 : self.level_running = False def addBullet(self, x, y, team, direction, damage, radius): self.bullets.append(Bullet(x, y, team, self.bulletSpeed, direction, damage, radius, self.canvas)) def bulletCollision(self): for bullet in self.bullets : x = bullet.getX() y = bullet.getY() radius = bullet.getRadius() hits = self.canvas.find_overlapping(x-radius,y-radius,x+radius,y+radius) for hit in hits: if "tank" in self.canvas.gettags(hit) : if self.tanks_map[hit].getTeam() != bullet.getTeam() : if self.tanks_map[hit].doDamage(bullet.getDamage()) : dead_tank = self.tanks_map.pop(hit) self.team_counts[dead_tank.team] -= 1 self.tanks.remove(dead_tank) bullet.destroy() if "obstacle" in self.canvas.gettags(hit) : bullet.destroy() if (x > self.width) or (x < 0) or (y > self.height) or (y < 0) : bullet.destroy() self.bullets[:] = [bullet for bullet in self.bullets if not bullet.getExploded()] def tankCollision(self): #between tanks for (tank_a,tank_b) in itertools.combinations(self.tanks,2) : result = self.collisionBetweenRectangles(tank_a, tank_b) if result : #There is a collision (smallestOverlap,axis) = result direction = (tank_b.getX() - tank_a.getX(), tank_b.getY() - tank_a.getY()) #check the direction of the axis between the tank and the object if (axis[0] * direction[0] + axis[1] * direction[1]) > 0 : #If not pointing the right way, invert (MTV rectangles) axis = (-axis[0],-axis[1]) correct_xoffset = Math.ceil((axis[0] * smallestOverlap) / 2.0) correct_yoffset = Math.ceil((axis[1] * smallestOverlap) / 2.0) tank_a.moveTank(correct_xoffset, correct_yoffset) for tank in self.tanks : corrections = [] #between tank and obstacles for obstacle in self.level.obstacles : result = self.collisionBetweenRectangles(tank, obstacle) if result : #There is a collision (smallestOverlap,axis) = result direction = (obstacle.getX() - tank.getX(), obstacle.getY() - tank.getY()) #check the direction of the axis between the tank and the object if (axis[0] * direction[0] + axis[1] * direction[1]) > 0 : #If not pointing the right way, invert (MTV rectangles) axis = (-axis[0],-axis[1]) correct_xoffset = (axis[0] * smallestOverlap) correct_yoffset = (axis[1] * smallestOverlap) corrections.append((correct_xoffset, correct_yoffset)) #between tanks and borders corrections.extend(self.checkBoundaryMove(tank)) xCor = 0 yCor = 0 for (x,y) in corrections : xCor += x yCor += y tank.moveTank(xCor, yCor) def checkBoundaryMove(self,tank) : corrections = [] for (x,y) in tank.getCoords() : if (x > self.width) : corrections.append((self.width-x,0)) if (x < 0) : corrections.append((0-x,0)) if (y > self.height) : corrections.append((0,self.height-y)) if (y < 0) : corrections.append((0,0-y)) return corrections def collisionBetweenRectangles(self,rec1,rec2): smallestOverlap = 0 axis = (0,0) r1 = rec1.getRadius() r2 = rec2.getRadius() x1 = rec1.getX() x2 = rec2.getX() y1 = rec1.getY() y2 = rec2.getY() dsqrd = (y2-y1) * (y2-y1) + (x2-x1) * (x2-x1) if (dsqrd < (r1+r2)*(r1+r2)) : smallestOverlap = 10000 coords1 = rec1.getCoords() coords2 = rec2.getCoords() 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]), (coords2[0][0] - coords2[3][0], coords2[0][1] - coords2[3][1]), ( coords2[0][0] - coords2[1][0], coords2[0][1] - coords2[1][1])] for (x,y) in axiss : rec1projected=[] rec2projected=[] xn = x/Math.sqrt(x*x+y*y) yn = y/Math.sqrt(x*x+y*y) for point in range(4) : rec1projected.append((xn*coords1[point][0]) + (yn*coords1[point][1])) for point in range(4) : rec2projected.append((xn*coords2[point][0]) + (yn*coords2[point][1])) maxrec1 = max(rec1projected) minrec1 = min(rec1projected) maxrec2 = max(rec2projected) minrec2 = min(rec2projected) if minrec1 < minrec2 : overlap = maxrec1 - minrec2 else : overlap = maxrec2 - minrec1 if overlap > 0 : if (overlap < smallestOverlap ) : smallestOverlap = overlap axis = (xn,yn) continue return False return (smallestOverlap,axis) return False def getSightedEnemies(self, tank, range = -1): xpos2 = tank.getX() ypos2 = tank.getY() in_range = [] for enemy in self.tanks : if tank.getTeam() != enemy.getTeam() : xpos1 = enemy.getX() ypos1 = enemy.getY() distance = ( (xpos1 - xpos2) ** 2 + (ypos1 - ypos2) ** 2 ) ** 0.5 if range < 0 or range > distance : sighted = True for obstacle in self.level.obstacles : if lineIntersectsObstacle(xpos1,ypos1,xpos2,ypos2,obstacle) : sighted = False continue if sighted : in_range.append(((xpos1,ypos1),distance)) return in_range def lineIntersectsObstacle(xpos1,ypos1,xpos2,ypos2,obstacle) : width = obstacle.getWidth() halfwidth = width/2 left = obstacle.getX()- halfwidth top = obstacle.getY() - halfwidth height = width minX = xpos1 maxX = xpos2 if xpos1 > xpos2 : minX = xpos2 maxX = xpos1 if maxX > (left + width) : maxX = left + width if minX < left : minX = left if minX > maxX : return False minY = ypos1 maxY = ypos2 dx = xpos2 - xpos1 if Math.fabs(dx) > 0.0000001 : a = (ypos2 - ypos1) / dx b = ypos1 - a * xpos1 minY = a * minX + b maxY = a * maxX + b if minY > maxY : tmp = maxY maxY = minY minY = tmp if maxY > (top + height) : maxY = top + height if minY < top : minY = top if minY > maxY : return False return True