Posts: 63
Threads: 22
Joined: Aug 2017
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.
Error: Traceback (most recent call last):
File "/home/pi/Documents/Alan/Dev/RocksInSpace/Prototype/v0.10/Python/rocksinspace.py", line 2332, in <module>
TaskManager.process_task_list()
File "/home/pi/Documents/Alan/Dev/RocksInSpace/Prototype/v0.10/Python/clsTaskManager.py", line 102, in process_task_list
cls.process_task_queue(tl)
File "/home/pi/Documents/Alan/Dev/RocksInSpace/Prototype/v0.10/Python/clsTaskManager.py", line 120, in process_task_queue
q.linked_routine(q)
File "/home/pi/Documents/Alan/Dev/RocksInSpace/Prototype/v0.10/Python/clsAutopilot.py", line 95, in _autopilot_point_craft_in_oaf
self._autopilot_turn_to_angle(obj, update_task_status)
File "/home/pi/Documents/Alan/Dev/RocksInSpace/Prototype/v0.10/Python/clsAutopilot.py", line 269, in _autopilot_turn_to_angle
so_dupl =copy.deepcopy(so)
File "/usr/lib/python3.4/copy.py", line 182, in deepcopy
y = _reconstruct(x, rv, 1, memo)
File "/usr/lib/python3.4/copy.py", line 300, in _reconstruct
state = deepcopy(state, memo)
File "/usr/lib/python3.4/copy.py", line 155, in deepcopy
y = copier(x, memo)
File "/usr/lib/python3.4/copy.py", line 246, in _deepcopy_dict
y[deepcopy(key, memo)] = deepcopy(value, memo)
File "/usr/lib/python3.4/copy.py", line 182, in deepcopy
y = _reconstruct(x, rv, 1, memo)
File "/usr/lib/python3.4/copy.py", line 295, in _reconstruct
y = callable(*args)
File "/usr/lib/python3.4/copyreg.py", line 88, in __newobj__
return cls.__new__(cls, *args)
TypeError: object.__new__(pygame.mask.Mask) is not safe, use pygame.mask.Mask.__new__()
Posts: 5,151
Threads: 396
Joined: Sep 2016
Aug-05-2018, 01:15 PM
(This post was last modified: Aug-05-2018, 01:16 PM by metulburr.)
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
Recommended Tutorials:
Posts: 544
Threads: 15
Joined: Oct 2016
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)
99 percent of computer problems exists between chair and keyboard.
Posts: 63
Threads: 22
Joined: Aug 2017
(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.
Posts: 5,151
Threads: 396
Joined: Sep 2016
Aug-05-2018, 03:31 PM
(This post was last modified: Aug-05-2018, 03:31 PM by metulburr.)
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...et/tank.py
https://github.com/Mekire/pygame-samples...animate.py
Recommended Tutorials:
Posts: 5,151
Threads: 396
Joined: Sep 2016
Aug-05-2018, 06:38 PM
(This post was last modified: Aug-05-2018, 06:38 PM by metulburr.)
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.
Recommended Tutorials:
Posts: 544
Threads: 15
Joined: Oct 2016
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()
99 percent of computer problems exists between chair and keyboard.
Posts: 63
Threads: 22
Joined: Aug 2017
Nice one, thanks for the examples and tips.
Posts: 544
Threads: 15
Joined: Oct 2016
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()
99 percent of computer problems exists between chair and keyboard.
|