def crash(self): """Indicate that the moon has crashed. Args: None. Returns: Nothing. Sets the velocity to (0, 0), changes the sprite image to an explosion and sets the crashed flag to true. """ self.velocity = Vector(0, 0) self.image = self.images[1] self.crashed = True self.__adjust_position()
def chk_in_arrow(self, x, y): """Checks whether point is inside the velocity arrow. Args: x (float or int): X-coordinate of the point. y (float or int): Y-coordinate of the point. Returns: bool: True if the point is contained, False if not. The check is accomplished by setting up a bounding rect for the arrow that is aligned along the x-axis pointing to the right. The point is then set relative to the moon and rotated to a corresponding orientation versus the bounding rect along the axis. The model.engine.inrect method is the used to determine containment. """ # Bounding rect for velocity arrow. arrow_rect = Rect() arrow_rect.width = (const.MOON_ARROW_LEN_SCALE * self.velocity.mag() + const.MOON_ARROW_HDX) arrow_rect.height = const.MOON_ARROW_WIDTH_SCALE * self.width arrow_rect.x = const.MOON_ARROW_BASE_SHIFT * self.width arrow_rect.y = -arrow_rect.height / 2 # Get click position relative to the moon. pos = Vector(x, y) rel_pos = pos - self.__locus # Rotate the relative click position to the new arrow position. ang = -self.velocity.angle_rad() rel_rot_x = rel_pos.x * math.cos(ang) - rel_pos.y * math.sin(ang) rel_rot_y = rel_pos.x * math.sin(ang) + rel_pos.y * math.cos(ang) return model.engine.inrect(rel_rot_x, rel_rot_y, arrow_rect)
def __init__(self, draw_label=False): """Initialization. Args: draw_label (bool): Flag for whether the simulation label should be drawn. """ config = pyglet.gl.Config(double_buffer=True, sample_buffers=1, samples=4) super().__init__(width=const.MAIN_WIN_WIDTH, height=const.MAIN_WIN_HEIGHT, caption=const.MAIN_WIN_TITLE, config=config) # Initialize the simulation master data object. self.simstate = 'stopped' self.simmode = 'ready' self.simoptions = {'draw_label': draw_label} self.resets = { 'init_loc': Vector(const.MOON_INIT_LOCX, const.MOON_INIT_LOCY), 'init_vel': Vector(const.MOON_INIT_VELX, const.MOON_INIT_VELY), 'last_loc': Vector(const.MOON_INIT_LOCX, const.MOON_INIT_LOCY), 'last_vel': Vector(const.MOON_INIT_VELX, const.MOON_INIT_VELY) } # Initialize the simulation objects and the graphics batch. self.graphics_batch = pyglet.graphics.Batch() self.planets = list() self.planets.append( model.planet.Planet(resources.images.planet, locus=Vector(const.PLANET_INIT_LOCX, const.PLANET_INIT_LOCY), batch=self.graphics_batch)) self.moon = model.moon.Moon( images=[resources.images.moon, resources.images.crash_animation], locus=Vector(const.MOON_INIT_LOCX, const.MOON_INIT_LOCY), velocity=Vector(const.MOON_INIT_VELX, const.MOON_INIT_VELY), batch=self.graphics_batch) self.player = model.player.Player( start_img=resources.images.start_button, pause_img=resources.images.pause_button, stop_img=resources.images.stop_button, reset_img=resources.images.reset_button, x=const.MAIN_WIN_WIDTH, y=const.MAIN_WIN_HEIGHT, batch=self.graphics_batch) self.player.x -= self.player.width self.player.y -= self.player.height # Initialize the viewer. self.viewer = view.viewer.Viewer(self) # Connect signals and slots. self.__connect()
def __init__(self, img, locus, mass=1, batch=None): """Initialization. Args: img (image): Sprite graphic for the planet. locus (Vector): Position vector for the planet. mass (float): Relative mass of the planet. batch (pyglet.graphics.Batch): Batch for drawing. """ super().__init__(img=img, batch=batch) self.mass = mass self.__locus = Vector(locus.x, locus.y) self.locus = self.__locus
def move_moon(self, x, y): """Repositions the moon based on bouse input. Args: x (float): New mouse-x coordinate for moon center. y (float): New mouse-y coordinate for moon center. Returns: Nothing. """ if self.simstate in ['paused', 'stopped'] and not self.moon.crashed: self.simmode = 'moving_moon' self.moon.reset(locus=Vector(x, y))
def locus(self, value): """Setter for the locus vector. This method will also update the moon path. """ if len(self.path) // 2 > 0: delta_x = value - Vector(self.path[-2], self.path[-1]) disp = delta_x.mag() else: disp = 0 self.__locus.x = value.x self.__locus.y = value.y self.__adjust_position() if disp >= self.path_segment: self.path.extend((self.__locus.x, self.__locus.y)) if len(self.path) // 2 > self.path_length: self.path = self.path[2:]
def move_arrow(self, x, y): """Changes the velocity of the moon based on mouse input. Args: x (float): Mouse-x coordinate (absolute). y (float): Mouse-y coordinate (absolute). Returns: Nothing. Uses the distance from the mouse point to the center of the moon to determine a new moon velocity using the change_velocity method of the moon object. """ if self.simstate in ['paused', 'stopped'] and not self.moon.crashed: self.simmode = 'moving_arrow' mouse_abs = Vector(x, y) mouse_rel = mouse_abs - self.moon.locus self.moon.change_velocity(mouse_rel)
class Moon(pyglet.sprite.Sprite): """Manages the moon object for the simulation.""" def __init__(self, images, locus, velocity, mass=1, batch=None, path_segment=5, path_length=200): """Initialization. Args: images (list of images): Sprite graphics for the moon. batch (pyglet.graphics.Batch): Batch for drawing. locus (Vector): Initial position vector. velocity (Vector): Initial velocity vector. mass (float): Mass of the moon. path_segment (int): Min length of path segment. path_length (int): Max number of segments in path. """ super().__init__(img=images[0], batch=batch) self.path = [locus.x, locus.y] self.path_segment = path_segment self.path_length = path_length self.images = images self.mass = mass self.__locus = locus self.velocity = velocity self.crashed = False self.__adjust_position() ####################################### # Signals. # These are methods that can be connected to slot methods in another # object to allow communication without dispatching events. If the # signal methods are not connected, they do nothing. def sig_moon_clicked(self): """Emitted when the moon is clicked.""" pass def sig_arrow_clicked(self): """Emitted when the moon velocity arrow is clicked.""" pass ####################################### # Methods. def reset(self, locus=None, velocity=None): """Reset the moon location and velocity. Args: locus (Vector): New moon locus. velocity (Vector): New moon velocity. Returns: Nothing. The locus is centered at the center of the moon sprite. If locus or velocity is None, then no change is made to the corresponding member. """ self.image = self.images[0] self.crashed = False if locus != None: self.locus = locus if velocity != None: self.velocity = velocity self.path = [self.__locus.x, self.__locus.y] def crash(self): """Indicate that the moon has crashed. Args: None. Returns: Nothing. Sets the velocity to (0, 0), changes the sprite image to an explosion and sets the crashed flag to true. """ self.velocity = Vector(0, 0) self.image = self.images[1] self.crashed = True self.__adjust_position() def change_velocity(self, mpos): """Set the velocity based on position of the mouse. Args: mpos (Vector): Vector from moon center to the mouse. Returns: Nothing. """ mdir = mpos.norm() new_vel_mag = mpos.mag() - self.width * const.MOON_ARROW_BASE_SHIFT if new_vel_mag < 0: new_vel_mag = 0 new_vel_mag /= const.MOON_ARROW_LEN_SCALE self.velocity = new_vel_mag * mdir def get_velocity_arrow(self): """Returns the unrotated, untranslated arrow vertices. Args: None. Returns: vertices (tuple of float): Vertices to draw the triangle fan for the velocity arrow. numv (int): Number of vertices. The vertices are determined for the unrotated, untranslated velocity arrow that points from the origin right along the x-axis. The base is positioned correctly versus the moon sprite at the oring. If no arrow is to be drawn, numv = 0. """ # X-pos of start of arrow base. basex = const.MOON_ARROW_BASE_SHIFT * self.width # Dimensions of rectangular part of arrow. xdimbase = const.MOON_ARROW_LEN_SCALE * self.velocity.mag() ydimbase = const.MOON_ARROW_WIDTH_SCALE * self.width if xdimbase < 1: return (), 0 # x-pos of arrow tip. xtip = basex + xdimbase + const.MOON_ARROW_HDX vertices = ( xtip, 0, xtip - const.MOON_ARROW_HDXFULL, -const.MOON_ARROW_HDY / 2, xtip - const.MOON_ARROW_HDX, -ydimbase / 2, basex, -ydimbase / 2, basex, ydimbase / 2, xtip - const.MOON_ARROW_HDX, ydimbase / 2, xtip - const.MOON_ARROW_HDXFULL, const.MOON_ARROW_HDY / 2) numv = 7 return vertices, numv def chk_in_arrow(self, x, y): """Checks whether point is inside the velocity arrow. Args: x (float or int): X-coordinate of the point. y (float or int): Y-coordinate of the point. Returns: bool: True if the point is contained, False if not. The check is accomplished by setting up a bounding rect for the arrow that is aligned along the x-axis pointing to the right. The point is then set relative to the moon and rotated to a corresponding orientation versus the bounding rect along the axis. The model.engine.inrect method is the used to determine containment. """ # Bounding rect for velocity arrow. arrow_rect = Rect() arrow_rect.width = ( const.MOON_ARROW_LEN_SCALE * self.velocity.mag() + const.MOON_ARROW_HDX) arrow_rect.height = const.MOON_ARROW_WIDTH_SCALE * self.width arrow_rect.x = const.MOON_ARROW_BASE_SHIFT * self.width arrow_rect.y = -arrow_rect.height / 2 # Get click position relative to the moon. pos = Vector(x, y) rel_pos = pos - self.__locus # Rotate the relative click position to the new arrow position. ang = -self.velocity.angle_rad() rel_rot_x = rel_pos.x * math.cos(ang) - rel_pos.y * math.sin(ang) rel_rot_y = rel_pos.x * math.sin(ang) + rel_pos.y * math.cos(ang) return model.engine.inrect(rel_rot_x, rel_rot_y, arrow_rect) def click(self, x, y, info): """Route click events on the moon and velocity arrow. Args: x (float or int): X-coordinate of click. y (float or int): Y-coordinate of click. info (string): String indicating routing. Returns: Nothing. This method is a convenience method that does nothing more than take a click event on the moon and its velocity arrow and decompose it depending on whether the click was on the arrow or the moon itself.""" if info == 'moon': self.sig_moon_clicked(x, y) elif info == 'arrow': self.sig_arrow_clicked(x, y) def __adjust_position(self): """Adjust the sprite position based on the locus vector. Args: None. Returns: Nothing. The sprite drawing reference is left/bottom, and the locus vector is center/center. This method corrects the sprite the drawing reference based on the locus vector. """ self.x = self.__locus.x - self.width / 2 self.y = self.__locus.y - self.height / 2 @property def locus(self): """Getter for the locus vector.""" return self.__locus @locus.setter def locus(self, value): """Setter for the locus vector. This method will also update the moon path. """ if len(self.path) // 2 > 0: delta_x = value - Vector(self.path[-2], self.path[-1]) disp = delta_x.mag() else: disp = 0 self.__locus.x = value.x self.__locus.y = value.y self.__adjust_position() if disp >= self.path_segment: self.path.extend((self.__locus.x, self.__locus.y)) if len(self.path) // 2 > self.path_length: self.path = self.path[2:]
class Moon(pyglet.sprite.Sprite): """Manages the moon object for the simulation.""" def __init__(self, images, locus, velocity, mass=1, batch=None, path_segment=5, path_length=200): """Initialization. Args: images (list of images): Sprite graphics for the moon. batch (pyglet.graphics.Batch): Batch for drawing. locus (Vector): Initial position vector. velocity (Vector): Initial velocity vector. mass (float): Mass of the moon. path_segment (int): Min length of path segment. path_length (int): Max number of segments in path. """ super().__init__(img=images[0], batch=batch) self.path = [locus.x, locus.y] self.path_segment = path_segment self.path_length = path_length self.images = images self.mass = mass self.__locus = locus self.velocity = velocity self.crashed = False self.__adjust_position() ####################################### # Signals. # These are methods that can be connected to slot methods in another # object to allow communication without dispatching events. If the # signal methods are not connected, they do nothing. def sig_moon_clicked(self): """Emitted when the moon is clicked.""" pass def sig_arrow_clicked(self): """Emitted when the moon velocity arrow is clicked.""" pass ####################################### # Methods. def reset(self, locus=None, velocity=None): """Reset the moon location and velocity. Args: locus (Vector): New moon locus. velocity (Vector): New moon velocity. Returns: Nothing. The locus is centered at the center of the moon sprite. If locus or velocity is None, then no change is made to the corresponding member. """ self.image = self.images[0] self.crashed = False if locus != None: self.locus = locus if velocity != None: self.velocity = velocity self.path = [self.__locus.x, self.__locus.y] def crash(self): """Indicate that the moon has crashed. Args: None. Returns: Nothing. Sets the velocity to (0, 0), changes the sprite image to an explosion and sets the crashed flag to true. """ self.velocity = Vector(0, 0) self.image = self.images[1] self.crashed = True self.__adjust_position() def change_velocity(self, mpos): """Set the velocity based on position of the mouse. Args: mpos (Vector): Vector from moon center to the mouse. Returns: Nothing. """ mdir = mpos.norm() new_vel_mag = mpos.mag() - self.width * const.MOON_ARROW_BASE_SHIFT if new_vel_mag < 0: new_vel_mag = 0 new_vel_mag /= const.MOON_ARROW_LEN_SCALE self.velocity = new_vel_mag * mdir def get_velocity_arrow(self): """Returns the unrotated, untranslated arrow vertices. Args: None. Returns: vertices (tuple of float): Vertices to draw the triangle fan for the velocity arrow. numv (int): Number of vertices. The vertices are determined for the unrotated, untranslated velocity arrow that points from the origin right along the x-axis. The base is positioned correctly versus the moon sprite at the oring. If no arrow is to be drawn, numv = 0. """ # X-pos of start of arrow base. basex = const.MOON_ARROW_BASE_SHIFT * self.width # Dimensions of rectangular part of arrow. xdimbase = const.MOON_ARROW_LEN_SCALE * self.velocity.mag() ydimbase = const.MOON_ARROW_WIDTH_SCALE * self.width if xdimbase < 1: return (), 0 # x-pos of arrow tip. xtip = basex + xdimbase + const.MOON_ARROW_HDX vertices = (xtip, 0, xtip - const.MOON_ARROW_HDXFULL, -const.MOON_ARROW_HDY / 2, xtip - const.MOON_ARROW_HDX, -ydimbase / 2, basex, -ydimbase / 2, basex, ydimbase / 2, xtip - const.MOON_ARROW_HDX, ydimbase / 2, xtip - const.MOON_ARROW_HDXFULL, const.MOON_ARROW_HDY / 2) numv = 7 return vertices, numv def chk_in_arrow(self, x, y): """Checks whether point is inside the velocity arrow. Args: x (float or int): X-coordinate of the point. y (float or int): Y-coordinate of the point. Returns: bool: True if the point is contained, False if not. The check is accomplished by setting up a bounding rect for the arrow that is aligned along the x-axis pointing to the right. The point is then set relative to the moon and rotated to a corresponding orientation versus the bounding rect along the axis. The model.engine.inrect method is the used to determine containment. """ # Bounding rect for velocity arrow. arrow_rect = Rect() arrow_rect.width = (const.MOON_ARROW_LEN_SCALE * self.velocity.mag() + const.MOON_ARROW_HDX) arrow_rect.height = const.MOON_ARROW_WIDTH_SCALE * self.width arrow_rect.x = const.MOON_ARROW_BASE_SHIFT * self.width arrow_rect.y = -arrow_rect.height / 2 # Get click position relative to the moon. pos = Vector(x, y) rel_pos = pos - self.__locus # Rotate the relative click position to the new arrow position. ang = -self.velocity.angle_rad() rel_rot_x = rel_pos.x * math.cos(ang) - rel_pos.y * math.sin(ang) rel_rot_y = rel_pos.x * math.sin(ang) + rel_pos.y * math.cos(ang) return model.engine.inrect(rel_rot_x, rel_rot_y, arrow_rect) def click(self, x, y, info): """Route click events on the moon and velocity arrow. Args: x (float or int): X-coordinate of click. y (float or int): Y-coordinate of click. info (string): String indicating routing. Returns: Nothing. This method is a convenience method that does nothing more than take a click event on the moon and its velocity arrow and decompose it depending on whether the click was on the arrow or the moon itself.""" if info == 'moon': self.sig_moon_clicked(x, y) elif info == 'arrow': self.sig_arrow_clicked(x, y) def __adjust_position(self): """Adjust the sprite position based on the locus vector. Args: None. Returns: Nothing. The sprite drawing reference is left/bottom, and the locus vector is center/center. This method corrects the sprite the drawing reference based on the locus vector. """ self.x = self.__locus.x - self.width / 2 self.y = self.__locus.y - self.height / 2 @property def locus(self): """Getter for the locus vector.""" return self.__locus @locus.setter def locus(self, value): """Setter for the locus vector. This method will also update the moon path. """ if len(self.path) // 2 > 0: delta_x = value - Vector(self.path[-2], self.path[-1]) disp = delta_x.mag() else: disp = 0 self.__locus.x = value.x self.__locus.y = value.y self.__adjust_position() if disp >= self.path_segment: self.path.extend((self.__locus.x, self.__locus.y)) if len(self.path) // 2 > self.path_length: self.path = self.path[2:]