How to copy an object - Printable Version +- Python Forum (https://python-forum.io) +-- Forum: Python Coding (https://python-forum.io/forum-7.html) +--- Forum: Game Development (https://python-forum.io/forum-11.html) +--- Thread: How to copy an object (/thread-12008.html) |
How to copy an object - microphone_head - Aug-05-2018 Hi members, Does anyone know how to do a deep copy (copy.deepcopy) with pygame? I'm having trouble performing a deep copy of an object (a class instance ?). The problem seems to stem from the fact that its Parent is from the pygame.sprite (but that's just a guess). I thought I would check here first because I think someone else must have come across this. Its advising me to use pygame to do this. PS. I don't need to carry across any of the images in the copy operation.
RE: How to copy an object - metulburr - Aug-05-2018 What is your purpose in deepcopying the object in the first place? From the error it seems you might be copying an object to rotate it, which would be overkill to handle such a task RE: How to copy an object - Windspar - Aug-05-2018 If you deepcopy anything. It copies everything. Personal I never use pygame sprites class. Example. class Ship # class instance. There be only one. doesn't matter how many objects you make. image = # load ship image def __init__(self): self.image = pygame.transform.rotate(Ship.image, angle) class Rock: image = # load rock image def __init__(self): self.image = pygame.transform.rotate(Rock.image, angle) RE: How to copy an object - microphone_head - Aug-05-2018 (Aug-05-2018, 01:15 PM)metulburr Wrote: What is your purpose in deepcopying the object in the first place? From the error it seems you might be copying an object to rotate it, which would be overkill to handle such a task I'm working with a class based on the pygame.sprite, and working on a task that involved simulating an autopilot program that kicks in when the craft strays to far off the screen. I have a routine that predicts the maximum speed the craft can turn without missing and over shooting the target angle. I thought working on a copy of the object would be the easiest way. Performing a shallow copy means I have to treat the object differently. RE: How to copy an object - metulburr - Aug-05-2018 You shouldnt need to copy an object to rotate it at all. The only trick is to keep the original untainted. An example of rotation is given in the post above by Windspar. And it doesnt have nor need any copy (deep or shallow) in it at all. self.image = pygame.transform.rotate(original_image, angle)This rotates self.image to the specified angle. You just keep recreating self.image with a new angle as it rotates from the same unmodified original_image. Here is a full fledged workable examples https://github.com/Mekire/pygame-samples/blob/master/tank_turret/tank.py https://github.com/Mekire/pygame-samples/blob/master/rotation_animation/rotate_animate.py RE: How to copy an object - metulburr - Aug-05-2018 Please leave conversation in the forums so future searchers can benefit from it as well. If you really dont want to handle it at runtime, you can always do the same and save the 360 degrees of animated objects in a list and then display the proper one accordingly. But python is plenty fast enough to not have to worry about speed until there is an actual problem. And most bottlenecks are a result of poor programming than python's speed, if that is what your thinking. RE: How to copy an object - Windspar - Aug-05-2018 I always avoid sprite class. Example how I handle Sprite. import pygame import random pygame.init() class Point: @classmethod def rnd(cls, min_size, max_size): return cls( random.randint(min_size, max_size), random.randint(min_size, max_size)) def __init__(self, x, y): self.x = x self.y = y def tup(self): return self.x, self.y def __add__(self, rhs): if isinstance(rhs, Point): return Point(self.x + rhs.x, self.y + rhs.y) elif isinstance(rhs, (int, float)): return Point(self.x + rhs, self.y + rhs) def __sub__(self, rhs): if isinstance(rhs, Point): return Point(self.x - rhs.x, self.y - rhs.y) elif isinstance(rhs, (int, float)): return Point(self.x - rhs, self.y - rhs) def __mul__(self, rhs): if isinstance(rhs, Point): return Point(self.x * rhs.x, self.y * rhs.y) elif isinstance(rhs, (int, float)): return Point(self.x * rhs, self.y * rhs) def __str__(self): return "Point({0}, {1})".format(self.x, self.y) class TickTimer: ticks = 0 @classmethod def tick(cls): cls.ticks = pygame.time.get_ticks() def __init__(self, interval): self.interval = interval self.next_tick = TickTimer.ticks + interval def elapse(self): if TickTimer.ticks > self.next_tick: self.next_tick += self.interval if TickTimer.ticks > self.next_tick: self.next_tick = TickTimer.ticks + self.interval return True return False class Rock: rocks = [] @staticmethod def create_image(size, color): image = pygame.Surface((size, size)) image = image.convert_alpha() image.fill((0,0,0,0)) pygame.draw.rect(image, color, (1,1,size - 1,size - 1)) return image @classmethod def load(cls): cls.images = [ cls.create_image(10, (0,200,0)), cls.create_image(20, (0,0,200)), cls.create_image(30, (200,0,200))] @classmethod def update(cls, surface): alive_rocks = [] for rock in cls.rocks: if rock.alive: rock.draw(surface) alive_rocks.append(rock) cls.rocks = alive_rocks def __init__(self, position, angle, direction, size=2, rotation=1): self.image = pygame.transform.rotate(Rock.images[size], angle) self.size = size self.position = position self.direction = direction self.rect = self.image.get_rect() self.rect.topleft = position.tup() self.angle = angle self.rotation = rotation self.rotation_timer = TickTimer(40) self.timer = TickTimer(20) Rock.rocks.append(self) self.alive = True def copy(self): if self.size > 0: return Rock( self.position, self.angle, self.direction, self.size - 1, self.rotation) return None def draw(self, surface): if self.alive: if self.rotation_timer.elapse(): self.angle += self.rotation self.angle %= 360 self.image = pygame.transform.rotate(Rock.images[self.size], self.angle) rect = self.image.get_rect() rect.center = self.rect.center point = Point(*self.rect.topleft) - Point(*rect.topleft) self.position -= point self.rect = rect if self.timer.elapse(): self.position += self.direction self.rect.x = int(self.position.x) self.rect.y = int(self.position.y) clamp = self.rect.clamp(Screen.rect) if clamp.x != self.rect.x: self.direction.x = -self.direction.x self.position.x = clamp.x if clamp.y != self.rect.y: self.direction.y = -self.direction.y self.position.y = clamp.y self.rect = clamp surface.blit(self.image, self.rect) class Screen: rect = pygame.Rect(0,0,800,600) clock = pygame.time.Clock() surface = pygame.display.set_mode(rect.size) @classmethod def loop(cls, fps=30): cls.running = True while cls.running: for event in pygame.event.get(): if event.type == pygame.QUIT: cls.running = False cls.surface.fill((0,0,0)) TickTimer.tick() Rock.update(cls.surface) pygame.display.flip() pygame.quit() def main(): Rock.load() for i in range(5): Rock( Point.rnd(1, 770), random.randint(0, 360), Point.rnd(-200, 200) * 0.03, 2, random.choice([-2, 2])) Screen.loop() main() RE: How to copy an object - microphone_head - Aug-05-2018 Nice one, thanks for the examples and tips. RE: How to copy an object - Windspar - Aug-05-2018 Improve Example. They randomly blow up. import pygame import random pygame.init() class Point: @classmethod def rnd(cls, min_size, max_size): return cls( random.randint(min_size, max_size), random.randint(min_size, max_size)) def __init__(self, x, y): self.x = x self.y = y def tup(self): return self.x, self.y def __add__(self, rhs): if isinstance(rhs, Point): return Point(self.x + rhs.x, self.y + rhs.y) elif isinstance(rhs, (int, float)): return Point(self.x + rhs, self.y + rhs) def __sub__(self, rhs): if isinstance(rhs, Point): return Point(self.x - rhs.x, self.y - rhs.y) elif isinstance(rhs, (int, float)): return Point(self.x - rhs, self.y - rhs) def __mul__(self, rhs): if isinstance(rhs, Point): return Point(self.x * rhs.x, self.y * rhs.y) elif isinstance(rhs, (int, float)): return Point(self.x * rhs, self.y * rhs) def __str__(self): return "Point({0}, {1})".format(self.x, self.y) class TickTimer: ticks = 0 @classmethod def tick(cls): cls.ticks = pygame.time.get_ticks() def __init__(self, interval): self.interval = interval self.next_tick = TickTimer.ticks + interval def elapse(self): if TickTimer.ticks > self.next_tick: self.next_tick += self.interval if TickTimer.ticks > self.next_tick: self.next_tick = TickTimer.ticks + self.interval return True return False class Rock: rocks = [] @staticmethod def get_direction(size): speed = [150, 100, 50][size] value_x = random.randint(speed - 25, speed) * 0.02 if random.choice([False, True]): value_x = -value_x value_y = random.randint(speed - 25, speed) * 0.02 if random.choice([False, True]): value_y = -value_y return Point(value_x, value_y) @staticmethod def create_image(size, color): image = pygame.Surface((size, size)) image = image.convert_alpha() image.fill((0,0,0,0)) pygame.draw.rect(image, color, (1,1,size - 1,size - 1)) return image @classmethod def load(cls): cls.images = [ cls.create_image(10, (0,200,0)), cls.create_image(20, (0,0,200)), cls.create_image(30, (200,0,200))] @classmethod def update(cls, surface): alive_rocks = [] for rock in cls.rocks: if rock.alive: rock.draw(surface) alive_rocks.append(rock) if random.randint(1, 200) == 1: rock.alive = False if rock.size > 0: for i in range(2): alive_rocks.append(rock.copy()) cls.rocks = alive_rocks if len(cls.rocks) < 5: Rock( Point.rnd(1, 770), random.randint(0, 360), Rock.get_direction(2), 2, random.choice([-2, 2])) def __init__(self, position, angle, direction, size=2, rotation=1, add_rock=True): self.image = pygame.transform.rotate(Rock.images[size], angle) self.size = size self.position = position self.direction = direction self.rect = self.image.get_rect() self.rect.topleft = position.tup() self.angle = angle self.rotation = rotation self.rotation_timer = TickTimer(40) self.timer = TickTimer(20) self.alive = True if add_rock: Rock.rocks.append(self) def copy(self): if self.size > 0: return Rock( self.position, self.angle, Rock.get_direction(self.size - 1), self.size - 1, self.rotation, False) return None def draw(self, surface): if self.alive: if self.rotation_timer.elapse(): self.angle += self.rotation self.angle %= 360 self.image = pygame.transform.rotate(Rock.images[self.size], self.angle) rect = self.image.get_rect() rect.center = self.rect.center point = Point(*self.rect.topleft) - Point(*rect.topleft) self.position -= point self.rect = rect if self.timer.elapse(): self.position += self.direction self.rect.x = int(self.position.x) self.rect.y = int(self.position.y) clamp = self.rect.clamp(Screen.rect) if clamp.x != self.rect.x: self.direction.x = -self.direction.x self.position.x = clamp.x if clamp.y != self.rect.y: self.direction.y = -self.direction.y self.position.y = clamp.y self.rect = clamp surface.blit(self.image, self.rect) class Screen: rect = pygame.Rect(0,0,800,600) clock = pygame.time.Clock() surface = pygame.display.set_mode(rect.size) @classmethod def loop(cls, fps=30): cls.running = True while cls.running: for event in pygame.event.get(): if event.type == pygame.QUIT: cls.running = False cls.surface.fill((0,0,0)) TickTimer.tick() Rock.update(cls.surface) pygame.display.flip() cls.clock.tick(fps) pygame.quit() def main(): Rock.load() for i in range(5): Rock( Point.rnd(1, 770), random.randint(0, 360), Rock.get_direction(2), 2, random.choice([-2, 2])) Screen.loop() main() |