123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279 |
- #
- # 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
|