|
- '''
- Filename nodes.py
- Author: Bryan "ObsidianBlk" Miller
- Date Created: 8/1/2018
- Python Version: 3.7
- '''
-
- from .display import Display
- from .events import Events
- from .resource import ResourceManager
- import pygame
-
-
- class NodeError(Exception):
- pass
-
-
- class Node:
- def __init__(self, name="Node", parent=None):
- self._NODE_DATA={
- "parent":None,
- "name":name,
- "children":[],
- "resource":None,
- "position":(0,0)
- }
- if parent is not None:
- try:
- self.parent = parent
- except NodeError as e:
- raise e
-
- @property
- def parent(self):
- return self._NODE_DATA["parent"]
-
- @parent.setter
- def parent(self, new_parent):
- try:
- self.parent_to_node(new_parent)
- except NodeError as e:
- raise e
-
- @property
- def root(self):
- if self.parent is None:
- return self
- return self.parent.root
-
- @property
- def name(self):
- return self._NODE_DATA["name"]
-
- @name.setter
- def name(self, value):
- if self.parent is not None:
- if self.parent.get_node(value) is not None:
- raise NodeError("Parent already contains node named '{}'.".format(name))
- self._NODE_DATA["name"] = value
-
- @property
- def full_name(self):
- if self.parent is None:
- return self.name
- return self.parent.full_name + "." + self.name
-
- @property
- def resource(self):
- if self._NODE_DATA["resource"] is None:
- # Only bother creating the instance if it's being asked for.
- # All ResourceManager instances access same data.
- self._NODE_DATA["resource"] = ResourceManager()
- return self._NODE_DATA["resource"]
-
- @property
- def child_count(self):
- return len(self._NODE_DATA["children"])
-
- @property
- def position(self):
- p = self._NODE_DATA["position"]
- return (p[0], p[1])
- @position.setter
- def position(self, pos):
- if not isinstance(pos, (list, tuple)):
- raise TypeError("Expected a list or tuple.")
- if len(pos) != 2:
- raise ValueError("Wrong number of values given.")
- try:
- self.position_x = pos[0]
- self.position_y = pos[1]
- except Exception as e:
- raise e
-
- @property
- def position_x(self):
- return self._NODE_DATA["position"][0]
- @position_x.setter
- def position_x(self, v):
- if not isinstance(v, (int, float)):
- raise TypeError("Excepted an number value.")
- self._NODE_DATA["position"] = (float(v), self._NODE_DATA["position"][1])
-
- @property
- def position_y(self):
- return self._NODE_DATA["position"][1]
- @position_y.setter
- def position_y(self, v):
- if not isinstance(v, (int, float)):
- raise TypeError("Excepted an number value.")
- self._NODE_DATA["position"] = (self._NODE_DATA["position"][0], float(v))
-
-
- def get_world_position(self):
- if self.parent is None:
- return (0,0)
- pos = self.position
- ppos = self.parent.get_world_position()
- return (pos[0] + ppos[0], pos[1] + ppos[1])
-
- def parent_to_node(self, parent, allow_reparenting=False):
- if not isinstance(parent, Node):
- raise NodeError("Node may only parent to another Node instance.")
- if self.parent is None or self.parent != parent:
- if self.parent is not None:
- if allow_Reparenting == False:
- raise NodeError("Node already assigned a parent Node.")
- if self.parent.remove_node(self) != self:
- raise NodeError("Failed to remove self from current parent.")
- try:
- parent.attach_node(self)
- except NodeError as e:
- raise e
-
-
- def attach_node(self, node, reparent=False, index=-1):
- if node.parent is not None:
- if node.parent == self:
- return # Nothing to do. Given node already parented to this node.
- if reparent == False:
- raise NodeError("Node already parented.")
- if node.parent.remove_node(node) != node:
- raise NodeError("Failed to remove given node from it's current parent.")
- if self.get_node(node.name) is not None:
- raise NodeError("Node with name '{}' already attached.".format(node.name))
- node._NODE_DATA["parent"] = self
- children = self._NODE_DATA["children"]
- if index < 0 or index >= len(children):
- children.append(node)
- else:
- children.insert(index, node)
-
- def remove_node(self, node):
- if isinstance(node, (str, unicode)):
- n = self.get_node(node)
- if n is not None:
- try:
- return self.remove_node(n)
- except NodeError as e:
- raise e
- elif isinstance(node, Node):
- if node.parent != self:
- if node.parent == None:
- raise NodeError("Cannot remove an unparented node.")
- try:
- return node.parent.remove_node(node)
- except NodeError as e:
- raise e
- if node in self._NODE_DATA["children"]:
- self._NODE_DATA["children"].remove(node)
- node._NODE_DATA["parent"] = None
- return node
- else:
- raise NodeError("Expected a Node instance or a string.")
- return None
-
-
- def get_node(self, name):
- if self.child_count <= 0:
- return None
-
- subnames = name.split(".")
- for c in self._NODE_DATA["children"]:
- if c.name == subnames[0]:
- if len(subnames) > 1:
- return c.get_node(".".join(subnames[1:-1]))
- return c
- return None
-
- def listen(self, signal, callback_fn):
- try:
- Events.listen(signal, callback_fn)
- except Exception as e:
- raise e
-
- def unlisten(self, signal, callback_fn):
- Events.unlisten(signal, callback_fn)
-
- def emit(self, signal, data={}):
- # NOTE: I'm currently forcing the existance of this "NODE" key in the dictionary given. Not sure if I'll keep this.
- data["NODE"] = {
- "name":self.name,
- "n":self
- }
- Events.emit(signal, data)
-
- def _init(self):
- if hasattr(self, "on_init"):
- self.on_init()
- for c in self._NODE_DATA["children"]:
- c._init()
-
- def _close(self):
- if hasattr(self, "on_close"):
- self.on_close()
- for c in self._NODE_DATA["children"]:
- c._close()
-
- def _pause(self):
- if hasattr(self, "on_pause"):
- self.on_pause()
- for c in self._NODE_DATA["children"]:
- c._pause()
-
- def _start(self):
- if hasattr(self, "on_start"):
- self.on_start()
- for c in self._NODE_DATA["children"]:
- c._start()
-
- def _update(self, dt):
- if hasattr(self, "on_update"):
- self.on_update(dt)
-
- for c in self._NODE_DATA["children"]:
- c._update(dt)
-
- def _render(self, surface):
- for c in self._NODE_DATA["children"]:
- c._render(surface)
-
-
-
-
- class Node2D(Node):
- def __init__(self, name="Node2D", parent=None):
- try:
- Node.__init__(self, name, parent)
- except NodeError as e:
- raise e
- self._NODE2D_DATA = {
- "visible":True
- }
-
- @property
- def resolution(self):
- p = self.parent
- # We don't directly have the answer, but maybe our parent does?
- if p is not None:
- if hasattr(p, "resolution"):
- return p.resolution
- # Otherwise the Display object should.
- return Display.resolution
-
- @property
- def visible(self):
- return self._NODE2D_DATA["visible"]
- @visible.setter
- def visible(self, vis):
- self._NODE2D_DATA["visible"] = (vis == True)
-
- def _callOnRender(self, surface):
- if hasattr(self, "on_render"):
- self._ACTIVE_SURF = surface
- self.on_render()
- del self._ACTIVE_SURF
-
- def _render(self, surface):
- if self._NODE2D_DATA["visible"] == True:
- self._callOnRender(surface)
- Node._render(self, surface)
-
- def draw_image(self, img, pos=(0,0), rect=None):
- if not hasattr(self, "_ACTIVE_SURF"):
- return
- self._ACTIVE_SURF.blit(img, pos, rect)
-
- def fill(self, color):
- if not hasattr(self, "_ACTIVE_SURF"):
- return
- self._ACTIVE_SURF.fill(color)
-
- def draw_lines(self, points, color, thickness=1, closed=False):
- if not hasattr(self, "_ACTIVE_SURF"):
- return
- pygame.draw.lines(self._ACTIVE_SURF, color, closed, points, thickness)
-
- def draw_rect(self, rect, color, thickness=1, fill_color=None):
- if not hasattr(self, "_ACTIVE_SURF"):
- return
- if fill_color is not None:
- self._ACTIVE_SURF.fill(fill_color, rect)
- if thickness > 0:
- pygame.draw.rect(self._ACTIVE_SURF, color, rect, thickness)
-
- def draw_ellipse(self, rect, color, thickness=1, fill_color=None):
- if not hasattr(self, "_ACTIVE_SURF"):
- return
- if fill_color is not None:
- pygame.draw.ellipse(self._ACTIVE_SURF, fill_color, rect)
- if thickness > 0:
- pygame.draw.ellipse(self._ACTIVE_SURF, color, rect, thickness)
-
- def draw_circle(self, pos, radius, color, thickness=1, fill_color=None):
- if not hasattr(self, "_ACTIVE_SURF"):
- return
- if fill_color is not None:
- pygame.draw.circle(self._ACTIVE_SURF, fill_color, pos, radius)
- if thickness > 0:
- pygame.draw.circle(self._ACTIVE_SURF, color, pos, radius, thickness)
-
- def draw_polygon(self, points, color, thickness=1, fill_color=None):
- if not hasattr(self, "_ACTIVE_SURF"):
- return
- if fill_color is not None:
- pygame.draw.polygon(self._ACTIVE_SURF, fill_color, points)
- if thickness >= 1:
- pygame.draw.polygon(self._ACTIVE_SURF, color, points, thickness)
-
-
-
-
- class NodeSurface(Node2D):
- def __init__(self, name="NodeSurface", parent=None):
- try:
- Node2D.__init__(self, name, parent)
- except NodeError as e:
- raise e
- # TODO: Update this class to use the _NODE*_DATA={} structure.
- self._NODESURFACE_DATA={
- "clear_color":None
- }
- self._scale = (1.0, 1.0)
- self._scaleToDisplay = False
- self._scaleDirty = False
- self._keepAspectRatio = False
- self._alignCenter = False
- self._surface = None
- self._tsurface = None
- self.set_surface()
-
- def _updateTransformSurface(self):
- if self._surface is None:
- return
-
- self._scaleDirty = False
- if self._scaleToDisplay:
- dsize = Display.resolution
- ssize = self._surface.get_size()
- self._scale = (dsize[0] / ssize[0], dsize[1] / ssize[1])
- if self._keepAspectRatio:
- if self._scale[0] < self._scale[1]:
- self._scale = (self._scale[0], self._scale[0])
- else:
- self._scale = (self._scale[1], self._scale[1])
-
- if self._scale[0] == 1.0 and self._scale[1] == 1.0:
- self._tsurface = None
- return
- size = self._surface.get_size()
- nw = size[0] * self._scale[0]
- nh = 0
- if self._keepAspectRatio:
- nh = size[1] * self._scale[0]
- else:
- nh = size[1] * self._scale[1]
- self._tsurface = pygame.Surface((nw, nh), pygame.SRCALPHA, self._surface)
- self._tsurface.fill(pygame.Color(0,0,0,0))
-
- @property
- def resolution(self):
- if self._surface is None:
- return super().resolution
- return self._surface.get_size()
- @resolution.setter
- def resolution(self, res):
- try:
- self.set_surface(res)
- except (TypeError, ValueError) as e:
- raise e
-
- @property
- def width(self):
- return self.resolution[0]
-
- @property
- def height(self):
- return self.resolution[1]
-
- @property
- def scale(self):
- return self._scale
- @scale.setter
- def scale(self, scale):
- if self._keepAspectRatio:
- if not isinstance(scale, (int, float)):
- raise TypeError("Expected number value.")
- self._scale = (scale, self._scale[1])
- else:
- if not isinstance(scale, tuple):
- raise TypeError("Expected a tuple")
- if len(scale) != 2:
- raise ValueError("Expected tuple of length two.")
- if not isinstance(scale[0], (int, float)) or not isinstance(scale[1], (int, float)):
- raise TypeError("Expected number values.")
- self._scale = scale
- self._updateTransformSurface()
-
- @property
- def keep_aspect_ratio(self):
- return self._keepAspectRatio
- @keep_aspect_ratio.setter
- def keep_aspect_ratio(self, keep):
- self._keepAspectRatio = (keep == True)
- self._updateTransformSurface()
-
- @property
- def align_center(self):
- return self._alignCenter
- @align_center.setter
- def align_center(self, center):
- self._alignCenter = (center == True)
-
- @property
- def scale_to_display(self):
- return self._scaleToDisplay
- @scale_to_display.setter
- def scale_to_display(self, todisplay):
- if todisplay == True:
- self._scaleToDisplay = True
- Events.listen("VIDEORESIZE", self._OnVideoResize)
- else:
- self._scaleToDisplay = False
- Events.unlisten("VIDEORESIZE", self._OnVideoResize)
- self._updateTransformSurface()
-
- def scale_to(self, target_resolution):
- if self._surface is not None:
- size = self._surface.get_size()
- nscale = (float(size[0]) / float(target_resolution[0]), float(size[1]) / float(target_resolution[1]))
- self.scale = nscale
-
-
- def set_surface(self, resolution=None):
- dsurf = Display.surface
- if resolution is None:
- if dsurf is not None:
- self._surface = dsurf.convert_alpha()
- self._surface.fill(pygame.Color(0,0,0,0))
- self._updateTransformSurface()
- else:
- if not isinstance(resolution, tuple):
- raise TypeError("Expected a tuple.")
- if len(resolution) != 2:
- raise ValueError("Expected a tuple of length two.")
- if not isinstance(resolution[0], int) or not isinstance(resolution[1], int):
- raise TypeError("Tuple expected to contain integers.")
- if dsurf is not None:
- self._surface = pygame.Surface(resolution, pygame.SRCALPHA, dsurf)
- else:
- self._surface = pygame.Surface(resolution, pygame.SRCALPHA)
- self._surface.fill(pygame.Color(0,0,0,0))
- self._updateTransformSurface()
-
- def set_clear_color(self, color):
- if color is None:
- self._NODESURFACE_DATA["clear_color"] = None
- elif isinstance(color, (list, tuple)):
- clen = len(color)
- if clen == 3 or clen == 4:
- iscolor = lambda v: isinstance(v, int) and v >= 0 and v < 256
-
- if iscolor(color[0]) and iscolor(color[1]) and iscolor(color[2]):
- if clen == 3 or (clen == 4 and iscolor(color[3])):
- self._NODESURFACE_DATA["clear_color"] = pygame.Color(*color)
-
- def get_clear_color(self):
- cc = self._NODESURFACE_DATA["clear_color"]
- if cc == None:
- return None
- return (cc.r, cc.g, cc.b, cc.a)
-
- def _render(self, surface):
- if self.visible == False:
- return
-
- if self._surface is None:
- self.set_surface()
- if self._surface is not None:
- if self._scaleDirty:
- self._updateTransformSurface()
- cc = self._NODESURFACE_DATA["clear_color"]
- if cc is not None:
- self._surface.fill(cc)
- Node2D._render(self, self._surface)
- else:
- Node2D._render(self, surface)
- self._scale_and_blit(surface)
-
-
- def _scale_and_blit(self, dest):
- dsize = dest.get_size()
-
- src = self._surface
- if self._tsurface is not None:
- pygame.transform.scale(self._surface, self._tsurface.get_size(), self._tsurface)
- src = self._tsurface
-
- ssize = src.get_size()
- posx = self.position_x
- posy = self.position_y
- if self._alignCenter:
- if dsize[0] > ssize[0]:
- posx += (dsize[0] - ssize[0]) * 0.5
- if dsize[1] > ssize[1]:
- posy += (dsize[1] - ssize[1]) * 0.5
- pos = (int(posx), int(posy))
- dest.blit(src, pos)
-
- def _OnVideoResize(self, event, data):
- if self._scaleToDisplay:
- self._scaleDirty = True
-
-
- class NodeText(Node2D):
- def __init__(self, name="NodeText", parent=None):
- try:
- Node2D.__init__(self, name, parent)
- except NodeError as e:
- raise e
- self._NODETEXT_DATA={
- "font_src":"",
- "size":26,
- "antialias":True,
- "color":pygame.Color(255,255,255),
- "background":None,
- "text":"Some Text",
- "surface":None
- }
-
- @property
- def font_src(self):
- return self._NODETEXT_DATA["font_src"]
- @font_src.setter
- def font_src(self, src):
- res = self.resource
- if src != "" and src != self._NODETEXT_DATA["font_src"] and res.is_valid("font", src):
- self._NODETEXT_DATA["font_src"] = src
- if not res.has("font", src):
- res.store("font", src)
- self._NODETEXT_DATA["surface"] = None
-
- @property
- def size(self):
- return self._NODETEXT_DATA["size"]
- @size.setter
- def size(self, size):
- if not isinstance(size, int):
- raise TypeError("Expected integer value.")
- if size <= 0:
- raise ValueError("Size must be greater than zero.")
- if size != self._NODETEXT_DATA["size"]:
- self._NODETEXT_DATA["size"] = size
- self._NODETEXT_DATA["surface"] = None
-
- @property
- def antialias(self):
- return self._NODETEXT_DATA["antialias"]
- @antialias.setter
- def antialias(self, enable):
- enable = (enable == True)
- if enable != self._NODETEXT_DATA["antialias"]:
- self._NODETEXT_DATA["antialias"] = enable
- self._NODETEXT_DATA["surface"] = None
-
- @property
- def text(self):
- return self._NODETEXT_DATA["text"]
- @text.setter
- def text(self, text):
- if text != self._NODETEXT_DATA["text"]:
- self._NODETEXT_DATA["text"] = text
- self._NODETEXT_DATA["surface"] = None
-
- def _setColor(self, cname, r, g, b, a):
- if r < 0 or r > 255:
- raise ValueError("Red value out of bounds.")
- if g < 0 or g > 255:
- raise ValueError("Green value out of bounds.")
- if b < 0 or b > 255:
- raise ValueError("Blue value out of bounds.")
- if a < 0 or a > 255:
- raise ValueError("Alpha value out of bounds.")
- color = self._NODETEXT_DATA[cname]
- if color is None or color.r != r or color.g != g or color.b != b or color.a != a:
- self._NODETEXT_DATA[cname] = pygame.Color(r,g,b,a)
- self._NODETEXT_DATA["surface"] = None
-
- def _getColor(self, cname):
- if self._NODETEXT_DATA[cname] is None:
- return (0,0,0,0)
- else:
- c = self._NODETEXT_DATA[cname]
- return (c.r, c.g, c.b, c.a)
-
- def set_color(self, r, g, b, a=255):
- try:
- self._setColor("color", r, g, b, a)
- except ValueError as e:
- raise e
- return self
-
- def get_color(self):
- return self._getColor("color")
-
- def set_background(self, r, g, b, a=255):
- try:
- self._setColor("background", r, g, b, a)
- except ValueError as e:
- raise e
- return self
-
- def clear_background(self):
- if self._NODETEXT_DATA["background"] is not None:
- self._NODETEXT_DATA["background"] = None
- self._NODETEXT_DATA["surface"] = None
- return self
-
- def get_background(self):
- c = self._getColor("background")
- if c[3] <= 0:
- return None
- return c
-
-
- def _render(self, surface):
- if self.visible == False:
- return
-
- if self._NODETEXT_DATA["surface"] is None and self._NODETEXT_DATA["text"] != "":
- res = self.resource
- fnt = res.get("font", self._NODETEXT_DATA["font_src"], {"size":self._NODETEXT_DATA["size"]})
- if fnt is not None and fnt() is not None:
- surf = None
- try:
- text = self.text
- antialias = self.antialias
- color = self._NODETEXT_DATA["color"]
- background = self._NODETEXT_DATA["background"]
- surf = fnt().render(text, antialias, color, background)
- except pygame.error as e:
- pass # TODO: Update to send out warning!
- self._NODETEXT_DATA["surface"] = surf
- # We really don't want to keep the font instance around... just in case we want to use the same font at different sizes.
- res.clear("font", self._NODETEXT_DATA["font_src"])
- Node2D._render(self, surface)
- if self._NODETEXT_DATA["surface"] is not None:
- pos = self.get_world_position()
- pos = (int(pos[0]), int(pos[1]))
- surface.blit(self._NODETEXT_DATA["surface"], pos)
-
-
-
- class NodeSprite(Node2D):
- def __init__(self, name="NodeSprite", parent=None):
- try:
- Node2D.__init__(self, name, parent)
- except NodeError as e:
- raise e
- self._NODESPRITE_DATA={
- "rect":[0,0,0,0],
- "image":"",
- "scale":[1.0, 1.0],
- "scale_dirty":True,
- "surface":None
- }
-
- @property
- def image_width(self):
- if self._NODESPRITE_DATA["surface"] is None:
- return 0
- surf = self._NODESPRITE_DATA["surface"]()
- return surf.get_width()
-
- @property
- def image_height(self):
- if self._NODESPRITE_DATA["surface"] is None:
- return 0
- surf = self._NODESPRITE_DATA["surface"]()
- return surf.get_height()
-
- @property
- def sprite_width(self):
- return int(self.rect_width * self.scale_x)
-
- @property
- def sprite_height(self):
- return int(self.rect_height * self.scale_y)
-
- @property
- def rect(self):
- return (self._NODESPRITE_DATA["rect"][0],
- self._NODESPRITE_DATA["rect"][1],
- self._NODESPRITE_DATA["rect"][2],
- self._NODESPRITE_DATA["rect"][3])
-
- @rect.setter
- def rect(self, rect):
- if not isinstance(rect, (list, tuple)):
- raise TypeError("Expected a list or tuple.")
- if len(rect) != 4:
- raise ValueError("rect value contains wrong number of values.")
- try:
- self.rect_x = rect[0]
- self.rect_y = rect[1]
- self.rect_width = rect[2]
- self.rect_height = rect[3]
- except Exception as e:
- raise e
-
- @property
- def rect_x(self):
- return self._NODESPRITE_DATA["rect"][0]
- @rect_x.setter
- def rect_x(self, v):
- if not isinstance(v, int):
- raise TypeError("Expected integer value.")
- self._NODESPRITE_DATA["rect"][0] = v
- self._NODESPRITE_ValidateRect()
-
- @property
- def rect_y(self):
- return self._NODESPRITE_DATA["rect"][1]
- @rect_y.setter
- def rect_y(self, v):
- if not isinstance(v, int):
- raise TypeError("Expected integer value.")
- self._NODESPRITE_DATA["rect"][1] = v
- self._NODESPRITE_ValidateRect()
-
-
- @property
- def rect_width(self):
- return self._NODESPRITE_DATA["rect"][2]
- @rect_width.setter
- def rect_width(self, v):
- if not isinstance(v, int):
- raise TypeError("Expected integer value.")
- self._NODESPRITE_DATA["rect"][2] = v
- self._NODESPRITE_ValidateRect()
-
-
- @property
- def rect_height(self):
- return self._NODESPRITE_DATA["rect"][3]
- @rect_height.setter
- def rect_height(self, v):
- if not isinstance(v, int):
- raise TypeError("Expected integer value.")
- self._NODESPRITE_DATA["rect"][3] = v
- self._NODESPRITE_ValidateRect()
-
- @property
- def center(self):
- r = self._NODESPRITE_DATA["rect"]
- return (int(r[0] + (r[2] * 0.5)), int(r[1] + (r[3] * 0.5)))
-
- @property
- def scale(self):
- return (self._NODESPRITE_DATA["scale"][0], self._NODESPRITE_DATA["scale"][1])
- @scale.setter
- def scale(self, scale):
- if not isinstance(scale, (list, tuple)):
- raise TypeError("Expected a list or tuple.")
- if len(scale) != 2:
- raise ValueError("Scale contains wrong number of values.")
- try:
- self.scale_x = scale[0]
- self.scale_y = scale[1]
- except Exception as e:
- raise e
-
- @property
- def scale_x(self):
- return self._NODESPRITE_DATA["scale"][0]
- @scale_x.setter
- def scale_x(self, v):
- if not isinstance(v, (int, float)):
- raise TypeError("Expected number value.")
- self._NODESPRITE_DATA["scale"][0] = float(v)
- self._NODESPRITE_DATA["scale_dirty"] = True
-
- @property
- def scale_y(self):
- return self._NODESPRITE_DATA["scale"][1]
- @scale_y.setter
- def scale_y(self, v):
- if not isinstance(v, (int, float)):
- raise TypeError("Expected number value.")
- self._NODESPRITE_DATA["scale"][1] = float(v)
- self._NODESPRITE_DATA["scale_dirty"] = True
-
- @property
- def image(self):
- return self._NODESPRITE_DATA["image"]
- @image.setter
- def image(self, src):
- src = src.strip()
- if self._NODESPRITE_DATA["image"] == src:
- return # Nothing to change... lol
- if self._NODESPRITE_DATA["image"] != "":
- self._NODESPRITE_DATA["surface"] = None # Clear reference to original surface.
- if src != "":
- rm = self.resource
- try:
- if not rm.has("graphic", src):
- rm.store("graphic", src)
- self._NODESPRITE_DATA["image"] = src
- self._NODESPRITE_DATA["surface"] = rm.get("graphic", src)
- if self._NODESPRITE_DATA["surface"] is None:
- self._NODESPRITE_DATA["image"] = ""
- self._NODESPRITE_DATA["rect"]=[0,0,0,0]
- else:
- # Resetting the rect to identity for the new image.
- surf = self._NODESPRITE_DATA["surface"]()
- size = surf.get_size()
- self._NODESPRITE_DATA["rect"]=[0,0,size[0], size[1]]
- except Exception as e:
- raise e
- else:
- self._NODESPRITE_DATA["image"] = ""
- self._NODESPRITE_DATA["rect"]=[0,0,0,0]
-
- def _render(self, surface):
- if self.visible == False:
- return
-
- # Call the on_render() method, if any
- Node2D._callOnRender(self, surface)
-
- # Paint the sprite onto the surface
- if self._NODESPRITE_DATA["surface"] is not None:
- rect = self._NODESPRITE_DATA["rect"]
- scale = self._NODESPRITE_DATA["scale"]
- surf = self._NODESPRITE_DATA["surface"]()
- # Of course, only bother if we have a surface to work with.
- if surf is not None:
- # Do some prescaling work, if needed.
- if self._NODESPRITE_DATA["scale_dirty"]:
- self._NODESPRITE_DATA["scale_dirty"] = False
- self._NODESPRITE_UpdateFrameSurface(surf)
- self._NODESPRITE_UpdateScaleSurface(scale, surf)
- fsurf = surf # Initial assumption that the surface is also the "frame"
- # If we have a "frame" surface, however, let's get it and blit the rect into the frame surface.
- if "frame_surf" in self._NODESPRITE_DATA:
- fsurf = self._NODESPRITE_DATA["frame_surf"]
- fsurf.blit(surf, (0, 0), rect)
- # If scaling, then transform (scale) the frame surface into the scale surface and set the frame surface to the scale surface.
- if "scale_surf" in self._NODESPRITE_DATA:
- ssurf = self._NODESPRITE_DATA["scale_surf"]
- pygame.transform.scale(fsurf, ssurf.get_size(), ssurf)
- fsurf = ssurf
-
- # Place the sprite! WHEEEEE!
- pos = self.get_world_position()
- surface.blit(fsurf, pos)
-
- # Call on all children
- Node._render(self, surface)
-
- def _NODESPRITE_UpdateFrameSurface(self, surf):
- rect = self.rect
- ssize = surf.get_size()
- if rect[2] == ssize[0] and rect[3] == ssize[1]:
- if "frame_surf" in self._NODESPRITE_DATA:
- del self._NODESPRITE_DATA
- return
-
- if "frame_surf" not in self._NODESPRITE_DATA:
- self._NODESPRITE_DATA["frame_surf"] = pygame.Surface((rect[2], rect[3]), pygame.SRCALPHA, surf)
- else:
- fsurf = self._NODESPRITE_DATA["frame_surf"]
- fsize = fsurf.get_size()
- if fsize[0] != rect[2] or fsize[1] != rect[3]:
- self._NODESPRITE_DATA["frame_surf"] = pygame.Surface((rect[2], rect[3]), pygame.SRCALPHA, surf)
-
-
- def _NODESPRITE_UpdateScaleSurface(self, scale, surf):
- ssurf = None
- if "scale_surf" in self._NODESPRITE_DATA:
- ssurf = self._NODESPRITE_DATA["scale_surf"]
-
- if scale[0] == 1.0 and scale[1] == 1.0:
- if ssurf is not None:
- del self._NODESPRITE_DATA["scale_surf"]
- return
- nw = int(self.rect_width * scale[0])
- nh = int(self.rect_height * scale[1])
-
- if nw != ssurf.get_width() or nh != ssurf.get_height():
- ssurf = pygame.Surface((nw, nh), pygame.SRCALPHA, surf)
- ssurf.fill(pygame.Color(0,0,0,0))
- self._NODESPRITE_DATA["scale_surf"] = ssurf
-
- def _NODESPRITE_ValidateRect(self):
- if self._NODESPRITE_DATA["surface"] is None:
- self._NODESPRITE_DATA["rect"] = [0,0,0,0]
- else:
- rect = self._NODESPRITE_DATA["rect"]
- isize = (self.image_width, self.image_height)
- if rect[0] < 0:
- rect[2] += rect[0]
- rect[0] = 0
- elif rect[0] >= isize[0]:
- rect[0] = isize[0]-1
- rect[2] = 0
- if rect[1] < 0:
- rect[3] += rect[1]
- rect[1] = 0
- elif rect[1] >= isize[1]:
- rect[1] = isize[1]-1
- rect[3] = 0
- if rect[2] < 0:
- rect[2] = 0
- elif rect[0] + rect[2] > isize[0]:
- rect[2] = isize[0] - rect[0]
- if rect[3] < 0:
- rect[3] = 0
- elif rect[1] + rect[3] > isize[1]:
- rect[3] = isize[1] - rect[1]
-
- self._NODESPRITE_DATA["scale_dirty"] = True
-
-
-
|