def obstacleAvoid(self, obstacles):
		self.avoidance = v2.vector2(0,0)
		tv = self.velocity
		tv.norm()
		tv = tv * MAXAVOIDAHEAD
		ahead = self.position + tv
		mostThreatening = None
		
		for i in range(len(obstacles)):
			obstacle = obstacles[i]
			
			if((obstacle.pos - self.position).mag()>96):
				continue
			else:
				if(kd.debug):
					PKFW.drln(self.position.x, self.position.y, obstacle.pos.x, obstacle.pos.y, 0,0,1)
				
			coll = self.lineIntersection(self.position, ahead, obstacle)
			if(coll and ((mostThreatening is None) or (self.position.distance(obstacle.pos) < self.position.distance(mostThreatening.pos)))):
				mostThreatening = obstacle
		
		if(mostThreatening is not None):
			self.avoidance = ahead - mostThreatening.pos
			self.avoidance.norm()
			self.avoidance = self.avoidance * AVOIDFOR
		else:
			self.wander()
	def update(self):
	
		self.steering = self.mintrunc(self.steering + self.avoidance, MAXFOR)
		self.steering = self.steering / self.mass
		self.velocity = self.maxtrunc(self.velocity + self.steering, MAXSPD)
		
		self.position = self.position + self.velocity
	
		if(self.position.x < 0):self.position.x = kd.sp['width']
		if(self.position.x > kd.sp['width']):self.position.x = 0
		if(self.position.y < 0):self.position.y = kd.sp['height'] 
		if(self.position.y > kd.sp['height']):self.position.y = 0
		
		PKFW.spmo(self.sprite,self.position.x, self.position.y)
	def LevelGridDraw(self):
		for x in range(len(self.levelTiles)):
			for y in range(len(self.levelTiles[x])):
				if(self.levelTiles[x][y].Sid != -1):
					PKFW.spmo(self.levelTiles[x][y].Sid,self.levelTiles[x][y].pos.x, self.levelTiles[x][y].pos.y )
					PKFW.spdr(self.levelTiles[x][y].Sid)	
		
		for i in range(len(self.wanderers)):
			self.wanderers[i].obstacleAvoid(walls)
			self.wanderers[i].update()
			self.wanderers[i].draw()
			if(math.isnan(self.wanderers[i].position.x) or math.isnan(self.wanderers[i].position.y)):
				# on rare occasions the boid position and steering becomes NAN due to being too close to too many 
				# walls... I am not sure why this is happening and have implemented a half fix which just
				# re initialises the boid if this happens
				self.wanderers[i] = ai.boid(kd.sp['width']*0.5, kd.sp['height']*0.5, 64, sprites[5])
		
		if(self.flock is not None):
			self.flock.update()
	def __init__(self, tileSize):
		reload(pathfinding)
		reload(ai)
		reload(v2)
		reload(kd)
		
		#sprites['tileSID'] = PKFW.spcr("./images/grey.png", tileSize['width'], tileSize['height'])
		#sprites['startSID'] = PKFW.spcr("./images/blue.png", tileSize['width'], tileSize['height'])
		#sprites['finishSID'] = PKFW.spcr("./images/green.png", tileSize['width'], tileSize['height'])
		#sprites['wallSID'] = PKFW.spcr("./images/red.png", tileSize['width'], tileSize['height'])
		#sprites['pathSID'] = PKFW.spcr("./images/purple.png",tileSize['width'], tileSize['height'])
		#sprites['boidSID'] = PKFW.spcr("./images/reds.png", 32,32)
		sprites.append(PKFW.spcr("./images/grey.png", tileSize['width'], tileSize['height']))
		sprites.append(PKFW.spcr("./images/blue.png", tileSize['width'], tileSize['height']))
		sprites.append(PKFW.spcr("./images/green.png", tileSize['width'], tileSize['height']))
		sprites.append(PKFW.spcr("./images/red.png", tileSize['width'], tileSize['height']))
		sprites.append(PKFW.spcr("./images/purple.png",tileSize['width'], tileSize['height']))
		sprites.append(PKFW.spcr("./images/reds.png", 32,32))
		
		self.wanderers = []
		self.flock = None
		self.path = None
		
		self.buttonpressed = [False]*5
		self.screenProps = kd.sp
		self.tileSize = tileSize
		self.levelSize = {'x':self.screenProps['width']/self.tileSize['width'], 'y':self.screenProps['height']/self.tileSize['height']}
		self.levelTiles = [[None]*self.levelSize['y'] for i in range(self.levelSize['x'])]
		
		#initialising levelTiles grid with new tiles
		#small random portion of tiles set to walls 
		#outer edges of tiles set to wall (not needed but included to avoid boid boundries)
		for x in range(len(self.levelTiles)):
			for y in range(len(self.levelTiles[x])):
				self.levelTiles[x][y] = Tile()
				if(random.random()>0.20) or ((x>10 and x<14) and (y>4 and y<9)):
					self.levelTiles[x][y].setS(sprites[0])
				else:		
					self.levelTiles[x][y].setS(sprites[3])
					
				self.levelTiles[x][y].pos.x = (self.tileSize['width']) * x%self.screenProps['width']+ (tileSize['width']*0.5)
				self.levelTiles[x][y].pos.y = (self.tileSize['height']) * y%self.screenProps['height']+ (tileSize['width']*0.5)
				self.levelTiles[x][y].gpos['x'] = x
				self.levelTiles[x][y].gpos['y'] = y
				if(not x or not y) or (x is self.levelSize['x']-1 or y is self.levelSize['y']-1):
					self.levelTiles[x][y].setS(sprites[3])
		
		#initialising 10 boid wanderers 
		for i in range(10):
			rx = random.randint(kd.sp['width']*0.5-64,kd.sp['width']*0.5+64)
			ry = random.randint(kd.sp['height']*0.5-72,kd.sp['height']*0.5+72)
			self.wanderers.append(ai.boid(rx, ry, 32, sprites[5]))
	def lineIntersection(self, pos, ahead, obstacle):
		tv = self.velocity
		tv.norm()
		tv = tv * MAXAVOIDAHEAD * 0.75
		
		ahead2 = self.position + tv
		if(kd.debug):
			PKFW.drln(self.position.x, self.position.y, ahead.x, ahead.y, 1,0,1)
			PKFW.drln(self.position.x, self.position.y, ahead2.x, ahead2.y, 1,1,0)
		n = 52
		if(kd.debug):
			for t in range(n)[::3]:
				th = 2* math.pi * t/n
				th1 = 2* math.pi * (t+1)/n
				v = v2.vector2(n*math.cos(th), n*math.sin(th))
				v1 = v2.vector2(n*math.cos(th1), n*math.sin(th1))
				if(obstacle.gpos['x']>0 and obstacle.gpos['y']>0):
					PKFW.drln(obstacle.pos.x+v.x, obstacle.pos.y+v.y, obstacle.pos.x+v1.x, obstacle.pos.y+v1.y, 1,1,1)
		return (obstacle.pos.distance(ahead)<=n) or (obstacle.pos.distance(ahead2)<=n)
	def draw(self):
		PKFW.spdr(self.sprite)
