In [ ]:
import json
import pathlib
import logging
from pikov import JSONGraph
In [ ]:
# Helper for displaying images.
# source: http://nbviewer.ipython.org/gist/deeplook/5162445
from io import BytesIO
from IPython import display
from PIL import Image
def display_pil_image(im):
"""Displayhook function for PIL Images, rendered as PNG."""
b = BytesIO()
im.save(b, format='png')
data = b.getvalue()
ip_img = display.Image(data=data, format='png', embed=True)
return ip_img._repr_png_()
# register display func with PNG formatter:
png_formatter = get_ipython().display_formatter.formatters['image/png']
dpi = png_formatter.for_type(Image.Image, display_pil_image)
In [ ]:
sample_dir = (pathlib.Path("..") / ".." / "samples").resolve()
with open(sample_dir / "pikov-core.json") as fp:
core_types = json.load(fp)
#graph = JSONGraph.load(fp)
In [ ]:
sample_path = sample_dir / "gamekitty.json"
# Merge core types into pikov.json
graph = JSONGraph.load(sample_path)
for key, item in core_types["guidMap"].items():
graph._guid_map[key] = item
In [ ]:
names = {}
for node in graph:
for edge in node:
if edge.guid == "169a81aefca74e92b45e3fa03c7021df":
value = node[edge].value
if value in names:
raise ValueError('name: "{}" defined twice'.format(value))
names[value] = node
names["ctor"]
In [ ]:
def name_to_guid(name):
if name not in names:
return None
node = names[name]
if not hasattr(node, "guid"):
return None
return node.guid
In [ ]:
from pikov.sprite import Bitmap, Clip, Frame, FrameList, Point, Resource, Sprite, Transition
Create instances of the Pikov classes to define a concrete Pikov graph, based on my "gamekitty" animations.
In the previous notebook, we chopped the spritesheet into bitmaps. Find those and save them to an array so that they can be indexed as they were in the original PICO-8 gamekitty doodle.
In [ ]:
resource = Resource(graph, guid=name_to_guid("spritesheet"))
spritesheet = []
for row in range(16):
for column in range(16):
sprite_number = row * 16 + column
bitmap_name = "bitmap[{}]".format(sprite_number)
bitmap = Bitmap(graph, guid=name_to_guid(bitmap_name))
spritesheet.append(bitmap)
In [ ]:
def find_nodes(graph, ctor, cls):
nodes = set()
# TODO: With graph formats that have indexes, there should be a faster way.
for node in graph:
if node[names["ctor"]] == ctor:
node = cls(graph, guid=node.guid)
nodes.add(node)
return nodes
def find_frames(graph):
return find_nodes(graph, names["frame"], Frame)
def find_transitions(graph):
return find_nodes(graph, names["transition"], Transition)
def find_absorbing_frames(graph):
transitions = find_transitions(graph)
target_frames = set()
source_frames = set()
for transition in transitions:
target_frames.add(transition.target.guid)
source_frames.add(transition.source.guid)
return target_frames - source_frames # In but not out. Dead end!
In [ ]:
MICROS_12_FPS = int(1e6 / 12) # 12 frames per second
MICROS_24_FPS = int(1e6 / 24)
def connect_frames(graph, transition_name, source, target):
transition = Transition(graph, guid=name_to_guid(transition_name))
transition.name = transition_name
transition.source = source
transition.target = target
return transition
def make_clip(graph, name, sprite_numbers, loop=False, duration=MICROS_12_FPS, guid=None):
clip_name = "clip[{}]".format(name)
clip_guid = guid or name_to_guid(clip_name)
clip = Clip(graph, guid=clip_guid)
clip.name = clip_name
if clip.frames:
logging.warning("Clip already has frames")
return clip
frame_list_name = "framelist[{}, 0]".format(name)
end_of_clip = FrameList(graph, guid=name_to_guid(frame_list_name))
clip.frames = end_of_clip
clip.frames.name = "framelist[{}, 0]".format(name)
previous_sprite_name = None
previous_frame = None
for sequence, sprite_number in enumerate(sprite_numbers):
sprite_name = "{}[{}]".format(name, sequence)
frame_name = "frames[{}]".format(sprite_name)
frame = Frame(graph, guid=name_to_guid(frame_name))
frame.name = frame_name
frame.bitmap = spritesheet[sprite_number]
frame.duration_microsections = duration
if previous_sprite_name:
transition_name = "transitions[{}, {}]".format(
previous_sprite_name,
sprite_name)
connect_frames(graph, transition_name, previous_frame, frame)
previous_sprite_name = sprite_name
previous_frame = frame
frame_list_name = "framelist[{}, {}]".format(name, sequence + 1)
end_of_clip = end_of_clip.append(frame, guid=name_to_guid(frame_list_name))
end_of_clip.name = frame_list_name
if loop:
transition_name = "transitions[{}, {}]".format(
previous_sprite_name,
"{}[0]".format(name))
connect_frames(graph, transition_name, previous_frame, clip.frames.head)
return clip
In [ ]:
sit = make_clip(graph, "sit", [0], loop=True)
#sit[0].bitmap.image
sit
In [ ]:
sit_to_stand = make_clip(graph, "sit_to_stand", [1,2,3,4])
sit_to_stand
In [ ]:
stand_waggle = make_clip(graph, "stand_waggle", [26,4], loop=True)
stand_waggle
In [ ]:
stand_to_sit = make_clip(graph, "stand_to_sit", [57, 58, 59, 60, 61])
stand_to_sit
In [ ]:
origin = Point(graph, guid=name_to_guid("origin"))
origin.name = "origin"
origin.x = 0
origin.y = 0
origin
In [ ]:
sprite = Sprite(graph, guid=name_to_guid("gamekitty"))
graph._properties["root"] = sprite.guid
sprite.name = "gamekitty"
sprite.position = origin
sprite.frame = sit[0]
sprite
In [ ]:
sit_paw = make_clip(graph, "sit_paw", [62, 63, 64, 65])
sit_paw
In [ ]:
sit_to_crouch = make_clip(graph, "sit_to_crouch", [69, 70, 71])
sit_to_crouch
In [ ]:
crouch = make_clip(graph, "crouch", [72])
crouch
In [ ]:
crouch_to_sit = make_clip(graph, "crouch_to_sit", [75, 76, 77])
crouch_to_sit
In [ ]:
find_absorbing_frames(graph)
In [ ]:
graph.save()
In [ ]: