Re: Create a game map?

Hi,
Probably an unpopular suggestion, but worth chucking out there:

I know there's lots of boilerplate code in here, but I've taken the _Base class from my pyrts project.

With the below code you can instantiate maps and tiles with relative ease. Of course there's no provision for storing objects, but that's only a matter of extending what I've written.

I use this kind of setup a lot. If you want to see more sql in action, look at the pyrts source code, or check the running instance.

from enum import Enum as PythonEnum
from inspect import isclass

from sqlalchemy import (
    create_engine, Column, Integer, ForeignKey, Enum, inspect
)
from sqlalchemy.exc import DatabaseError
from sqlalchemy.orm import relationship, sessionmaker
from sqlalchemy.ext.declarative import declarative_base

engine = create_engine('sqlite:///:memory:')
Session = sessionmaker(bind=engine)
session = Session()


class TileTypes(PythonEnum):
    """The possible types for tiles."""

    sand = 0
    grass = 1
    water = 2
    wall = 3
    lava = 4


class _Base:
    """Create a primary key and some useful methods."""
    id = Column(Integer, primary_key=True)

    def save(self):
        """Save this object."""
        session.add(self)
        try:
            session.commit()
        except DatabaseError:
            session.rollback()
            raise

    def delete(self):
        session.delete(self)
        try:
            session.commit()
        except DatabaseError:
            session.rollback()
            raise

    @classmethod
    def query(cls, *args, **kwargs):
        """Return a query object with this class."""
        return session.query(cls).filter(*args).filter_by(**kwargs)

    @classmethod
    def count(cls, *args, **kwargs):
        """Return the number of instances of this class in the database."""
        return cls.query(*args, **kwargs).count()

    @classmethod
    def first(cls, *args, **kwargs):
        """Return the first instance of this class in the database."""
        return cls.query(*args, **kwargs).first()

    @classmethod
    def get(cls, id):
        """Get an object with the given id."""
        return cls.query().get(id)

    @classmethod
    def one(cls, *args, **kwargs):
        return cls.query(*args, **kwargs).one()

    @classmethod
    def all(cls, *args, **kwargs):
        """Return all child objects."""
        return cls.query(*args, **kwargs).all()

    @classmethod
    def classes(cls):
        """Return all table classes."""
        for item in cls._decl_class_registry.values():
            if isclass(item) and issubclass(item, cls):
                yield item

    @classmethod
    def number_of_objects(cls):
        """Returns the number of objects in the database."""
        count = 0
        for base in cls.classes():
            count += base.count()
        return count

    def __repr__(self):
        name = type(self).__name__
        string = '%s (' % name
        attributes = []
        i = inspect(type(self))
        for column in i.c:
            name = column.name
            attributes.append('%s=%r' % (name, getattr(self, name)))
        string += ', '.join(attributes)
        return string + ')'

    @classmethod
    def get_class_from_table(cls, table):
        """Return the class whose __table__ attribute is the provided Table
        instance."""
        for value in cls._decl_class_registry.values():
            if getattr(value, '__table__', None) is table:
                return value


Base = declarative_base(bind=engine, cls=_Base)


class Tile(Base):
    """A tile on the map."""

    __tablename__ = 'tiles'
    x = Column(Integer, nullable=False)
    y = Column(Integer, nullable=False)
    type = Column(Enum(TileTypes), nullable=False)
    map_id = Column(Integer, ForeignKey('maps.id'), nullable=False)
    map = relationship(
        'Map', backref='tiles', single_parent=True,
        cascade='all, delete-orphan'
    )


class Map(Base):
    """A map which can contain lots of tiles."""

    __tablename__ = 'maps'
    size_x = Column(Integer, nullable=False, default=100)
    size_y = Column(Integer, nullable=False, default=100)
    default_type = Column(
        Enum(TileTypes), nullable=False, default=TileTypes.sand
    )

    @property
    def size(self):
        return self.size_x, self.size_y

    @size.setter
    def size(self, value):
        self.size_x, self.size_y = value

    def tile_at(self, x, y):
        """Return the type of tile at the given coordinates."""
        tile = Tile.first(map=self, x=x, y=y)
        if tile is None:
            return self.default_type
        return tile.type

    def add_tile(self, x, y, type):
        """Create and return a tile of the given type at the given
        coordinates."""
        return Tile(map=self, x=x, y=y, type=type)


if __name__ == '__main__':
    Base.metadata.create_all()
    m = Map()
    m.save()
    m.add_tile(1, 1, TileTypes.wall).save()
    assert m.tile_at(0, 0) is TileTypes.sand
    assert m.tile_at(1, 1) is TileTypes.wall
-- 
Audiogames-reflector mailing list
Audiogames-reflector@sabahattin-gucukoglu.com
https://sabahattin-gucukoglu.com/cgi-bin/mailman/listinfo/audiogames-reflector
  • ... AudioGames . net Forum — Developers room : frastlin via Audiogames-reflector
    • ... AudioGames . net Forum — Developers room : amerikranian via Audiogames-reflector
    • ... AudioGames . net Forum — Developers room : amerikranian via Audiogames-reflector
    • ... AudioGames . net Forum — Developers room : chrisnorman7 via Audiogames-reflector
    • ... AudioGames . net Forum — Developers room : frastlin via Audiogames-reflector

Reply via email to