def GameInit():#initialise game and globals
	PKFW.init(kd.sp['width'], kd.sp['height'])
	LevelGridInit()
def GameUpdate():#main game loop 
	PKFW.upda()
	global tilegrid
	tilegrid.LevelGridUpdate()
	tilegrid.LevelGridDraw()
	def LevelGridUpdate(self):
		mx, my = PKFW.gtmp() #mouse x and y
		tx = int(mx/self.tileSize['width'])
		ty = int(my/self.tileSize['height'])	#current tile mouse is over

		if(tx<0):tx=0
		if(ty<0):ty=0
		if(tx>self.levelSize['x']-1):
			tx = self.levelSize['x']-1
		if(ty>self.levelSize['y']-1):
			ty = self.levelSize['y']-1	#current tile mouse is over window clamp	
				

		#left mouse button sets tile to start
		#right mouse button sets tile to wall
		#middle mouse button sets tile to blank				
		if(PKFW.gmpr(0) and self.buttonpressed[0] is False):
			self.buttonpressed[0] = True
			self.levelTiles[tx][ty].setS(sprites[1])
		self.buttonpressed[0] = not PKFW.gtmr(0)
		if(PKFW.gmpr(1)):
			self.levelTiles[tx][ty].setS(sprites[3])
		if(PKFW.gmpr(2)):
			self.levelTiles[tx][ty].setS(sprites[0])
		

		#if the start exists and there is only one finish and the 'a' key is pressed
		#astar runs and sets the tiles in the returned path to the path sprite	
		if isinstance(start, Tile) and len(finish)==1 and PKFW.gtkp(65) and self.buttonpressed[1] is False: 
			self.buttonpressed[1] = True
			self.path = pathfinding.astar(start, finish[0], self.levelTiles, self.levelSize)
			if(isinstance(self.path, list)):
				for i in range(len(self.path)):
					self.path[i].setS(sprites[4])
		self.buttonpressed[1] = not PKFW.gtkr(65)
		
		#if the start exists and there is at least 1 finish and the 'd' key is pressed
		#dijkstra runs (path tiles sprite set to path)
		if isinstance(start, Tile) and len(finish)>0 and PKFW.gtkp(68) and self.buttonpressed[2] is False:
			self.buttonpressed[2] = True
			self.path = pathfinding.dijkstra(start, finish, self.levelTiles, self.levelSize)
			if(isinstance(self.path,list)):
				for i in range(len(self.path)):
					self.path[i].setS(sprites[4])
		self.buttonpressed[2] = not PKFW.gtkr(68)

		#checks if path is a list
		#if so then delete all the elements and set to None
		#in case previous tiles from previous paths are left over when attempting new path
		
		if(isinstance(self.path,list)):
			for i in range(len(self.path)):
				self.path[i].resetTile()
			del self.path[:]
			self.path = None
			
		
		#when the 'c' button is pressed all the tiles that are not walls are set to blank tiles
		if(PKFW.gtkp(67)):
			for x in range(len(self.levelTiles)):
				for y in range(len(self.levelTiles[x])):
					if(self.levelTiles[x][y].Sid != sprites[3]):
						self.levelTiles[x][y].resetTile()
						self.levelTiles[x][y].setS(sprites[0])


		#the f1 button clears all the wanderes and tiles and initialises the flock class
		#to return to the wanderers and tiles press ESC
		if(PKFW.gtkp(kd.keys['F1']) and self.buttonpressed[3] is False):
			self.buttonpressed[3] = True
			self.flock = ai.flock(30, sprites[5])
			for i in range (len(self.wanderers)):
				del self.wanderers[:]
			for x in range(len(self.levelTiles)):
				for y in range(len(self.levelTiles[x])):
					self.levelTiles[x][y].setS(sprites[0])
		self.buttonpressed[3] = not PKFW.gtkr(kd.keys['F1'])


		#pressing f12 sets debug to !debug
		#used when creating boid steering behaviours
		if(PKFW.gtkp(kd.keys['F12']) and self.buttonpressed[4] is False):
			self.buttonpressed[4] = True
			kd.debug = not kd.debug
		self.buttonpressed[4] = not PKFW.gtkr(kd.keys['F12'])
	def cs(self):
		global sprites
		PKFW.spde(sprites[0])
		PKFW.spde(sprites[1])
		PKFW.spde(sprites[2])
		PKFW.spde(sprites[3])
		PKFW.spde(sprites[4])
		PKFW.spde(sprites[5])
		
		del sprites[:]