Skip to content

Instantly share code, notes, and snippets.

@wkta
Created September 25, 2025 23:49
Show Gist options
  • Select an option

  • Save wkta/ee1f80231258bf73e97167a22ab986b9 to your computer and use it in GitHub Desktop.

Select an option

Save wkta/ee1f80231258bf73e97167a22ab986b9 to your computer and use it in GitHub Desktop.
BaseGame Legacy component
import collections
import time
from abc import ABCMeta
import katagames_sdk as katasdk
kataen = katasdk.engine
pygame = kataen.import_pygame()
EventReceiver = kataen.EventReceiver
EngineEvTypes = kataen.EngineEvTypes
class BaseGame(metaclass=ABCMeta):
"""
Base class for games
"""
FPS_TRACKING_DEFAULT_SS = 13
def __init__(self, track_fps=True):
if track_fps:
self._fps_n_frames = self.FPS_TRACKING_DEFAULT_SS
else:
self._fps_n_frames = 0
self._fps_tracker_logic = collections.deque()
self._fps_tracker_rendering = collections.deque()
self._tick = 0
self._cached_info_text = None
self._info_font = None
def start(self):
"""Starts the game loop. This method will not exit until the game has finished execution."""
class _ProxyReceiver(EventReceiver):
def __init__(self, ref_game):
super().__init__()
self._tnow_cache = None
self._game = ref_game
self._event_queue = []
self._last_update_time = time.time()
def proc_event(self, ev, source):
if ev.type == EngineEvTypes.LOGICUPDATE:
self._game._update_internal(self._event_queue, ev.curr_t, ev.curr_t-self._last_update_time)
self._last_update_time = self._tnow_cache = ev.curr_t
self._event_queue.clear()
if ev.type == EngineEvTypes.PAINT:
self._game._render_internal(ev.screen, self._tnow_cache)
else:
self._event_queue.append(ev)
kataen.init(self.__get_mode_internal())
b, a = kataen.get_game_ctrl(), _ProxyReceiver(self)
a.turn_on()
b.turn_on()
self.pre_update()
b.loop()
kataen.cleanup()
"""
implement methods below so the game class suits your needs
"""
def get_mode(self) -> str:
"""
you need to return either
'HD', 'OLD_SCHOOL', or 'SUPER_RETRO'
"""
raise NotImplementedError()
def pre_update(self):
pass
def render(self, screen):
raise NotImplementedError()
def update(self, events, dt):
raise NotImplementedError()
"""
utils
"""
def get_fps(self, logical=True) -> float:
q = self._fps_tracker_logic if logical else self._fps_tracker_rendering
if len(q) <= 1:
return 0
else:
total_time_secs = q[-1] - q[0]
n_frames = len(q)
if total_time_secs <= 0:
return float('inf')
else:
return (n_frames - 1) / total_time_secs
@staticmethod
def get_screen_size():
return kataen.get_screen().get_size()
def get_tick(self) -> int:
return self._tick
@staticmethod
def is_running_in_web() -> bool:
return kataen.runs_in_web()
def render_text(self, screen, text, size=12, pos=(0, 0), color=(255, 255, 255), bg_color=None):
if self._info_font is None or self._info_font.get_height() != size:
self._info_font = pygame.font.Font(None, size)
lines = text.split("\n")
y = pos[1]
for lii in lines:
surf = self._info_font.render(lii, False, color, bg_color)
screen.blit(surf, (pos[0], y))
y += surf.get_height()
"""
private methods
"""
def __get_mode_internal(self):
mode_str = self.get_mode().upper()
if mode_str == 'HD':
return kataen.HD_MODE
elif mode_str == 'OLD_SCHOOL':
return kataen.OLD_SCHOOL_MODE
elif mode_str == 'SUPER_RETRO':
return kataen.SUPER_RETRO_MODE
else:
raise ValueError("Unrecognized mode: {}".format(mode_str))
def _render_internal(self, screen, tnow):
if self._fps_n_frames > 0:
self._fps_tracker_rendering.append(tnow)
if len(self._fps_tracker_rendering) > self._fps_n_frames:
self._fps_tracker_rendering.popleft()
self.render(screen)
def _update_internal(self, events, tnow, dt):
if self._fps_n_frames > 0:
self._fps_tracker_logic.append(tnow)
if len(self._fps_tracker_logic) > self._fps_n_frames:
self._fps_tracker_logic.popleft()
self.update(events, dt)
self._tick += 1
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment