Posts Tagged ‘games’

Planet simulator and Goserver

Posted in Programming on January 1st, 2010 by Mat – Be the first to comment

In an effort to revive this blog and start posting regularly I’ve decided to post some things I made ages ago which I haven’t posted online before.

The first is a solar system simulator that demonstrates Kepler’s laws of planetary motion:

kepler.tar (source)

This originated as part of a multiplayer space shooter game I worked on with Bencoder, which was never completed (mainly because we couldn’t decide how the game was supposed to work). We wanted planets which would move, but would be consistent across the network. Keplerian orbits allowed us to predict the state of the system at any given time, while still being realistic enough to satisfy my nerdiness. This is basically the map editor I wrote for the game. I think it was my first C++ application and my first GUI application (using Qt). As a result, the code is a horrible mess and it’s a bit buggy, but it’s quite fun to play around with.

Features:

  • construct systems of suns, moons and planets
  • customize the image shown for each one with user created content
  • modify the size, mass and position of the objects
  • modify the ellipticity and direction of the orbits
  • view an animation of the system in real time

Note: since the planets only interact with one other object, the system will behave a bit weirdly when the orbital paths intersect or are close to each other.

The other thing I made (this was a bit more recent) is a turn based go server in ruby on rails. It’s unfinished at the moment, but I have it running here if you want to take a look. I was using this project to try and learn rails, but I think I may have picked something a bit too ambitious. There was a problem I couldn’t figure out with the images sometimes not loading and I eventually gave up on it. I learned a lot from it though, and I really like rails for web development, even though it’s a lot of hassle to set up on my website compared to PHP.

Generating grids to use as go boards

Posted in Programming on December 29th, 2009 by Mat – Be the first to comment

So I decided to go back to my python go game I started many months ago. I have several other things I want to work on, most of which also involve go, but for some reason this interests me the most at the moment, and I haven’t done any python programming in a while so I’m going to put them on hold.

One of the main things I wanted to do with the game was to allow for playing on many different types of board, rather than limit it to the boring old 19×19 square kind, so I’ve written a module with several different classes which can be used to create board objects.

The rules of go are very simple, and are pretty much independent of the board shape. To work out what happens to the rest of the board when you place a stone, all you really need to know is how the points are connected to each other and where all the stones are. This means that an arbitrary graph can be used as the go board and what the board actually looks like is irrelevant. You can easily play go on 3D structures such as diamond structures or invent some strange irregular shape if you want. This makes it pretty easy to seperate the board structure from the game logic.

I’ve decided to limit myself to regular structures for the time being, and have stuck to 2 dimensions as I’m too lazy to mess around with 3D visualizations. I’ve implemented a regular rectangular board a board which allows the edges to be wrapped pacman style, which can be used to simulate playing on a the surface of a cylinder or torus (donut shape). To test it works ok I’ve whipped up a simple view in pygame which shows the neighbours of each point when you click on it.

The next step is to rewrite my go game around this module and create a usable gui for it.

'''Classes for modelling the goboard itself, i.e. an arrangement of points with lines connecting them. No game logic is included.
Grid/lattice coordinates should all be integers'''
from itertools import izip
import sys

#Move this somewhere else later
class Observable:
    '''Implement observer pattern'''

    def __init__(self):
        self.listeners = []

    def register_listener(self, listener):
        self.listeners.append(listener) #this object has synasthaesia

    def remove_listener(self, listener):
        self.listeners.remove(listener)

    def notify(self, *args):
        for i in self.listeners:
            if args:
                i(args)
            else:
                i()

class Grid(Observable):
    '''A representation of a 2D grid with each point holding some value.
    Stores the relative location of each point and the lines connecting them.
    Lattice is a list of points representing the lattice structure the grid is based around.
    Basis is a tuple of coordinates of the grid points relative to the lattice points.
    Connections is a list of 4-tuples of the form (x1,y1,x2,y2) indicating how points in the basis are connected'''

    def __init__(self, lattice, basis, connections, default_value=0):
        '''Store points and connections'''
        Observable.__init__(self)
        self.points = {}
        self.connections = {}

        for lx,ly in lattice.items():

            #Add the points by superimposing the basis onto each lattice point
            for b in basis:
                bx, by = b
                self.points[(lx+bx, ly+by)] = default_value
                self.connections[(lx+bx, ly+by)] = []

        #Now connect the points
        for lx,ly in lattice.items():

            try:
                for c in connections:
                    cx1, cy1, cx2, cy2 = c
                    a = (lx+cx1, ly+cy1)
                    b = (lx+cx2, ly+cy2)
                    if a in self.points and b in self.points:
                        self.connections[a].append(b)
                        self.connections[b].append(a)
                    else:
                        print 'Missing points for connection '+str(a)+'-'+str(b)
                        if a not in self.points: print a
                        if b not in self.points: print b
            except KeyError:
                raise Exception('Invalid connections')

    def neighbours(self, x, y):
        try:
            return self.connections[(x,y)]
        except KeyError:
            raise Exception('Bad grid coordinates')

    def set_point(self, x, y, val):
        try:
            self.points[(x,y)] = val
            self.notify() #notify observers on changes
        except KeyError:
            raise Exception('Bad grid coordinates')

