def update(self, dt): # print(dt) if self.paused or self.game_over: return adjust_x = self.parent.width * dt adjust_y = self.parent.height * dt # apply movement self.ball.x += self.vel.x * adjust_x self.ball.y += self.vel.y * adjust_y # check borders: if self.ball.right >= self.parent.width or self.ball.x <= 0: self.vel.x *= -1 self.ball.x += self.vel.x * adjust_x if self.ball.top >= self.parent.height: self.vel.y *= -1 self.ball.y += self.vel.y * adjust_y if self.ball.y <= 0: self.game_over = True # collisions: # collision: ball and player if self.ball.collide_widget(self.player): print("collide", self.ball.pos) # check if hit some corner: speed = self.vel.length() ball_center = Vector(self.ball.center) topleft = Vector(self.player.x, self.player.top) # botleft = Vector(self.player.x, self.player.y) topright = Vector(self.player.right, self.player.top) # botright = Vector(self.player.right, self.player.y) hit_topleft = topleft.distance(ball_center) <= self.ball.radius # # hit_botleft = botleft.distance(ball_center) <= self.ball.radius hit_topright = topright.distance( ball_center) <= self.ball.radius # # hit_botright = botright.distance( ball_center) <= self.ball.radius dx = self.ball.center_x - topright.x dy = self.ball.center_y - topright.y alpha = Vector(dx, dy).angle(Vector(1, 0)) if self.player.x < self.ball.center_x < self.player.right: self.vel.y *= -1 elif hit_topright or hit_topleft: print(hit_topleft, hit_topright, speed, alpha) self.vel = Vector(speed, 0).rotate(alpha) print(self.vel) self.ball.y += self.vel.y * adjust_y # collision: ball and bricks for brick in self.bricks: if self.ball.collide_widget(brick): print("destroy", brick) self.vel.y *= -1 self.remove_widget(brick) self.bricks.remove(brick) if len(self.bricks) == 0: self.level += 1 self.new()
def is_on_over(self): a = Vector(self.cline.points[0:2]) b = Vector(self.cline.points[2:4]) c = Vector(self.mouse_pos) d = round(a.distance(c) + c.distance(b) - a.distance(b)) if d == 0: self.is_overed = True else: self.is_overed = False
def get_scale_xy(self): p1 = Vector(*self.to_parent(0, 0)) p2 = Vector(*self.to_parent(1, 0)) scale_x = p1.distance(p2) p3 = Vector(*self.to_parent(0, 0)) p4 = Vector(*self.to_parent(0, 1)) scale_y = p3.distance(p4) return scale_x, scale_y
def find_triple_tap(self, ref): '''Find a triple tap touch within self.touches. The touch must be not a previous triple tap, and the distance must be ok, also, the touch profile must be compared so the kind of touch is the same ''' for touchid in self.touches: if ref.uid == touchid: continue etype, touch = self.touches[touchid] if not touch.is_double_tap: continue if etype != 'end': continue if touch.is_triple_tap: continue distance = Vector.distance(Vector(ref.sx, ref.sy), Vector(touch.osx, touch.osy)) if distance > self.triple_tap_distance: continue if touch.is_mouse_scrolling or ref.is_mouse_scrolling: continue if 'button' in touch.profile or 'button' in ref.profile: if 'button' not in ref.profile or ref.button != touch.button: continue touch.triple_tap_distance = distance return touch return None
def find_double_tap(self, ref): '''Find a double tap touch within self.touches. The touch must be not a previous double tap and the distance must be within the specified threshold. Additionally, the touch profiles must be the same kind of touch. ''' ref_button = None if 'button' in ref.profile: ref_button = ref.button for touchid in self.touches: if ref.uid == touchid: continue etype, touch = self.touches[touchid] if etype != 'end': continue if touch.is_double_tap: continue distance = Vector.distance(Vector(ref.sx, ref.sy), Vector(touch.osx, touch.osy)) if distance > self.double_tap_distance: continue if touch.is_mouse_scrolling or ref.is_mouse_scrolling: continue touch_button = None if 'button' in touch.profile: touch_button = touch.button if touch_button != ref_button: continue touch.double_tap_distance = distance return touch return None
def find_triple_tap(self, ref): """Find a triple tap touch within *self.touches*. The touch must be not be a previous triple tap and the distance must be be within the bounds specified. Additionally, the touch profile must be the same kind of touch. """ ref_button = None if "button" in ref.profile: ref_button = ref.button for touchid in self.touches: if ref.uid == touchid: continue etype, touch = self.touches[touchid] if not touch.is_double_tap: continue if etype != "end": continue if touch.is_triple_tap: continue distance = Vector.distance(Vector(ref.sx, ref.sy), Vector(touch.osx, touch.osy)) if distance > self.triple_tap_distance: continue if touch.is_mouse_scrolling or ref.is_mouse_scrolling: continue touch_button = None if "button" in touch.profile: touch_button = touch.button if touch_button != ref_button: continue touch.triple_tap_distance = distance return touch return None
def find_double_tap(self, ref): '''Find a double tap touch within self.touches. The touch must be not a previous double tap, and the distance must be ok, also, the touch profile must be compared so the kind of touch is the same ''' ref_button = None if 'button' in ref.profile: ref_button = ref.button for touchid in self.touches: if ref.uid == touchid: continue etype, touch = self.touches[touchid] if etype != 'end': continue if touch.is_double_tap: continue distance = Vector.distance( Vector(ref.sx, ref.sy), Vector(touch.osx, touch.osy)) if distance > self.double_tap_distance: continue if touch.is_mouse_scrolling or ref.is_mouse_scrolling: continue touch_button = None if 'button' in touch.profile: touch_button = touch.button if touch_button != ref_button: continue touch.double_tap_distance = distance return touch return None
def ItemAction(self, item, n): hero = self.start.hero lifebar = self.start.lifebar u = Vector(*item.center) v = Vector(*hero.center) def speed_boost(): hero.velocity = 4 def plus_life(): if lifebar.lives < 8: lifebar.lives += 1 lifebar.graphics_file = lifebar.files[lifebar.lives - 1] else: pass def shield_up(): hero.shield_up = True hero.graphic = 'Graphics/starship_shield.png' def empty(): pass action = { 'boost': speed_boost, 'one_up': plus_life, 'shield': shield_up, 'empty': empty } if v.distance(u) < 40 and item.y < self.goal.y: action[item.name]() item.pos = (750 - (n * 50), 550)
def update(self, delta): app = App.get_running_app() pos = Vector(self.pos) self.pos = pos + Vector(self.direction) * delta self.score = min(5, int(pos.distance(app.root.center) / 50) + 1) if app.ship: if ( (Vector(self.center) - app.root.center).length() < (self.width + app.ship.width) / 2 ): if app.ship.growth > 0: Clock.unschedule(self.update) self.parent.remove_widget(self) app.score += self.score if SOUND: snd_hit.play() anim = Animation( font_size=dp(140), duration=0.3, ) + Animation( font_size=dp(80), duration=1.0, t="out_bounce" ) anim.start(app.root.score_label) print("CURRENT SCORE: %s" % app.score) else: if SOUND: snd_explode.play() app.root.remove_widget(app.ship) app.ship = "" print("GAME OVER") print("FINAL SCORE: %s" % app.score)
def __init__(self, game, **kwargs): super().__init__() self.game = game self.x = kwargs.get("x", Window.width / 2 - self.width / 2) self.y = kwargs.get("y", self.height) self.game.add_widget(self, index=0) self.game.balls.append(self) self.color = kwargs.get("color", random.choice(list(POSSIBLE_COLORS))) self.touching_balls = [] self.n_repeated_balls = 1 with self.canvas.before: Color(*POSSIBLE_COLORS.get(self.color)) # Collisions: for ball in self.game.balls: if ball is self: continue ball_pos = Vector(*ball.center) self_pos = Vector(*self.center) dist_between_balls = ball_pos.distance(self_pos) if dist_between_balls <= self.game.ball_size + 1: self.touching_balls.append(ball) ball.touching_balls.append(self) print("ball", self.color, self.pos) print("self.touching_balls", self.touching_balls) for ball in self.touching_balls: print("ball", ball.color, ball.pos)
def move(self): p = Vector(*self.pos) h = Vector(*self.heading) if p.distance(h) > 2: self.pos = self.speed + self.pos else: pass
def on_touch_move(self, touch): """based on kivy.uix.scatter""" if touch.grab_current and self.pinch_zooming: self.zoom_by = 0 anchor = Vector(self.touches[0].pos) old_distance = anchor.distance(touch.ppos) new_distance = anchor.distance(touch.pos) if old_distance > new_distance: self.zoom_by = self._zoom_by return True elif new_distance > old_distance: self.zoom_by = -self._zoom_by return True # noinspection PyUnresolvedReferences return super().on_touch_move(touch)
def bounce_ball(self, ball): if self.collide_widget(ball): vx, vy = ball.velocity y_offset = (ball.center_y - self.center_y) / (self.height / 2) bounced = Vector(-1 * vx, vy) if bounced.distance(Vector(0, 0)) < ball.max_speed: vel = bounced * 1.1 else: vel = bounced ball.velocity = vel.x, vel.y + y_offset
def move(self, heading): v = Vector(*heading) u = Vector(self.pos) d = u.distance(v) speed_vector = v - u try: speed_vector *= (self.speed / d) except ZeroDivisionError: speed_vector = Vector(0, 0) self.pos = speed_vector + self.pos
class Ball: def __init__(self): self.color = random() self.r = 25 self.p = Vector((Window.size[0] - 2 * self.r) * random() + self.r, (Window.size[1] - 2 * self.r) * random() + self.r) self.v = Vector(200 * (random() - 0.5), 200 * (random() - 0.5)) self.g = Vector(0, 0) self.loss = 0 self.image = None def get_pos(self): return self.p.x - self.r, self.p.y - self.r def draw(self, canvas): with canvas: Color(self.color, 1, 1, mode="hsv") self.image = Ellipse(pos=self.get_pos(), size=(2 * self.r, 2 * self.r)) def bounce_box(self): if self.p.x < self.r: self.v.x = abs(self.v.x) self.p.x = self.r self.v *= (1 - self.loss) if self.p.x > Window.size[0] - self.r: self.v.x = -abs(self.v.x) self.p.x = Window.size[0] - self.r self.v *= (1 - self.loss) if self.p.y < self.r: self.v.y = abs(self.v.y) self.p.y = self.r self.v *= (1 - self.loss) if self.p.y > Window.size[1] - self.r: self.v.y = -abs(self.v.y) self.p.y = Window.size[1] - self.r self.v *= (1 - self.loss) def bounce_ball(self, ball): #clinging is still possible d = self.p.distance(ball.p) if d < self.r + ball.r: e = (ball.p - self.p).normalize() dv = e.dot(ball.v - self.v) * e self.v += dv ball.v -= dv self.p -= (self.r + ball.r - d) / 2 * e ball.p += (self.r + ball.r - d) / 2 * e self.v *= (1 - self.loss) ball.v *= (1 - ball.loss) def move(self, dt): self.v += self.g * dt self.p += self.v * dt self.image.pos = self.get_pos()
def shotWithArc(self): self.animIndex = 0 origin = Vector(self.tower.center) destination = Vector( self.enemy.getFuturePos(self.tower.shotDuration * 1.1)) destination = Vector( destination.x + random.randint(0, Map.mapvar.squsize), destination.y + random.randint(0, Map.mapvar.squsize)) centerPoint = origin - (origin - destination) / 2 radius = origin.distance(destination) / 2 initAngle = round( math.atan2((origin.y - centerPoint.y), (origin.x - centerPoint.x)), 1) destAngle = round( math.atan2((destination.y - centerPoint.y), (destination.x - centerPoint.x)), 1) self.pointlist = [] interval = .3 angle = initAngle if self.enemy.x <= self.x: if angle > destAngle: while angle > destAngle: a = centerPoint[0] + (radius * math.cos(angle)) b = centerPoint[1] + (radius * math.sin(angle)) self.pointlist.append([a, b]) angle -= interval angle = round(angle, 1) else: while angle < destAngle: a = centerPoint[0] + (radius * math.cos(angle)) b = centerPoint[1] + (radius * math.sin(angle)) self.pointlist.append([a, b]) angle += interval angle = round(angle, 1) else: angle = -angle if angle > destAngle: while angle > destAngle: a = centerPoint[0] + (radius * math.cos(angle)) b = centerPoint[1] + (radius * math.sin(angle)) self.pointlist.append([a, b]) angle -= interval angle = round(angle, 1) else: while angle < destAngle: a = centerPoint[0] + (radius * math.cos(angle)) b = centerPoint[1] + (radius * math.sin(angle)) self.pointlist.append([a, b]) angle += interval angle = round(angle, 1) self.pointlist.append(destination)
def nearest_square(self, current): cpos = Vector(current.pos) nearest_d = 999 nearest_child = None for child in self.children: if not isinstance(child, PentaminoSquare): continue if child is current: continue d = cpos.distance(child.pos) if d < nearest_d: nearest_d = d nearest_child = child return nearest_child, nearest_d
def _get_scale_y(self): p1 = Vector(*self.to_parent(0, 0)) p2 = Vector(*self.to_parent(0, 1)) scale_y = p1.distance(p2) # XXX float calculation are not accurate, and then, scale can be # throwed again even with only the position change. So to # prevent anything wrong with scale, just avoid to dispatch it # if the scale "visually" didn't change. #947 # Remove this ugly hack when we'll be Python 3 only. if hasattr(self, '_scale_py'): if str(scale_y) == str(self._scale_py): return self._scale_py return scale_y
def move(self, previousPart, magnitude): #moves an individual part #first calculates the previous part's position and vectorizes it previousPos = (previousPart.absolutePos[0],previousPart.absolutePos[1]) destination = Vector(previousPos[0], previousPos[1]) current = (self.absolutePos[0], self.absolutePos[1]) velocity = Vector(destination.x-current[0],destination.y-current[1]) #determines velocity based on destination and current position if destination.distance(current) < self.width: #realigns the part velocity so that parts don't outrun the head #when the head turns magnitude *= velocity.length() / self.width velocity = velocity.normalize() * magnitude self.absolutePos[0] += velocity.x self.absolutePos[1] += velocity.y self.wrapAround()
def _get_scale(self): p1 = Vector(*self.to_parent(0, 0)) p2 = Vector(*self.to_parent(1, 0)) scale = p1.distance(p2) # XXX float calculation are not accurate, and then, scale can be # throwed again even with only the position change. So to # prevent anything wrong with scale, just avoid to dispatch it # if the scale "visually" didn't change. #947 # Remove this ugly hack when we'll be Python 3 only. if hasattr(self, '_scale_p'): if str(scale) == str(self._scale_p): return self._scale_p self._scale_p = scale return scale
def move(self, previousPart, magnitude): #moves an individual part #first calculates the previous part's position and vectorizes it previousPos = (previousPart.absolutePos[0], previousPart.absolutePos[1]) destination = Vector(previousPos[0], previousPos[1]) current = (self.absolutePos[0], self.absolutePos[1]) velocity = Vector(destination.x - current[0], destination.y - current[1]) #determines velocity based on destination and current position if destination.distance(current) < self.width: #realigns the part velocity so that parts don't outrun the head #when the head turns magnitude *= velocity.length() / self.width velocity = velocity.normalize() * magnitude self.absolutePos[0] += velocity.x self.absolutePos[1] += velocity.y self.wrapAround()
def checkCollisions(self, entity, entities): for other in entities: if entity is not other: dx = other.x - entity.x dy = other.y - entity.y minDist = other.radius + entity.radius otherxy = Vector(other.x, other.y) selfxy = Vector(entity.x, entity.y) if selfxy.distance(otherxy) < minDist: angle = atan2(dy, dx) targetX = entity.x + cos(angle) * minDist targetY = entity.y + sin(angle) * minDist ax = (targetX - other.x) * entity.spring ay = (targetY - other.y) * entity.spring self.collide(entity, other, ax, ay)
def create_game(self): """ fonction qui crée un terrain de jeu : - apparition aléatoires des noeuds de début de jeu """ """WARNING : penser a inserer le return a l'écran de menu via un double clic sur l'écran """ print "createeeeeeeeeeeeeeee" # w, h = canvas.size(); root = Widget() # root = ScatterPlane() """ ici on soustrait la taille du rond afin que l'affichage se fasse bien, qu'aucun noeud ne soit couper par les bords de la fenetre """ w = Window.width - 50 h = Window.height - 50 # on ajoute la liste des positions des Point que l'on crées à la liste # root listPoint = [] # inclure n : nbre de noeuds while len(listPoint) != self.nbDep: point = Point(size=(25, 25), pos=(random() * w, random() * h)) ok = True v = Vector(point.center) for p in listPoint: if v.distance(p.center) <= 25: ok = False break if ok: """ si la variable ok est true, cad si la distance entre deux points est supérieur a deux fois le rayon, alors j'ajoute mon point a ma liste de point et j'ajoute mon point a mon root pour qu'il soit affiché a l'écran """ listPoint.append(point) root.add_widget(point) root.add_widget(Tracer()) return root
def find_double_tap(self, ref): '''Find a double tap touch within self.touches. The touch must be not a previous double tap, and the distance must be ok''' for touchid in self.touches: if ref.uid == touchid: continue etype, touch = self.touches[touchid] if etype != 'end': continue if touch.is_double_tap: continue distance = Vector.distance(Vector(ref.sx, ref.sy), Vector(touch.osx, touch.osy)) if distance > self.double_tap_distance: continue touch.double_tap_distance = distance return touch return None
def createEdges(): lst = list() for tabw in slmap.walls: x = tabw[0] * CELL_SIZE y = tabw[1] * CELL_SIZE typ = tabw[2] * CELL_SIZE p1 = Vector(persoX, persoY) p2 = Vector(x + CELL_SIZE/2, y + CELL_SIZE/2) distToChar = p1.distance(p2) if distToChar > SIGHT_RANGE: continue view = p2 - p1 edges = list() for i in xrange(0,4): if i == 0 and typ not in [2,3,4,7,8,9,11,15]: p1 = Vector(x, y) # DOWN p2 = Vector(x+CELL_SIZE, y) elif i == 1 and typ not in [1,3,5,7,8,10,11,14]: p1 = Vector(x+CELL_SIZE, y) # RIGHT p2 = Vector(x+CELL_SIZE, y+CELL_SIZE) elif i == 2 and typ not in [2,5,6,7,9,10,11,13]: p1 = Vector(x+CELL_SIZE, y+CELL_SIZE) # UP p2 = Vector(x, y+CELL_SIZE) elif i == 3 and typ not in [1,4,6,8,9,10,11,12]: p1 = Vector(x, y+CELL_SIZE) # LEFT p2 = Vector(x, y) dire = p2 - p1 norm = Vector(-dire[1], dire[0]) if norm.dot(view) > 0: edge = Edge(p1, p2, distToChar) lst.append(edge) return lst
def find_double_tap(self, ref): '''Find a double tap touch within self.touches. The touch must be not a previous double tap, and the distance must be ok''' for touchid in self.touches: if ref.uid == touchid: continue etype, touch = self.touches[touchid] if etype != 'end': continue if touch.is_double_tap: continue distance = Vector.distance( Vector(ref.sx, ref.sy), Vector(touch.osx, touch.osy)) if distance > self.double_tap_distance: continue touch.double_tap_distance = distance return touch return None
def on_touch_move(self, touch): # Need to return False for Scatter to work when touching this point # Not sure why True is returned by Kivy when disabled anyway. if self.disabled: return False if super(ControlPoint, self).on_touch_move(touch): return True x, y = touch.pos[0], touch.pos[1] # If grabbing this point and the move is within bounds of parent, move the point if touch.grab_current is self: # pos was converted to_local # Restrict to parent # 0 if < 0, parent.right if > parent.right, otherwise x parent = self.parent # TODO Fix Hardcoded logic to animation step 0 if self.position_index == setup_step: # Parents boundary in local coords self.x = min(max(0, x), parent.width) self.y = min(max(0, y), parent.height) else: origin = self.positions[setup_step] # Only allow moving if within this distance of first point distance_limit = parent.bbox_diagonal pos0v = Vector(origin) if pos0v.distance((x, y)) < distance_limit: self.pos = (x, y) else: # Place as far as allowed v = (Vector((x,y)) - Vector(origin)).normalize() self.pos = pos0v + v*distance_limit return True return False
def on_touch_down(self, touch): a = touch.x - self.width / 2 b = touch.y if a < 0: a = 0 elif a > (Window.width - 50): a = Window.width - 50 elif b > Window.height - 50: b = Window.height - 50 else: pass self.heading = a, b v = Vector(a, b) u = Vector(self.pos) d = u.distance(v) new_vector = v - u try: new_vector *= (self.velocity / d) except ZeroDivisionError: new_vector = 0, 0 self.speed[0] = new_vector[0] self.speed[1] = new_vector[1]
def mind_barier(self, game): for barier in game.children: if "Barier object" in str(barier): if self.collide_widget(barier): nearest=Vector(barier.center) nearestdist=nearest.distance(self.center) if barier.height > barier.width: for y in range(int(barier.y+barier.offset), int(barier.y+barier.height-barier.offset)): dist = Vector(barier.center_x,y).distance(self.center) if dist < nearestdist: nearest = Vector(barier.center_x,y) nearestdist=dist else: for x in range(int(barier.x+barier.offset), int(barier.x+barier.width-barier.offset)): dist = Vector(x,barier.center_y).distance(self.center) if dist < nearestdist: nearest = Vector(x,barier.center_y) nearestdist=dist barierbball = 20* (Vector(self.center)-Vector(nearest)) if nearestdist==0: nearestdist=0.1 barierbball = Vector(self.velocity)+(barierbball/(nearestdist*nearestdist)) self.velocity_x=barierbball.x self.velocity_y=barierbball.y
class Circle: def __init__(self, pos, radius): self.pos = Vector(*pos) self.r = radius def get_bbox(self): return self.pos.x - self.r, self.pos.y - self.r, self.pos.x + self.r, self.pos.y + self.r def get_y_at(self, x): # solution of y^2 - 2 * self.pos.y * y + self.pos.y^2 + (x - self.pos.x)^2 - self.r^2 = 0 # quadratic equation a = 1 b = -2 * self.pos.y c = self.pos.y**2 + (x - self.pos.x)**2 - self.r**2 has_sol, s1, s2 = self.solve_quadratic(a, b, c) if not has_sol: return False, 0, 0 return True, s1, s2 def collide_point(self, point): return self.pos.distance(point) <= self.r def collide_line(self, v1, v2): # based on https://stackoverflow.com/questions/40970478/python-3-5-2-distance-from-a-point-to-a-line x_diff = v2.x - v1.x y_diff = v2.y - v1.y num = abs(y_diff * self.pos.x - x_diff * self.pos.y + v2.x * v1.y - v2.y * v1.x) den = v2.distance(v1) return (num / den) <= self.r def collide_line_segment(self, v1, v2): if self.collide_point(v1) or self.collide_point(v2): return True # based on https://codereview.stackexchange.com/questions/86421/line-segment-to-circle-collision-algorithm # rewrite the segment as v1 + t*dir dir = v2 - v1 # at^2 + bt + c a = dir.dot(dir) b = 2 * dir.dot(v1 - self.pos) c = v1.dot(v1) + self.pos.dot( self.pos) - 2 * v1.dot(self.pos) - self.r**2 has_sol, t1, t2 = self.solve_quadratic(a, b, c) if not has_sol: return False return 0 <= t1 <= 1 or 0 <= t2 <= 1 def collide_rect(self, rectangle): # any rectangle vertex inside the circle (either whole rectangle inside or side collision) for vertex in rectangle.get_vertexes(): if self.collide_point(vertex): return True # all rect vertexes outside, try side collision for side in rectangle.get_sides(): if self.collide_line_segment(side[0], side[1]): return True @staticmethod def solve_quadratic(a, b, c): disc = b**2 - 4 * a * c if disc < 0: return False, 0, 0 sqrt_disc = math.sqrt(disc) t1 = (-b + sqrt_disc) / (2 * a) t2 = (-b - sqrt_disc) / (2 * a) return True, t1, t2
def update(self, dt): # collisions: # stick collide with the balls: if self.stick.collide_widget( self.white_ball) and self.shoot_power != 0: print("collide with white ball") dx = cos(self.stick.angle * pi / 180 + pi / 2) * self.shoot_power dy = sin(self.stick.angle * pi / 180 + pi / 2) * self.shoot_power self.white_ball.dx = dx self.white_ball.dy = dy try: self.anim.cancel(self.stick) except: pass # collisions with borders: for ball in self.balls: if ball.top > self.table.top: ball.top = self.table.top ball.dy *= -1 if ball.y < self.table.y: ball.y = self.table.y ball.dy *= -1 if ball.right > self.table.right: ball.right = self.table.right ball.dx *= -1 if ball.x < self.table.x: ball.x = self.table.x ball.dx *= -1 # collision ball1-ball2: for ball1, ball2 in [(self.balls[0], self.balls[1]), (self.balls[0], self.balls[2]), (self.balls[1], self.balls[2])]: if ball1.collide_widget(ball2): ball1_pos = Vector(*ball1.pos) print(ball2) ball2_pos = Vector(*ball2.pos) dist_ball1_ball2 = ball1_pos.distance(ball2_pos) offset = max(ball1.width - dist_ball1_ball2, 0) ball1_vel = Vector(ball1.dx, ball1.dy) half_speed = ball1_vel.length() / 2 angle_vel = ball1_vel.angle(Vector(1, 0)) angle_ball1_ball2 = Vector(ball2.x - ball1.x, ball2.y - ball1.y).angle( Vector(1, 0)) angle_desv_perp_collision = angle_ball1_ball2 + (90 - angle_vel) angle_ball1 = angle_desv_perp_collision + angle_ball1_ball2 + 90 ball1_vel = Vector(half_speed, 0).rotate(angle_ball1) ball1.dx = ball1_vel.x ball1.dy = ball1_vel.y angle_ball2 = angle_ball1_ball2 + 90 - angle_desv_perp_collision ball_1 = Vector(half_speed, 0).rotate(angle_ball2) ball2.dx = ball_1.x ball2.dy = ball_1.y vector_offset = Vector(offset, 0).rotate(angle_ball1) ball1.x += vector_offset.x ball1.y += vector_offset.y for ball in self.balls: print("ball", ball, ball.x, ball.y, ball.dx, ball.dy) # Collide with holes: for hole in self.holes: if hole.collide_point(*ball.center): self.remove_widget(ball) # Friction: ball.frictionx = ball.dx * BALL_FRICTION * dt ball.frictiony = ball.dy * BALL_FRICTION * dt # kinematic equations: ball.x += ball.dx * dt ball.y += ball.dy * dt ball.dx -= ball.frictionx ball.dy -= ball.frictiony if abs(ball.dx) < 0.01: ball.dx = 0 if abs(ball.dy) < 0.01: ball.dy = 0
def update(self, *args): def RndHeading(): rnd_x = random() * self.gamezone.width rnd_y = random() * self.gamezone.height heading = rnd_x, rnd_y return heading def set_patrol(): pointA = self.goal.x, self.goal.y - 60 pointB = self.goal.right - 50, self.goal.y - 60 return pointA, pointB l = self.start.lifebar self.start.hero.move() self.ItemAction(self.start.pickup1, 0) self.ItemAction(self.start.pickup2, 1) a = self.start.hero.x b = self.start.hero.y AI = { 'lurker': (a, Window.height / 2), 'homer': (a, b), 'irris': RndHeading, 'guard': set_patrol(), 'bluff': (a, b) } default_speed = { 'lurker': 2.5, 'homer': 2.9, 'irris': 4, 'guard': 4, 'bluff': 5 } if self.gamezone.collide_widget(self.start.hero): self.gamezone.text = '' for i in self.baddies: if i.name == 'irris': v = Vector(*i.rnd_heading) u = Vector(*i.pos) if i.counter % 60 == 0 or u.distance(v) < 25: heading_giver = AI[i.name] i.rnd_heading = heading_giver() i.counter = 0 i.counter += 1 heading = i.rnd_heading # Unnecessary brute-force!! ########################### elif i.name == 'guard': a1, b1 = AI[i.name] v = Vector(*i.pos) va = Vector(*a1) vb = Vector(*b1) if v.distance(va) < 25: self.k = 1 elif v.distance(vb) < 25: self.k = 0 else: pass if self.k == 0: heading = a1 elif self.k == 1: heading = b1 else: pass else: heading = AI[i.name] if i.name != 'bluff': i.move(heading) elif Vector(*i.pos).distance(Vector( a, b)) < 200 and i.attack < 0.7: i.move(heading) else: pass for i in self.baddies: # if baddies collide for j in self.baddies: if i != j: u = Vector(*i.pos) v = Vector(*j.pos) if u.distance(v) < 50: i.pos = 2 * (u - v) / hypot(*(u - v)) + i.pos j.pos = -2 * (u - v) / hypot(*(u - v)) + j.pos for i in self.baddies: i.speed = default_speed[i.name] hero = self.start.hero x1, y1 = i.pos x2, y2 = hero.pos if hypot( x1 - x2, y1 - y2 ) < 50 and hero.shield_up == False: # if player collides with enemy l.lives -= 1 self.list_baddies() if l.lives == 0: self.loss.open() l.lives = 5 self.level = 1 self.configure_level() self.set_graphics() self.reset() l.graphics_file = l.files[l.lives - 1] else: l.graphics_file = l.files[l.lives - 1] self.reset() i.attack = random() elif hypot(x1 - x2, y1 - y2) < 50 and hero.shield_up == True: i.pos = (-100, -100) self.baddies.remove(i) hero.shield_up = False hero.graphic = 'Graphics/starship.png' elif self.start.hero.y > self.gamezone.top: # if player reaches goal self.level += 1 if self.level > self.progress: self.progress = self.level self.txt.text = 'All your ships have been destroyed.\n Highest level reached: level %d' % ( self.progress) if self.level > len(self.Levels): self.gamezone.text = 'You Won!' self.start.hero.graphic = 'Graphics/starship_green.png' else: self.gamezone.text = 'Level ' + str(self.level) self.configure_level() self.set_graphics() self.reset() self.transition.open() else: pass
def collide(self): dx = Window.mouse_pos[0] - self.x dy = Window.mouse_pos[1] - self.y minDist = self.defender.radius + self.radius defxy = Vector(Window.mouse_pos[0], Window.mouse_pos[1]) selfxy = Vector(self.x, self.y) if selfxy.distance(defxy) < minDist: angle = atan2(dy, dx) targetX = self.x + cos(angle) * minDist targetY = self.y + sin(angle) * minDist ax = (targetX - Window.mouse_pos[0]) * self.spring ay = (targetY - Window.mouse_pos[1]) * self.spring self.vx -= ax self.vy -= ay self.defender.damage() if isinstance(self.othersList, list): for other in self.othersList: if other is not self: dx = other.x - self.x dy = other.y - self.y minDist = Vector(self.x, self.y).distance(Vector(self.x + (self.radius * 1.3), self.y + (self.radius * 1.3))) otherxy = Vector(other.x, other.y) if Vector(selfxy).distance(otherxy) <= minDist: angle = atan2(dy, dx) targetX = self.x + cos(angle) * minDist targetY = self.y + sin(angle) * minDist ax = (targetX - other.x) * self.spring ay = (targetY - other.y) * self.spring self.vx -= ax self.vy -= ay other.vx += ax other.vy += ay for laser in self.defender.lasers: minDist = self.radius + self.defender.blasterLength if Vector(selfxy).distance(Vector(laser.x, laser.y)) < minDist: print("You sank my energy chip!") #choice(SOUNDLIST).play() self.alive = False self.defender.score += 1 self.othersList = None if self.x + self.radius > SCREENWIDTH: self.x = SCREENWIDTH - self.radius self.vx *= self.friction #self.x = 0 + self.x elif self.x - self.radius < 0: self.x = self.radius self.vx *= self.friction #self.x = width - self.x if self.y + self.radius > SCREENHEIGHT: self.y = SCREENHEIGHT - self.radius self.vy *= self.friction #self.y = 0 +self.y elif self.y - self.radius < 0: self.y = self.radius self.vy *= self.friction
def _get_scale(self): p1 = Vector(*self.to_parent(0, 0)) p2 = Vector(*self.to_parent(1, 0)) scale = p1.distance(p2) return float(scale)
class CarEnv(object): def __init__(self, filename): print("CARENV-------->") self.filename = filename img = Image.open(self.filename).convert('L') self.sand = np.asarray(img) / 255 self.sand = self.sand.astype(int) self.max_y, self.max_x = self.sand.shape self.pos = Vector(int(self.max_x / 2), int(self.max_y / 2)) self.angle = Vector(0, 10).angle(self.pos) self.velocity = Vector(6, 0) self.wall_padding = 20 self.rel_pos = Vector(0, 0) self.max_angle = 10 self.max_action = [self.max_angle] self.crop_size = 100 self.goal_iter = 0 self.goals = [Vector(1890, 150), Vector(140, 380)] self.last_distance = 0 self.state_dim = (32, 32) self.action_dim = (1, ) self._max_episode_steps = 4000 # track rewards distribution self.rewards_distribution = Counter() def seed(self, seed): pass def reset(self): print("reset----> CARENV") self.angle = np.random.randint(low=0, high=360) onsand = True while onsand: self.pos.x = np.random.randint(low=self.wall_padding, high=self.max_x - self.wall_padding) self.pos.y = np.random.randint(low=self.wall_padding, high=self.max_y - self.wall_padding) if self.sand[int(self.pos.y), int(self.pos.x)] <= 0: onsand = False self.velocity = Vector(2, 0).rotate(self.angle) return self.get_state() def random_action(self): print("random_action----> CARENV") rotation = np.random.randint(low=-self.max_angle, high=self.max_angle) return (rotation, ) def step(self, action): print("step------------>") rotation = action[0] self.angle += rotation self.pos = Vector(*self.velocity) + self.pos self.pos.x = int(self.pos.x) self.pos.y = int(self.pos.y) reward = 0 done = False current_goal = self.goals[self.goal_iter] distance = self.pos.distance(current_goal) if self.sand[int(self.pos.y), int(self.pos.x)] > 0: self.velocity = Vector(0.5, 0).rotate(self.angle) reward = -1 tag = "sand (-1)" else: # otherwise self.velocity = Vector(2, 0).rotate(self.angle) reward = -0.1 tag = "road (-0.1)" if distance < self.last_distance: reward = 1 tag = "road (+1)" if self.pos.x < self.wall_padding: self.pos.x = self.wall_padding reward = -5 tag = "wall (-5)" done = True if self.pos.x > self.max_x - self.wall_padding: self.pos.x = self.max_x - self.wall_padding reward = -5 tag = "wall (-5)" done = True if self.pos.y < self.wall_padding: self.pos.y = self.wall_padding reward = -5 tag = "wall (-5)" done = True if self.pos.y > self.max_y - self.wall_padding: self.pos.y = self.max_y - self.wall_padding reward = -5 tag = "wall (-5)" done = True if distance < 25: self.goal_iter = (self.goal_iter + 1) % len(self.goals) goal = self.goals[self.goal_iter] reward = 10 tag = "goal (+10)" done = True self.last_distance = distance self.rewards_distribution[tag] += 1 return self.get_state(), reward, done def render(self): print("render---------->") # Create figure and axes fig, ax = plt.subplots(1, 5, figsize=(30, 6)) # Display the image ax[0].imshow(self.sand, cmap='gray', vmin=0, vmax=1) # Create a Rectangle patch rect = patches.Rectangle((self.pos.x - int(self.crop_size / 2), self.pos.y - int(self.crop_size / 2)), self.crop_size, self.crop_size, linewidth=1, edgecolor='r', facecolor='none') # Add the patch to the Axes ax[0].add_patch(rect) ax[0].set_title("x=%d,y=%d,angle=%d" % (self.pos.x, self.pos.y, self.angle)) marker = mmarkers.MarkerStyle(marker="$ \\rightarrow$") marker._transform = marker.get_transform().rotate_deg(self.angle) ax[0].scatter(self.pos.x, self.pos.y, s=50, c='red', marker=marker) self.get_state(ax).cpu().numpy() plt.show() def get_state(self, ax=None): print("get_state--------->") resize = T.Compose([ T.ToPILImage(), T.Resize(self.state_dim[0], interpolation=Image.CUBIC), T.ToTensor() ]) img = Image.open(self.filename).convert('L') # If we directly crop and rotate the image, we may loose information # from the edges. Hence we do the following: # * Crop a larger portion of image # * Rotate it to make the cropped image in the direction # of car's orientation # * Then crop it to required size crop_img = utilityImage.center_crop_img(img, self.pos.x, self.pos.y, self.crop_size * 3) if ax is not None: utilityImage.show_img(ax[1], crop_img, "large crop") print(" large crop-------->") r_img = utilityImage.rotate_img(crop_img, -self.angle) if ax is not None: utilityImage.show_img(ax[2], r_img, "rotated crop") print(" rotated crop-------->") r_img_x, r_img_y = r_img.size crop_img = utilityImage.center_crop_img(r_img, int(r_img_x / 2), int(r_img_y / 2), self.crop_size) if ax is not None: utilityImage.show_img(ax[3], crop_img, "final crop") print(" final crop-------->") np_img = np.asarray(crop_img) / 255 np_img = np_img.astype(int) screen = np.ascontiguousarray(np_img, dtype=np.float32) screen = torch.from_numpy(screen) screen = resize(screen) if ax is not None: print("crop get state-------->") np_img = screen.squeeze(0).numpy() np_img = np_img.astype(int) ax[4].imshow(np_img, cmap='gray', vmin=0, vmax=1) marker = mmarkers.MarkerStyle(marker="$ \\rightarrow$") ax[4].scatter(self.state_dim[0] / 2, self.state_dim[1] / 2, s=100, c='red', marker=marker) ax[4].set_title("final resized img") device = torch.device("cuda" if torch.cuda.is_available() else "cpu") print("crop------end") return screen.to(device)
class CarEnv(object): def __init__(self, filename): self.filename = filename img = Image.open(self.filename).convert('L') self.sand = np.asarray(img) / 255 self.sand = self.sand.astype(int) self.max_y, self.max_x = self.sand.shape self.pos = Vector(int(self.max_x / 2), int(self.max_y / 2)) self.angle = Vector(10, 0).angle(self.pos) self.velocity = Vector(6, 0) self.wall_padding = 5 self.max_angle = 20 self.max_action = [self.max_angle] self.crop_size = 100 self.goal_iter = 0 self.goals = [Vector(1890, 150), Vector(140, 380)] self.last_distance = 0 self.state_dim = (32, 3) self.action_dim = (1, ) self._max_episode_steps = 5000 # track rewards distribution self.rewards_distribution = Counter() self.target = Vector(335, 178) self.max_distance = 1574. def seed(self, seed): torch.manual_seed(seed) np.random.seed(seed) def reset(self): self.angle = np.random.randint(low=-180, high=180) onsand = True while onsand: self.pos.x = np.random.randint(low=self.wall_padding, high=self.max_x - self.wall_padding) self.pos.y = np.random.randint(low=self.wall_padding, high=self.max_y - self.wall_padding) if self.sand[int(self.pos.y), int(self.pos.x)] == 0: onsand = False self.velocity = Vector(0.5, 0).rotate(self.angle) return self.get_state() def random_action(self): rotation = np.random.uniform(low=-self.max_angle, high=self.max_angle) return (rotation, ) def step(self, action): rotation = action[0] self.angle += rotation if self.sand[int(self.pos.y), int(self.pos.x)] > 0: self.velocity = Vector(0.5, 0).rotate(self.angle) else: self.velocity = Vector(2.0, 0).rotate(self.angle) self.pos.x += self.velocity.x self.pos.y += -self.velocity.y reward = 0 done = False distance = self.pos.distance(self.target) if self.sand[int(self.pos.y), int(self.pos.x)] > 0: reward = -1 tag = "sand" else: if distance < 20: tag = "goal" reward = 10 done = True elif distance < self.last_distance: tag = "towards" reward = 0.1 else: tag = "away" reward = -0.5 wall_reward = -10 if self.pos.x < self.wall_padding: self.pos.x = self.wall_padding reward = wall_reward tag = "wall" done = True if self.pos.x > self.max_x - self.wall_padding: self.pos.x = self.max_x - self.wall_padding reward = wall_reward tag = "wall" done = True if self.pos.y < self.wall_padding: self.pos.y = self.wall_padding reward = wall_reward tag = "wall" done = True if self.pos.y > self.max_y - self.wall_padding: self.pos.y = self.max_y - self.wall_padding reward = wall_reward tag = "wall" done = True self.last_distance = distance self.rewards_distribution[tag] += 1 return self.get_state(), reward, done def render(self): # Create figure and axes fig, ax = plt.subplots(1, 5, figsize=(30, 6)) # Display the image ax[0].imshow(self.sand, cmap='gray', vmin=0, vmax=1) # Create a Rectangle patch rect = patches.Rectangle((self.pos.x - int(self.crop_size / 2), self.pos.y - int(self.crop_size / 2)), self.crop_size, self.crop_size, linewidth=1, edgecolor='r', facecolor='none') # Add the patch to the Axes ax[0].add_patch(rect) ax[0].set_title("x=%d,y=%d,angle=%d" % (self.pos.x, self.pos.y, self.angle)) marker = mmarkers.MarkerStyle(marker="$ \\rightarrow$") marker._transform = marker.get_transform().rotate_deg(self.angle) ax[0].scatter(self.pos.x, self.pos.y, s=50, c='red', marker=marker) self.get_state(ax) plt.show() def get_state(self, ax=None): distance = self.pos.distance(self.target) / self.max_distance goal_vector = self.target - self.pos goal_vector = Vector(goal_vector.x, self.max_y - goal_vector.y) velocity = Vector(2, 0).rotate(self.angle) orientation = Vector(*velocity).angle(goal_vector) / 180. resize = T.Compose([ T.ToPILImage(), T.Resize(self.state_dim[0], interpolation=Image.CUBIC), T.ToTensor() ]) img = Image.open(self.filename).convert('L') # If we directly crop and rotate the image, we may loose information # from the edges. Hence we do the following: # * Crop a larger portion of image # * Rotate it to make the cropped image in the direction # of car's orientation # * Then crop it to required size crop_img = imgutils.center_crop_img(img, self.pos.x, self.pos.y, self.crop_size * 3) if ax is not None: show_img(ax[1], crop_img, "large crop") r_img = imgutils.rotate_img(crop_img, -self.angle) if ax is not None: show_img(ax[2], r_img, "rotated crop") r_img_x, r_img_y = r_img.size crop_img = imgutils.center_crop_img(r_img, int(r_img_x / 2), int(r_img_y / 2), self.crop_size) if ax is not None: show_img(ax[3], crop_img, "final crop") np_img = np.asarray(crop_img) / 255 np_img = np_img.astype(int) screen = np.ascontiguousarray(np_img, dtype=np.float32) screen = torch.from_numpy(screen) screen = resize(screen) if ax is not None: np_img = screen.squeeze(0).numpy() np_img = np_img.astype(int) ax[4].imshow(np_img, cmap='gray', vmin=0, vmax=1) marker = mmarkers.MarkerStyle(marker="$ \\rightarrow$") ax[4].scatter(self.state_dim[0] / 2, self.state_dim[0] / 2, s=100, c='red', marker=marker) ax[4].set_title("final resized img") return screen, torch.Tensor([distance, orientation, -orientation])
def update(self, dt): if self.first_update: # print("First Update") # self.init_env() obs = self.get_state() obs.save("thumbnail.jpg", "JPEG") self.first_update = False # print("Update") obs = self.get_state() # action = self.random_action() # obs = self.step(action) # Training # We start the main loop over 500,000 timesteps if self.total_timesteps < self.max_timesteps: # If the episode is done if self.done: # If we are not at the very beginning, we start the training process of the model if self.total_timesteps != 0: print("Total Timesteps: {} Episode Num: {} Reward: {}". format(self.total_timesteps, self.episode_num, self.episode_reward)) self.policy.train(self.replay_buffer, self.episode_timesteps, self.batch_size, self.discount, self.tau, self.policy_noise, self.noise_clip, self.policy_freq) # When the training step is done, we reset the state of the environment obs = self.reset() # Set the Done to False done = False # Set rewards and episode timesteps to zero self.episode_reward = 0 self.episode_timesteps = 0 self.episode_num += 1 # Before 10000 timesteps, we play random actions if self.total_timesteps < self.start_timesteps: print("random Action ") action = self.random_action() obs = self.get_state() else: # After 10000 timesteps, we switch to the model print("Brain Action ") action = self.policy.select_action( np.array(obs).reshape(1, 40, 40)) # If the explore_noise parameter is not 0, we add noise to the action and we clip it if self.expl_noise != 0: action = (action + np.random.normal( 0, self.expl_noise, size=self.action_dim)).clip( -self.max_action, self.max_action) # The agent performs the action in the environment, then reaches the next state and receives the reward new_obs, reward, done = self.step(action) # Finding new Distance curr_pos = Vector(self.car.pos) new_distance = curr_pos.distance(self.current_goal) print(new_distance) # Adding environment conditions if self.sand[int(self.car.x), int(self.car.y)] > 0: self.car.velocity = Vector(0.5, 0).rotate(self.car.angle) reward = -0.5 self.done = False else: self.car.velocity = Vector(2, 0).rotate(self.car.angle) reward = 10 self.done = False if new_distance < self.distance: reward = 20 if self.car.x < 20: self.car.x = 20 reward -= 10 self.done = True if self.car.x > self.width - 20: self.car.x = self.width - 20 reward -= 10 self.done = True if self.car.y < 10: self.car.y = 10 reward -= 10 self.done = True if self.car.y > self.height - 10: self.car.y = self.height - 10 reward -= 10 self.done = True if new_distance < 25: reward += 35 if swap == 1: print("Reached position A: x: ", self.car.x, " y: ", self.car.y) self.goal_iter = 1 swap = 0 self.done = True else: print("Reached position B: x: ", self.car.x, " y: ", self.car.y) self.goal_iter = 0 swap = 1 self.done = False else: reward -= 0.1 # We check if the episode is done done_bool = 0 if self.episode_timesteps + 1 == self._max_episode_steps else float( done) # We increase the total reward self.episode_reward += reward # We store the new transition into the Experience Replay memory (ReplayBuffer) self.replay_buffer.add((obs, new_obs, action, reward, done_bool)) # We update the state, the episode timestep, the total timesteps, and the timesteps since the evaluation of the policy obs = new_obs self.distance = new_distance self.episode_timesteps += 1 self.total_timesteps += 1 self.timesteps_since_eval += 1
def on_touch_down(self, touch): # if self.image_unlocked: # Defer to Scatter implementation # return super(AnimationConstructor, self).on_touch_down(touch) # Otherwise manipulate ControlPoints instead of Scatter doing anything # handled = super(AnimationConstructor, self).on_touch_down(touch) # if handled: # return True x, y = touch.x, touch.y # Other Widgets, e.g. Button need us to return False to work if not self.collide_point(x, y): return False if self.move_resize: # Defer to Scatter return super(AnimationConstructor, self).on_touch_down(touch) # Otherwise, find nearest ControlPoint # We must take over children's on_touch_down since having them check who's closest instead of the parent assert len(self.children) == len(self.control_points) touch.push() try: touch.apply_transform_2d(self.to_local) transformed_x, transformed_y = touch.x, touch.y if self.children: touch_vec = Vector(transformed_x, transformed_y) closest = None closest_dist = 0 for child in self.children: if child.disabled: continue # Distance from touch to child dist = touch_vec.distance(child.pos) if closest is None or dist < closest_dist: closest = child closest_dist = dist if closest is None: # All children disabled return False # Grab closest if within certain distance elif closest_dist < closest.width/1.5: closest.pos = transformed_x, transformed_y touch.grab(closest) return True # No children or none close enough if self.animation_step != setup_step: # Only create ControlPoints in first step return False # None were close enough, create a new ControlPoint ctrl_pt = ControlPoint(moved_point_trigger=self._moved_control_point_trigger) ctrl_pt.mesh = self.mesh ctrl_pt.position_index = self.animation_step self.add_widget(ctrl_pt) # Use transformed coordinates ctrl_pt.pos = (transformed_x, transformed_y) # cp.vertex_index will be set within on_ctrl_points self.control_points.append(ctrl_pt) # Grab right away so user can create and move in one touch touch.grab(ctrl_pt) return True finally: # Always pop when returning from try block where we did touch.push() touch.pop() # Using Scatter now, need to think about, not needed I think # def on_touch_move(self, touch): # x, y = touch.x, touch.y # touch.push() # touch.apply_transform_2d(self.to_local) # ret = super(AnimationConstructor, self).on_touch_move(touch) # touch.pop() # return ret # # def on_touch_up(self, touch): # x, y = touch.x, touch.y # touch.push() # touch.apply_transform_2d(self.to_local) # ret = super(AnimationConstructor, self).on_touch_up(touch) # touch.pop() # return ret