class RectangularGrid(Grid):
    '''A rectangular grid. Aspect ratio should be a natural number (horizontal spacing >= vertical spacing)'''

    def __init__(self, width, height, aspect_ratio=1):
        aspect_ratio = int(aspect_ratio) #no floats please!
        lattice = RectangularLattice(width, height, aspect_ratio)
        basis = ((0, 0),)
        connections = ((0, 0, 1, 0), (0, 0, 0, 1))
        Grid.__init__(self, lattice, basis, connections)

class FoldedGrid(RectangularGrid):
    '''A rectangular grid where sides connect with each other.
    Joins is a list of tuples indicating which sides are joined, where each of the two values can be N, E, S or W
    Reverse_joins is the same except there is also a twist, so one side can map to another side reversed (or the same side)'''

    def __init__(self, width, height, aspect_ratio, joins = [], reverse_joins = []):
        RectangularGrid.__init__(self, width, height, aspect_ratio)

        #Lists of coordinates making up each side
        east = []
        west = []
        north = []
        south = []

        #East/West coordinates
        x1 = 0
        x2 = (width - 1) * aspect_ratio
        for i in range(height):
            east.append((x1, i))
            west.append((x2, i))

        #North/South coordinates
        y1 = 0
        y2 = height - 1
        for i in range(width):
            i *= aspect_ratio
            north.append((i, y1))
            south.append((i, y2))

        sides = {'E':east, 'W':west, 'N':north, 'S':south}

        #Make the extra connections
        try:
            for sideA, sideB in joins:
                #Zip the two sides together to get a tuple of tuples (coordinates) for each connected pair
                for c1, c2 in izip(sides[sideA], sides[sideB]):
                    self.connections[c1].append(c2)
                    self.connections[c2].append(c1)

            for sideA, sideB in reverse_joins:
                #This time the second side is reversed!
                for c1, c2 in izip(sides[sideA], reversed(sides[sideB])):
                    print str(c1) + '-' + str(c2)
                    self.connections[c1].append(c2)
                    self.connections[c2].append(c1)

        except KeyError:
            raise Exception('Invalid value for join or reverse_join')

class RectangularLattice:
    '''List of coordinates of points arranged in a grid'''

    def __init__(self, width, height, aspect_ratio, scale=1):
        aspect_ratio = int(aspect_ratio) #no floats please
        self.points = []
        for i in range(width):
            for j in range(height):
                j *= aspect_ratio
                self.points.append((i,j))

    def items(self):
        for i in self.points:
            yield i

class GridViewPygame:
    '''Draw grids using pygame'''

    def __init__(self, grid, surface, scale=None, rotation=0, zoom_to_fit=False, join_connected=False, highlight_connected=True):
        grid_width = max([x for x,y in grid.points])
        grid_height = max([y for x,y in grid.points])
        width = surface.get_width()
        height = surface.get_height()

        if zoom_to_fit:
            scale = min(width/float(grid_width), height/float(grid_height))
        elif scale is None:
            scale = 1

        self.scale = scale
        self.grid = grid
        self.surface = surface
        self.grid.register_listener(self.draw)
        self.highlighted = None

        self.highlight_connected = highlight_connected
        self.join_connected = join_connected

    def draw(self, *args):
        '''Draw the grid'''
        print 'redrawing'
        scale = self.scale
        self.surface.fill((255,255,255))

        for p in self.grid.points:
            x,y = p
            x *= scale
            y *= scale
            if (p == self.highlighted):
                pygame.draw.circle(self.surface, (0,0,255), (x,y), 3)
            else:
                pygame.draw.circle(self.surface, (0,0,0), (x,y), 2)

        #This actually draws the line for each connection twice but never mind
        if self.join_connected:
            for a,bs in self.grid.connections.items():
                for b in bs:
                    ax,ay = a
                    bx,by = b
                    ax *= scale
                    ay *= scale
                    bx *= scale
                    by *= scale
                    if (a == self.highlighted or b == self.highlighted):
                        pygame.draw.line(self.surface, (0,0,255), (ax,ay), (bx,by))
                    else:
                        pygame.draw.line(self.surface, (0,0,0), (ax,ay), (bx,by))

        if self.highlight_connected and self.highlighted:
            for x,y in self.grid.connections[self.highlighted]:
                x *= scale
                y *= scale
                pygame.draw.circle(self.surface, (0,255,0), (x,y), 2)

        pygame.display.flip()

    def board_to_grid(self, pos):
        '''Convert view coordinates to grid ones'''
        x,y = pos
        x = int(round(x/self.scale))
        y = int(round(y/self.scale))
        return (x,y)

    def onClick(self, pos):
        '''Highlight the nearest point'''
        pos = self.board_to_grid(pos)
        print pos
        self.highlighted = pos
        self.draw(False,True)

if __name__ == '__main__':

    #Initialize pygame
    import pygame
    pygame.init()
    from pygame.locals import *
    screen = pygame.display.set_mode((800, 600))

    #Create grid
#    grid = RectangularGrid(19,19)
    grid = FoldedGrid(19,19,1,[('N','S'),('E','W')])
#    grid = FoldedGrid(19,19,1,[],[('N','S'),('E','W')])
    view = GridViewPygame(grid, screen, zoom_to_fit=True)
    view.draw()

    #Handle events
    while True:
        for event in pygame.event.get():
            if event.type == QUIT:
                pygame.quit()
                sys.exit()
            elif event.type == MOUSEBUTTONDOWN:
                view.onClick(pygame.mouse.get_pos())

One day game (continued)

Posted in Ideas, One day games, Programming on June 5th, 2009 by Mat – Be the first to comment

Game 1 ended up being a huge failure. I think the main reason for this was a lack of experience in game development in general, and a poor choice of programming language, which I didn’t really know how to use properly when I started (flash/actionscript). As a result I wasted a lot of time trying to learn stuff and wasn’t able to put together anything playable within the time span I set myself.

Trying to come up with good ideas in so short a time was challenging, but I think I did have some workable ideas. While the obvious interpretation of “space” is a broad enough theme in itself, I decided to explore other meanings rather than immediately settling for some kind of spaceship game. Some of the ideas I had -

  • An abstract game where the player manipulates empty space somehow, by rearranging or destroying things
  • A tetris variant
  • Human expansion has left the solar system overcrowded and you have to destroy things to make space, possibly related to the Vogons in h2g2 (reflecting the theme in two ways)
  • Something related to recycling and consumerism (not enough space for all the garbage we produce?)
  • Any kind of space in the mathematical sense
  • Something related to the concept of personal space. e.g. avoiding other commuters on a crowded train (I rejected this but kept the general idea for my final game)

The idea I went with was a game in which you have to maintain a certain amount of space around you to survive. The player is a boy who is trying to avoid catching “cooties” from girls who run at the player from offscreen. Also the player is armed with a baseball bat.

This is as far as I got:
Failed game

24 hour game

Posted in One day games, Programming on June 4th, 2009 by Mat – Be the first to comment

This will be the first of hopefully many small games. Me and my friend Ben will both be attempting to design and make fun, playable games within a one day time frame. Each time, there will be a theme chosen at the start by one of us (the theme chooser will change each time) which both the games will have to fit in with. At the end, people will be able to vote on which is the best over at Ben’s blog.

The theme this time is “space” (chosen by Ben) and the challenge ends at 19.00 23.59 UTC+1 tommorow (5th of june).

Go

Posted in Programming on December 4th, 2008 by Mat – 2 Comments

I’ve gotten really into Go lately, so I decided to make my own Go app. I’m not really planning to accomplish anything useful, seeing as there’s a lot of good software already out there, so features will be added if and when I feel like it.

I’ve written a few classes for it now… you can play stones and it will try to work out if the move is legal and remove captured stones, which seems to work but probably doesn’t. I’ll test it properly later. I’m going to make a text only interface first, then add a gui once I’ve got it working properly.

*edit* made the text interface for playing a 2 player game on the same computer. Everything is working but it doesn’t calculate the score yet.

Go game

Go game