Category Archives: Projects

Advanced Sprite Animation Using Pygame in Python2.7


Advanced Sprite Animation Demo

you can download the codes for this tutorial here.

it has been quite a long while since i last posted a tutorial. fortunately i was able to come up with another one despite the busy schedule. and to continue from what we’ve left here, i am now presenting a tutorial on how to animate sprites with the look and feel that is a lot closer to how we see them in our 2D games. this tutorial will deal with animating sprites that use multiple images for each action, with the said images extracted from a large single image containing views of the sprites from all possible angles.

to begin let us visit the code for the sprites that we are going to use. as what we have learned from our OOP lessons, it is ideal to keep functions that we are going to use across our classes in a base class. this will save us from repetition and make the implementation of changes for all sub-classes easier. so let us check out first the code for our base class contained in lib_sprites.py. normally i would name it class_spritebase.py, but since i’m planning it to contain all other classes and helpers to be used by sprites in the future, i used the lib_ prefix instead to let me know it’s a library.

it of course starts with the imports.

import pygame
from pygame import *

import sys
sys.path.append('utils')

import lib_utils
from lib_utils import StaticFunction

as you can see, aside from the pygame library, we also imported our own library which is lib_utils. if you have been visiting the other tutorials, you can perhaps recall that it is the library we created for helper classes. in this tutorial we are going to use it to create static function calls against our SpriteDirection class.

SPRITEDIRECTION CLASS

the SpriteDirection class is meant to contain all valid directions that we are going to accept. this is so other developers who might want to use our library won’t be guessing parameters to pass whenever setting a sprite’s direction. this class also comes with an IsDirection function to validate direction values.

class SpriteDirection:
    NORTH = '+Y'
    EAST = '+X'
    WEST = '-X'
    SOUTH = '-Y'

    def IsDirection(direction):
        if(direction == SpriteDirection.NORTH or \
           direction == SpriteDirection.EAST or \
           direction == SpriteDirection.WEST or \
           direction == SpriteDirection.SOUTH):
            return True

        return False

    IsDirection = StaticFunction(IsDirection)

SPRITEBASE CLASS

the SpriteBase class as mentioned earlier should serve as the base class for all our sprite classes. it inherits from the built-in object type and has a set of properties with their own getters and setters. for now, it only has two functions namely RenderImage and RenderImageAtLocation which we are going to use to display the sprite’s image on our screen.

to describe our properties in detail:

ImageSource

a Surface returned by pygame.image.load() given a path to a sprite’s source image.

HotSpots

list of Rect objects pointing to portions in the source image that contains images to be used by the sprite.

Direction

a SpriteDirection value specifying the direction to which the sprite faces.

Location

the location of the sprite in the screen

class SpriteBase(object):
    def __init__(self):
        self._imagesource = None
        self._hotspots = list()
        self._direction = SpriteDirection.SOUTH
        self._location = [0, 0]

    #Properties
    def ImageSource(self, imgsrc=None):
        if (imgsrc == None):
            return self._imagesource
        else:
            self._imagesource = imgsrc

    def HotSpots(self, rect=None):
        if(rect == None):
            return self._hotspots
        else:
            self._hotspots.append(rect)

    def Direction(self, direction=None):
        if(direction == None):
            return self._direction
        else:
            if(SpriteDirection.IsDirection(direction)):
                self._direction = direction

    def Location(self, location=None):
        if(location == None):
            return self._location
        else:
            self._location = location

    #Methods
    def RenderImage(self, screen, spotindex):
        screen.blit(self._imagesource, self._location, self._hotspots[spotindex])

    def RenderImageAtLocation(self, screen, location=None, spotindex=0):
        screen.blit(self._imagesource, location, self._hotspots[spotindex])

SHEEP CLASS

i’ve created a number of classes inheriting from the SpriteBase class as requested by my 2 year old nephew. he loved watching the animals move. but for this tutorial i will only discuss the Sheep class contained in class_sheep.py.

it begins with a number of imports for pygame, the lib_sprites, datetime, and config as shown below. the datetime will be used for implementing the delay in displaying the series of images involved in one action while config refers to class we created that is supposed to contain the configurations for the game.

import pygame
from pygame import *

import datetime
from datetime import datetime, timedelta

import config
from config import AppConfig

import lib_sprites
from lib_sprites import SpriteBase, SpriteDirection

the constructor for the class will simply call the parent constructor, load the image to use, and specify the hotspots.

class Sheep(SpriteBase):
    def __init__(self):
        super(Sheep, self).__init__()
        self.ImageSource(pygame.image.load('images/Animal.png'))

        #looking north
        self.HotSpots(pygame.Rect(320, 96, 32, 32)) #standing
        self.HotSpots(pygame.Rect(288, 96, 32, 32)) #step right foot
        self.HotSpots(pygame.Rect(352, 96, 32, 32)) #step left foot

        #looking east
        self.HotSpots(pygame.Rect(320, 64, 32, 32)) #standing
        self.HotSpots(pygame.Rect(288, 64, 32, 32)) #step right foot
        self.HotSpots(pygame.Rect(352, 64, 32, 32)) #step left foot

        #looking west
        self.HotSpots(pygame.Rect(320, 32, 32, 32)) #standing
        self.HotSpots(pygame.Rect(352, 32, 32, 32)) #step right foot
        self.HotSpots(pygame.Rect(288, 32, 32, 32)) #step left foot

        #looking south
        self.HotSpots(pygame.Rect(320, 0, 32, 32)) #standing
        self.HotSpots(pygame.Rect(288, 0, 32, 32)) #step right foot
        self.HotSpots(pygame.Rect(352, 0, 32, 32)) #step left foot

the Turn() method will make the sprite turn to a different direction. note that screen.fill() is called before rendering the image. this is to cover the previously displayed image before rendering another. this can be replaced by a function to render the background when it’s already available.

    #makes a sprite turn to specified direction
    def Turn(self, screen, direction):
        self.Direction(direction)
        index = -1

        if(direction == SpriteDirection.NORTH):
            index = 0
        elif(direction == SpriteDirection.EAST):
            index = 3
        elif(direction == SpriteDirection.WEST):
            index = 6
        elif(direction == SpriteDirection.SOUTH):
            index = 9
        screen.fill(0)
        self.RenderImage(screen, index)
        pygame.display.update()

the Walk() method initiates variables for making the sprite walk to current direction. the direction is checked first and locations to display images are put into a list, the same as the indices of the images to display from the sprite’s hotspots. each location in the list of locations should correspond to one image in the sprite’s hotspots, therefore the length of locations array and index array should be equal.

putting a grid over the display screen, the length of either array could be taken as the number of steps that a sprite would take to move to the next cell in the grid. in our example we have a 32px x 32px cell and so a sprite’s ending location should be 32px from the current location. the more step we use, the smoother the action will be. however it could have a few issues like making the distance between two locations seem so far and too much redrawing of the surface than necessary. in our example, we’re just going to use 4 steps.

    #makes a sprite walk to current direction
    def Walk(self, screen):
        locations = list() #contains locations for each sprite image to render in succession
        indexarray = None #contains the indices of all sprite images to render
        if(self.Direction() == SpriteDirection.NORTH):
            locations.append([self.Location()[0], self.Location()[1]-8])
            locations.append([self.Location()[0], self.Location()[1]-16])
            locations.append([self.Location()[0], self.Location()[1]-24])
            locations.append([self.Location()[0], self.Location()[1]-32])
            indexarray = [1, 2, 1, 0]
        elif(self.Direction() == SpriteDirection.EAST):
            locations.append([self.Location()[0]+8, self.Location()[1]])
            locations.append([self.Location()[0]+16, self.Location()[1]])
            locations.append([self.Location()[0]+24, self.Location()[1]])
            locations.append([self.Location()[0]+32, self.Location()[1]])
            indexarray = [4, 5, 4, 3]
        elif(self.Direction() == SpriteDirection.WEST):
            locations.append([self.Location()[0]-8, self.Location()[1]])
            locations.append([self.Location()[0]-16, self.Location()[1]])
            locations.append([self.Location()[0]-24, self.Location()[1]])
            locations.append([self.Location()[0]-32, self.Location()[1]])
            indexarray = [7, 8, 7, 6]
        elif(self.Direction() == SpriteDirection.SOUTH):
            locations.append([self.Location()[0], self.Location()[1]+8])
            locations.append([self.Location()[0], self.Location()[1]+16])
            locations.append([self.Location()[0], self.Location()[1]+24])
            locations.append([self.Location()[0], self.Location()[1]+32])
            indexarray = [10, 11, 10, 9]

        self.__animate_walk__(screen, locations, indexarray)

the __animate_walk__() is a private method that takes care of the actual animation. this method simply loops through the specified locations and hotspot indices by the Walk() method and display the images on screen with certain delay enough for each image to be viewable to the user. a check was also included to make the sprite stay within the bounds of the display screen.

def __animate_walk__(self, screen, locations, indexarray):
        if(len(locations) == 0 or len(indexarray) == 0):
            return
        for i in range(len(locations)):
            loc = locations[i]
            if(loc[0] < 0 or loc[1] < 0 or loc[0] > AppConfig.DEFAULT_SCREENSIZE[0]-32 or loc[1] > AppConfig.DEFAULT_SCREENSIZE[1]-32):
                return
            self.Location(loc)
            screen.fill(0)
            self.RenderImage(screen, indexarray[i])
            pygame.display.update()
            #implements delay
            t1 = datetime.now() + timedelta(seconds=0.125)
            while(datetime.now() < t1):
                pass
            self.Location(loc)

THE GAME

the game.py file is where the game should be implemented. like the others, it begins with importing a number of libraries.

import pygame
from pygame import *

import datetime
from datetime import timedelta

import config
from config import AppConfig

import sys
sys.path.append('entities')

import lib_sprites
from lib_sprites import SpriteDirection

import class_sheep
from class_sheep import Sheep

import class_cow
from class_cow import Cow

import class_rooster
from class_rooster import Rooster

import class_butterfly
from class_butterfly import Butterfly

following imports is the initialization. notice that pygame.key.set_repeat() is used. this is to make the sprite walk as long as the the key is held down as opposed to making it walk from one cell to another for each key press.

pygame.init()
pygame.key.set_repeat(1, 1)

screen = pygame.display.set_mode(AppConfig.DEFAULT_SCREENSIZE)
display.set_caption('Advanced Animation Demo')

going = True

what follows is the initialization for the sprite and the main loop which is pretty self-explanatory. after rendering the sprite image in its initial position, we’re going to wait for a user triggered event and respond accordingly. we’ll close the application if we encounter a QUIT. if we encounter a button press in any of the four directions we either turn if it is different from the current one, or walk.

character = Sheep()
character.RenderImage(screen, 9)
pygame.display.update()

while going:
    for e in event.get():
        if e.type == QUIT: #checks if close button was clicked
            going = False
        elif e.type == KEYDOWN:
            keystate = pygame.key.get_pressed()
            if(keystate[K_UP]):
                if(character.Direction() == SpriteDirection.NORTH):
                    character.Walk(screen)
                else:
                    character.Turn(screen, SpriteDirection.NORTH)
            elif(keystate[K_RIGHT]):
                if(character.Direction() == SpriteDirection.EAST):
                    character.Walk(screen)
                else:
                    character.Turn(screen, SpriteDirection.EAST)
            elif(keystate[K_LEFT]):
                if(character.Direction() == SpriteDirection.WEST):
                    character.Walk(screen)
                else:
                    character.Turn(screen, SpriteDirection.WEST)
            elif(keystate[K_DOWN]):
                if(character.Direction() == SpriteDirection.SOUTH):
                    character.Walk(screen)
                else:
                    character.Turn(screen, SpriteDirection.SOUTH)

pygame.quit()

and that’s it. you can download the codes for this tutorial here. i hope you enjoyed working with this tutorial. ’til next time. -aB

Tagged , , , , , , ,

Flood-it! Game in Python 2.7 with Pygame


it has been quite a long while since i last posted a game tutorial. well i did not in any way intended this blog to be one, but the only project i’m dealing with right now has to be confidential so there’s no way it’s going out here in my blog. i’m also currently taking a short online course in game theory under Stanford and that’s what gets me occupied most of the time so it’s not ideal to discuss something rather complex as an actual IT project. so here i am with another game tutorial.

a couple of weeks ago (or maybe a month ago), i’ve encountered the game Flood-it! while checking out some games in Google Plus. i was idle then. i could have actually checked out some other games with better graphics, complex goals and all that, but i was at the office and thought i should not try those games that would catch too much attention from people who would probably pass by my work station. so i just chose Flood-it! and well it was okay to pass one’s time. the goal was very simple yet challenging, and Google Plus added a way for you and your friends to compete against each other. that was added coolness for those who are really competitive when it comes to games. the goal was simple, one has to fill/flood the 14×14 grid with only one color in 25 moves by selecting one of the six colors on the palette. you can check out an online sample here.

since i was idle and looking for something fun to do, i decided i would create a version of the game in python. the graphics needed was not very sophisticated and the logic was simple so i thought it was the perfect game to code while waiting for better tasks. now i know that sounds a little nerdy but i already said before that i’m learning python and it would be good to code using it in simple yet not ridiculous applications.

finally, let’s get to coding. i did not have time to refactor the codes so i have everything in a single file but i will try to discuss everything in detail.

we of course start with the essential initialization as shown below.

import pygame
import pygame._view
from pygame import *
import random

pygame.init()

DEFAULT_SCREEN_SIZE = [608, 448]
DEFAULT_TILE_SIZE = [32, 32]
DEFAULT_STEP_SIZE = 32
screen = pygame.display.set_mode(DEFAULT_SCREEN_SIZE)
display.set_caption('Flood-it!')

like the other tutorials, we start by importing pygame, and the random class library. we initialize the game by calling pygame.init() then we set the default values for the screen size, tile size, and the step size to use when iterating across the grid. finally we set the display mode and the caption to use in the window.

we then declare all variables the global variables needed in the game.

#declares all global variables
watchlist = None       #list of coordinates of all "flooded" tiles
checkedlist = None     #list of coordinates of tiles already updated
tiles = None           #list of coordinates of all tiles in the game
is_done = False        #tells whether game is done
update = False         #tells whether display must update
for_restart = False    #tells whether player opted to restart
movecount = None       #counts moves taken by the player
btncol = None          #list of control buttons

next, we create the essential functions. following are a few short ones.

#returns a color RGB values given a number from 1-6
def _getcolor(colornum):
    if colornum == 1:
        return [255, 105, 180] #hot pink
    elif colornum == 2:
        return [138, 43, 226] #blue violet
    elif colornum == 3:
        return [255, 255, 0] #yellow
    elif colornum == 4:
        return [255, 69, 0] #orange red
    elif colornum == 5:
        return [110, 139, 61] #dark olive green
    elif colornum == 6:
        return [0, 191, 255] #deep skyblue

#tells whether the two colors are the same
def _issamecolor(color1, color2):
    if color1[0] == color2[0] and color1[1] == color2[1] and color1[2] == color2[2]:
        return True
    return False

#adds a tile's coordinate to list of flooded tiles
def _addtowatchlist(coord, color):
    global tiles
    global watchlist
    adjcolor = tiles[str(coord[0])+"-"+str(coord[1])]
    if _issamecolor(color, adjcolor):
        _fill([coord[0], coord[1]], color)

#updates the color of the flooded tiles to the newly selected one
def _colorwatchlist(color):
    global checkedlist
    global watchlist
    for i in range(len(watchlist)):
        screen.blit(color, watchlist[i])
        checkedlist.remove(watchlist[i])
    pygame.display.update()

a built-in function for determining intersection of two lists exists but i took the long way of telling whether the two colors are the same because the built-in function got an issue with RGB values equal to 0.

next we create the function that will update the look of the grid after a user selects a color. the function basically checks if a tile must be flooded or not, adds it to the watch list if it must, then proceed to check adjacent tiles.

def _fill(coord, color):
    global checkedlist
    global tiles
    global watchlist

    #stops updates of already checked coordinates
    if checkedlist.__contains__(coord):
        return
    else:
        checkedlist.append(coord)
        #adds coordinate to watchlist if not existing
        if not watchlist.__contains__(coord):
            watchlist.append(coord)

    tile = pygame.Surface(DEFAULT_TILE_SIZE)
    tile.fill(color)
    screen.blit(tile, coord)
    if coord[0] - DEFAULT_STEP_SIZE >= 0:
        X = coord[0] - DEFAULT_STEP_SIZE
        Y = coord[1]
        _addtowatchlist([X, Y], color)

    if coord[0] + DEFAULT_STEP_SIZE < DEFAULT_SCREEN_SIZE[1]:         X = coord[0] + DEFAULT_STEP_SIZE         Y = coord[1]         _addtowatchlist([X, Y], color)     if coord[1] - DEFAULT_STEP_SIZE >= 0:
        X = coord[0]
        Y = coord[1] - DEFAULT_STEP_SIZE
        _addtowatchlist([X, Y], color)

    if coord[1] + DEFAULT_STEP_SIZE < DEFAULT_SCREEN_SIZE[1]:
        X = coord[0]
        Y = coord[1] + DEFAULT_STEP_SIZE
        _addtowatchlist([X, Y], color)

we then create the function that will render the game’s controls which are the six color buttons. the function basically draws the buttons on the screen and stores their location for later reference.

def _render_controls():
    #button initialization
    global btncol
    btncol = [dict(), dict(), dict(), dict(), dict(), dict()]

    #button color initialization
    btncol[0]['color'] = _getcolor(1)
    btncol[1]['color'] = _getcolor(2)
    btncol[2]['color'] = _getcolor(3)
    btncol[3]['color'] = _getcolor(4)
    btncol[4]['color'] = _getcolor(5)
    btncol[5]['color'] = _getcolor(6)

    #button position initialization
    btncol[0]['position'] = [512, 21]
    btncol[1]['position'] = [512, 95]
    btncol[2]['position'] = [512, 169]
    btncol[3]['position'] = [512, 243]
    btncol[4]['position'] = [512, 317]
    btncol[5]['position'] = [512, 391]

    #button bounds initialization
    btncol[0]['bounds'] = pygame.Rect(512, 21, 32, 32)
    btncol[1]['bounds'] = pygame.Rect(512, 95, 32, 32)
    btncol[2]['bounds'] = pygame.Rect(512, 169, 32, 32)
    btncol[3]['bounds'] = pygame.Rect(512, 243, 32, 32)
    btncol[4]['bounds'] = pygame.Rect(512, 317, 32, 32)
    btncol[5]['bounds'] = pygame.Rect(512, 391, 32, 32)

    for i in range(len(btncol)):
        pygame.draw.circle(screen, btncol[i]['color'] \
            , [btncol[i]['position'][0]+16, btncol[i]['position'][1]+16] \
            , 16)

    pygame.display.update()

the following functions are not really necessary but i wanted to add a little something to the game, rage faces! yes i’m at times pretty shallow that i enjoy rage faces. because of that, i created a function that will display a random rage face if a user wins or loses.

def _gameover():
    shade = pygame.Surface(DEFAULT_SCREEN_SIZE)
    shade.fill([0, 0, 0])
    shade.set_alpha(200)
    screen.blit(shade, [0, 0])

    imggameover = pygame.image.load('gameover.png')
    tilenum = random.randint(1, 4)
    rectangle = None
    if tilenum == 1:
        rectangle = pygame.Rect(0, 0, 320, 240)
    elif tilenum == 2:
        rectangle = pygame.Rect(320, 0, 320, 240)
    elif tilenum == 3:
        rectangle = pygame.Rect(0, 240, 320, 240)
    elif tilenum == 4:
        rectangle = pygame.Rect(320, 240, 320, 240)

    screen.blit(imggameover, [64, 104], rectangle)

    pygame.display.update()

def _success():
    shade = pygame.Surface(DEFAULT_SCREEN_SIZE)
    shade.fill([0, 0, 0])
    shade.set_alpha(200)
    screen.blit(shade, [0, 0])

    imgwin = pygame.image.load('win.png')
    tilenum = random.randint(1, 4)
    rectangle = None
    if tilenum == 1:
        rectangle = pygame.Rect(0, 0, 320, 240)
    elif tilenum == 2:
        rectangle = pygame.Rect(320, 0, 320, 240)
    elif tilenum == 3:
        rectangle = pygame.Rect(0, 240, 320, 240)
    elif tilenum == 4:
        rectangle = pygame.Rect(320, 240, 320, 240)

    screen.blit(imgwin, [64, 104], rectangle)

    pygame.display.update()

lastly, for the set of functions, we have the _init function that is supposed to start the game. it starts with initializing global variables then it proceeds to fill the grid with randomly colored tiles before. it then assigns the starting tile, then renders the controls.

def _init():
    global checkedlist
    global watchlist
    global tiles
    global movecount
    global for_restart
    checkedlist  = list()
    watchlist = list()
    tiles = dict()
    movecount = 0
    for_restart = False

    screen.fill(0) #color screen black

    #fills the grid with randomly colored tiles
    for i in range(14):
        for j in range(14):
            #sets coordinates
            X = DEFAULT_STEP_SIZE*i
            Y = DEFAULT_STEP_SIZE*j

            #gets random tile
            colornum = random.randint(1, 6)
            tile = pygame.Surface(DEFAULT_TILE_SIZE)
            color = _getcolor(colornum)
            tile.fill(color)
            tiles[str(X)+"-"+str(Y)] = color
            screen.blit(tile, [X, Y])

    #adds starting tile to watch list
    _fill([0, 0], tiles['0-0'])

    #initializes first time coloring of watch list
    tile = pygame.Surface(DEFAULT_TILE_SIZE)
    tile.fill(tiles['0-0'])
    _colorwatchlist(tile)

    #renders the controls
    _render_controls()

finally, the _init function has to be called before the game begins. then program will enter the loop that contains the logic of the game as shown below.

_init()

while is_done == False:
    global is_done
    global update
    global movecount
    global for_restart
    global btncol

    #checks for changes in direction and validates it
    for e in event.get():
        color = None

        if e.type == MOUSEBUTTONDOWN:
            for i in range(len(btncol)):
                if btncol[i]['bounds'].collidepoint(e.pos):
                    color = _getcolor(i+1)
        elif e.type == QUIT:
            is_done = True
        elif e.type == KEYUP:
            update = True
            if e.key == K_ESCAPE:
                is_done = True
            elif e.key == K_r:
                _init()
            elif e.key == K_a:
                color = _getcolor(1)
            elif e.key == K_s:
                color = _getcolor(2)
            elif e.key == K_d:
                color = _getcolor(3)
            elif e.key == K_z:
                color = _getcolor(4)
            elif e.key == K_x:
                color = _getcolor(5)
            elif e.key == K_c:
                color = _getcolor(6)

        if color != None and movecount < 25:
            if not for_restart:
                movecount += 1
                tile = pygame.Surface(DEFAULT_TILE_SIZE)
                tile.fill(color)
                for i in range(len(watchlist)):
                    _fill(watchlist[i], color)
                _colorwatchlist(tile)
                display.set_caption('Flood-it! '+str(movecount)+'/25')

        if len(watchlist) == 196:
            if not for_restart:
                _success()
                for_restart = True
            display.set_caption('Flood-it! Congratulations. You won!')

        if movecount == 25 and len(watchlist) != 196:
            if not for_restart:
                _gameover()
                for_restart = True
            display.set_caption('Flood-it! GAME OVER!')

    if update == True:
        #TODO: call update function
        update = False

first, the program will go through the events that might have occurred. a valid event could be a mouse-click on a button or pressing of any of the dedicated keys to any color. the program will then attempt to update the grid then see if user has reached the move limit or the goal of flooding the whole grid was already achieved.

whew, that was quite long. i hope you will get to enjoy this game and add your own enhancements (better tiles perhaps). you can download the codes and the images here. again, make sure you have python 2.7 and the compatible pygame library. until next time! (:

Tagged , , , , , ,

when a program throws an exception, the problem is not always in the code


it has been quite awhile since i last posted something. well although i could say that a number of things came up, i cannot say that they ate most of my time so as to prevent me from posting anything. truth is i could have posted a few lines but held myself back at the last moment for behind all the wordplay there was really nothing much to glean from them. well i’m no writer really but i’m writing here and i believe that if you want to be a good one, take it as a responsibility to feed your readers something sensible. surely there could be some sense in everybody’s life.

anyway, just last week i began testing this web service i created for our client. it was supposed to be utilized by the online banking system for the activation of various requests. this web service should run in the frontend and should call another web service from the backend (the mainframe specifically) for backend side request processing. during the development i had to work with stubs because i was working in our office. one can argue that i should’ve done it in the client’s development environment if permitted but i actually prefer working with stubs until i got most of the requirements done since the solution is easier to test that way.

so the time for testing the code came and i had to deploy the web service in our client’s development environment. it was pretty easy since i basically only had to change connection strings and a few more values in the web configuration file. i was informed that it was okay to input any value for the parameters of the web service method since there was no validation at the moment but when i did BAM! i received the error “Conversion from SOAP failed” when my code tried to invoke the exposed method of the mainframe web service and the mainframe’s transaction counter did not increment. i was cool at first thinking that surely i just got a line or two wrong. but when i found out that the exception was thrown by .Net’s wsdl.exe generated proxy when it called invoke, my expression was like “what the hell happened? what’s wrong?” i’ve used it before and i knew that the generated proxy is supposed to work with very little or no modification. still i tried to think of things that could’ve caused it like maybe i used the wrong wsdl file or i could not connect to the backend web service, etc. i tried applying the fixes i could think of but to no avail.

when i got back to the office, i was like “okay we’re unsuccessful but surely a lot of people could be encountering the same problem. if i could solve this, it will be something good to blog about” so i spent the remaining office hours researching on ways to connect to a mainframe web service and the common problems but surprisingly none of the google hits helped or even enlightened me. i thought i was doomed. i thought the best source would be the ones who previously worked with the web service but they are all not connected to our client now. another testing day passed and the problem remained unsolved until just last monday i tried inputting nothing in the parameters and the mainframe web service returned a different error code that was more expected. it was talking of invalid inputs. that gave me the idea that my problem was just a matter of giving the right inputs from the very beginning since there was very minimal modification done to my code. i went to the person in charge with the mainframe side of the project and asked for sample inputs and everything worked fine. well we’re not done yet testing the web service until the end of the defined transaction flow but it put end to the problem with the mainframe side of requests.

now this post was supposed to offer some sort of fix in a form of codes or instructions like i mentioned earlier. but since the problem was somewhere between the keyboard and the chair let me just leave an advice.

do not overanalyze.

we got as far as thinking of capturing packets exchanged between servers to check for discrepancies. it was a good thing that we had to postpone it because of the absence of the needed tools in the service. it would have been another failed fix in the list.

take time to consider all possible sources of the problem no matter how little or ridiculous they are.

in my case i completely ignored the possibility that the problem was caused by the wrong inputs. hadn’t i thought of giving the web service blank inputs, i wouldn’t have found out the answer to my problem.

lastly, use valid inputs whenever possible.

seriously, there’s no harm trying the right inputs especially when someone who knows them is just around.

hope you learned something from my experience. have a nice day!

Tagged , , , , , , , , ,

rendering background image using PyGame in Python 2.7


it has been quite a while since i last posted anything regarding my endeavors in game programming. the past weeks have been quite busy for i was working on the backend of another mobile application. anyway, i was able to continue studying python this weekend and inspired by Final Fantasy III which I’ve been playing using an emulator lately, I decided working on rendering more visually pleasing backgrounds. yes, you read that right, Final Fantasy III. why am i playing such an old game? i’m quite into light weight games. and i figured it would be better to start with 2D games.

this is a short tutorial on rendering backgrounds using a single image source. here’s a sample of the perfectly symmetric background i was able to produce.

Background Demo

the sample background of a 2D game

the codes are available HERE.

the source image

since i’m only working on a demo, i simply copied the source image from a game installed in my computer. that game is Deadly Sin. if we are going to create more maps just for practice, we can find good resource from the games already installed in our machines like this one.

Tile Set

the tile set from Deadly Sin

it is a 512px X 480px image composed of different tiles used in the game to create the various stages and maps.

the map

i decided to put all details of a particular place in one file and call it map. this way i can produce as many different maps as i want completely independent of the game.

import pygame
from pygame import *

# fills a 16 X 14 map with rectangles representing tiles to be rendered from the
# source images to the game display

#assigns source image
SOURCE = pygame.image.load('images/TileA4.png')

p = pygame.Rect(288, 0, 32, 32) #area of source image containing pavement
g = pygame.Rect(416, 0, 32, 32) #area of source image containing grass
s = pygame.Rect(288, 160, 32, 32) #area of source image containing sand/dirt
b = pygame.Rect(288, 320, 32, 32) #area of source image containing bush

#matrix containing the pattern of tiles to be rendered
MAP = [[p,p,p,p,p,p,p,p,p,p,p,p,p,p,p,p],\
       [p,b,b,b,b,b,p,p,p,p,b,b,b,b,b,p],\
       [p,b,b,g,g,g,g,p,p,g,g,g,g,b,b,p],\
       [p,b,g,g,g,g,g,p,p,g,g,g,g,g,b,p],\
       [p,b,g,g,g,p,p,p,p,p,p,g,g,g,b,p],\
       [p,b,g,s,g,p,s,s,s,s,p,g,s,g,b,p],\
       [s,s,s,s,s,s,s,g,g,s,s,s,s,s,s,s],\
       [s,s,s,s,s,s,s,g,g,s,s,s,s,s,s,s],\
       [p,b,g,s,g,p,s,s,s,s,p,g,s,g,b,p],\
       [p,b,g,g,g,p,p,p,p,p,p,g,g,g,b,p],\
       [p,b,g,g,g,g,g,p,p,g,g,g,g,g,b,p],\
       [p,b,b,g,g,g,g,p,p,g,g,g,g,b,b,p],\
       [p,b,b,b,b,b,p,p,p,p,b,b,b,b,b,p],\
       [p,p,p,p,p,p,p,p,p,p,p,p,p,p,p,p]]

as shown, we first loaded the image that will be used by the map and set it as its SOURCE. next we defined the areas from the source image that we would like to be rendered on our game screen as tiles p, g, s, and b. lastly, we created a 16 X 14 matrix that will contain the tiles we created. there could have been a better way of creating the matrix that is less space complex, but i intended it to be that way so we can directly compare the matrix with the pattern we have in mind just by looking at it.

the game

unlike the previous tutorials, this game file will not make use of any user input.

import pygame
from pygame import *
import map1

DEFAULT_SCREENSIZE = [512, 448] #16 X 14 grid with 32px X 32px cell

pygame.init()

screen = pygame.display.set_mode(DEFAULT_SCREENSIZE)
display.set_caption('Background Rendering Demo')

#loops through map to set background
for y in range(len(map1.MAP)):
    for x in range(len(map1.MAP[y])):
        location = (x*32, y*32)
        screen.blit(map1.SOURCE, location, map1.MAP[y][x])

updated = False
going = True

while going:
    if updated == False:
        pygame.display.update()
        updated = True

    for e in event.get():
        if e.type == QUIT: #checks if close button was clicked
            going = False

pygame.quit()

to discuss it in detail, first we import the modules we need including the map we created named map1.py.

import pygame
from pygame import *
import map1

next, we initialize our screen and display.

DEFAULT_SCREENSIZE = [512, 448] #16 X 14 grid with 32px X 32px cell

pygame.init()

screen = pygame.display.set_mode(DEFAULT_SCREENSIZE)
display.set_caption('Background Rendering Demo')

then we go to the most essential part of this tutorial where we need to loop through our map and assign the tiles to our screen.

#loops through map to set background
for y in range(len(map1.MAP)):
    for x in range(len(map1.MAP[y])):
        location = (x*32, y*32)
        screen.blit(map1.SOURCE, location, map1.MAP[y][x])

lastly, we perform the loop that will keep the game running. note that checking if the display was updated was only done to reduce overhead.

updated = False
going = True

while going:
    if updated == False:
        pygame.display.update()
        updated = True

    for e in event.get():
        if e.type == QUIT: #checks if close button was clicked
            going = False

pygame.quit()

that’s it for this week. hope you find this useful folks!

Tagged , , , , ,

Metro Manila Flood App (MMFA)


screenshot 1 a good news came today. after months of training, the team finally got to upload its first app in the app store. i was not part of its development but i’m breaking the news just the same because i’m proud of our three people working on iOS, namely Elbert Yagaya, Lei Montas, and Pope Abella.

the team has been around for more than a year now but there weren’t much activities in the past so i can say we are pretty much still starting. and this is a good start so far. it only took an hour or so before the app got approved. well maybe that was because it’s not very complex. but it’s doubtlessly useful.

you can get the app for free at iTunes. basically it’s an app that can monitor flood prone areas around Metro Manila and send real time notifications to its users regarding the current flood situation.

screenshot 2 screenshot 3
Tagged , , , , ,

Simple Sprite Animation in Python 2.7


a picture of the simple animation

a picture of the simple animation

the codes for this simple animation can be downloaded here.

last time i posted my sample of the snake game written in Python 2.7 using PyGame. like what i already said it was supposed to be a part of my self training on python game programming and it went pretty well. i have one comment though, i was trying to accomplish a lot in one sample project. so i decided that from this week on i’ll take it one step at a time by creating tiny projects that i could use as a template when i finally have something big to code. well not really big for i’m only programming games for leisure, the more approriate term would be complex, something more complex to code. and so for my first tiny project i’m going to have simple sprite animation.

anyway, since i’m a lover OOP i decided i’ll try creating a collection of modules that will function as a class library or, if lucky, a personal framework for creating my type of python games. my plan is to build this collection in the weeks to come. so let us begin.

THE UTILITIES LIBRARY

this library will contain classes that could be useful to most if not all other classes. classes that are not part of the game design but useful in carrying out particular tasks common to most other classes. i named the file ‘lib_utils.py’ the prefix ‘lib_’ is supposed to tell which of my python files function as libraries and which are not. it currently contains only one class which is the StaticFunction class that i use for creating static methods on my classes.

#used for creating static functions
class StaticFunction():
    def __init__(self, function):
        self.__call__ = function

THE SPRITES BASE LIBRARY

the sprites base library which i named ‘lib_spritesbase.py’ will contain classes that are essential to sprite animation. currently it contains classes such as Direction, ImageSet, and SimpleSprite

Direction class

#class enumerating valid directions
class Direction():
    UP, DOWN, RIGHT, LEFT, UPRIGHT, UPLEFT, DOWNRIGHT, DOWNLEFT = \
        'Y+', 'Y-', 'X+', 'X-', 'X+Y+', 'X-Y+', 'X+Y-', 'X-Y-'

    #checks if a given direction is valid
    def is_direction(direction):

        #compares direction to provided direction values
        if direction == Direction.UP:
            return True
        elif direction == Direction.DOWN:
            return True
        elif direction == Direction.RIGHT:
            return True
        elif direction == Direction.LEFT:
            return True
        elif direction == Direction.UPRIGHT:
            return True
        elif direction == Direction.UPLEFT:
            return True
        elif direction == Direction.DOWNRIGHT:
            return True
        elif direction == Direction.DOWNLEFT:
            return True

        #no match was found
        return False

    #makes the function 'is_direction' static to Direction class
    is_direction = StaticFunction(is_direction)

if you checked out my last post, this class and the SnakeMove class mentioned there are basically the same. the only thing i did was to give it a name that is not tied into any game and add other possible directions of movement in a game like the up right, up left, down right, and down left.

ImageSet class

#stores a collection of images to be used by a sprite
class ImageSet():
    def __init__(self, img_up=None, img_down=None, img_right=None \
                , img_left=None , img_upright=None, img_upleft=None \
                , img_dowright=None, img_downleft=None):

        #direction was used as key assuring that one direction corresponds to
        #one image
        self.images = {Direction.UP:img_up, Direction.DOWN:img_down \
            , Direction.RIGHT:img_right, Direction.LEFT:img_left \
            , Direction.UPRIGHT:img_upright, Direction.UPLEFT:img_upleft \
            , Direction.DOWNRIGHT:img_dowright, Direction.DOWNLEFT:img_downleft}

    #gets the image for a given direction
    def get_image(self, direction=None):
        #parameter validation
        if direction == None:
            raise Exception('Direction cannot be null.')
        if Direction.is_direction(direction) != True:
            raise Exception('Invalid direction.')

        return self.images[direction]

it’s not that i perfectly adhere to coding standards but we know how difficult it is whenever we don’t know the right parameters to a particular function provided in a third party class library, especially when working with weakly typed languages like python. because of this i always try to come up with a form of enumeration of valid values and provide some sort of validation no matter how shallow they maybe sometimes.

the ImageSet will be used as a container of all images that a simple sprite will use. since there could be a lot of ways to pass the filenames of images to a sprite class i made it a point that the my sprite classes will only accept an instance of ImageSet.

SimpleSprite class

class SimpleSprite(pygame.sprite.Sprite):
    def __init__(self, direction=None, position=None, images=None):

        #parameter validation
        if None in [direction, position, images]:
            raise Exception('None of the parameters could be equal to "None"')
        if Direction.is_direction(direction) != True:
            raise Exception('Invalid direction.')
        if isinstance(images, ImageSet) != True:
            raise Exception('Images assigned not of type ImageSet.')

        self.imageset = images
        self.position = position
        self.change_direction(direction)

    def change_direction(self, direction):
        #parameter validation
        if Direction.is_direction(direction) != True:
            raise Exception('Invalid direction.')
        if self.imageset.images[direction] == None:
            raise Exception('No image set for given direction.')

        self.image = image.load(self.imageset.get_image(direction))
        self.size = self.image.get_size()
        self.rect = self.image.get_rect()
        self.rect.topleft = self.position
        self.direction = direction

    #must be overridden in a sub-class
    def move(self):
        pass

SimpleSprite will be the base class of my simple sprites, meaning those sprites that has only one image per direction. as shown in the code it has a change_direction function and a stub of move function. i included change_direction since a change of direction doesn’t necessarily entail moving away from one’s position. the move function on the other hand may be omitted but i chose to include it to make it appear more like a base class.

THE SPRITES

i decided to put all my sprites in one file which i named ‘sprites.py’. currently it only has one class which is the Arrow class. the Arrow class is simply a sprite with an arrow for an image. since the whole point of this mini-project is to be able to move around a surface using a sprite that changes its appearance accordingly, i simply downloaded an image of an arrow here and rotated it to point to different directions.

class Arrow(SimpleSprite):
    def __init__(self, direction, position, images):
        super(Arrow, self).__init__(direction, position, images)

    def change_direction(self, direction):
        super(Arrow, self).change_direction(direction)

    def move(self, direction=None, limits=None):
        #parameter validation
        if Direction.is_direction(direction) != True:
            raise Exception('Invalid direction.')
        if limits == None:
            raise Exception('Limits must not be empty.')

        #gets size of step and creates new position
        newposition = self.position
        if direction in [Direction.UP, Direction.DOWN]:
            stepsize = self.size[1]
            if direction == Direction.UP:
                newposition = [self.position[0], (self.position[1]-stepsize)%limits[1]]
            else:
                newposition = [self.position[0], (self.position[1]+stepsize)%limits[1]]
        elif direction in [Direction.RIGHT, Direction.LEFT]:
            stepsize = self.size[0]
            if direction == Direction.RIGHT:
                newposition = [(self.position[0]+stepsize)%limits[0], self.position[1]]
            else:
                newposition = [(self.position[0]-stepsize)%limits[0], self.position[1]]

        self.position = newposition
        self.rect.topleft = newposition

as shown, initialization of this sub-class as well as the change_direction function simply calls that of the parent class or super class. also notice that the move function was overridden here. i intended the move function to be overridden because characters in game would not probably always move in the same way. once in a while we introduce characters that behave differently.

in the case of the Arrow class movement simply means moving to the next cell specified by a direction if we are going to take the whole surface as a grid.

THE CONFIGURATION FILE

i decided to have a separate file for configuration which i named ‘conf_arrow.py’. it isn’t really necessary but i decided to come up with it anyway. this will be loaded by the main game module everytime the game starts. this way, i can have multiple configurations with minimal modification to the main game module. with different configuration files i’ll be able to test different settings by simply changing a line in the main game module which loads the configuration to be used.

import lib_spritesbase
from lib_spritesbase import Direction, ImageSet, StaticFunction

class ArrowConfig:
    SCREENSIZE = [640, 480]
    INITIAL_DIRECTION = Direction.LEFT
    UPDATE_SPEED = 50
    INITIAL_POSITION = [0, 0]
    IMAGES = None
    BACKGROUND = 0

    def init():
        ArrowConfig.IMAGES = ImageSet('sprites/up2.png', 'sprites/down2.png' \
                , 'sprites/right2.png' , 'sprites/left2.png')

    init = StaticFunction(init)

in this file we set the size of the screen, the initial direction of the sprite, the speed by which the display is updated, the starting position of our sprite, the color of the background, and the set of images to be used. the ArrowConfig class will hold the configuration.

THE GAME MODULE

i named the main game module ‘arrow.py’. the filename of the module is not very crucial, i just figured i would name it after the sprite that i’m going to use in the game in it.

import pygame
from pygame import *

import sprites
from sprites import Arrow, Direction

import conf_arrow
from conf_arrow import ArrowConfig

pygame.init()
ArrowConfig.init()

#global variable initialization
updatetime = pygame.time.get_ticks() + ArrowConfig.UPDATE_SPEED
screen = pygame.display.set_mode(ArrowConfig.SCREENSIZE)
isdone = False

#sprite initialization
arrow = Arrow(ArrowConfig.INITIAL_DIRECTION, ArrowConfig.INITIAL_POSITION \
            , ArrowConfig.IMAGES)

while isdone == False:
    screen.fill(ArrowConfig.BACKGROUND) #color screen with default color
    direction = None
    for e in event.get():
        #checks key press and sets direction or end game
        if e.type == KEYUP:
            if e.key == K_ESCAPE:
                isdone = True
            elif e.key == K_UP:
                direction = Direction.UP
            elif e.key == K_DOWN:
                direction = Direction.DOWN
            elif e.key == K_RIGHT:
                direction = Direction.RIGHT
            elif e.key == K_LEFT:
                direction = Direction.LEFT

            #if sprite is facing wrong direction replace with appropriate sprite
            #else move sprite by one step to specified direction
            if arrow.direction != direction:
                arrow.change_direction(direction)
            else:
                arrow.move(direction, ArrowConfig.SCREENSIZE)

    currenttime = pygame.time.get_ticks()
    global updatetime
    if currenttime >= updatetime:
        screen.blit(arrow.image, arrow.rect)
        pygame.display.update()
        updatetime = currenttime + ArrowConfig.UPDATE_SPEED

since the contents of this module is pretty long. let’s try to take it few lines at a time.

import pygame
from pygame import *

import sprites
from sprites import Arrow, Direction

import conf_arrow
from conf_arrow import ArrowConfig

the first few lines are used for importing classes from the other modules mentioned earlier. observing the import lines, it is noticeable that i used * when importing from pygame. to be honest here i still don’t know the classes i need for a game by their names so i simply included all. however the following import lines are generally preferred since it specify the classes to be used from one class library and/or module. it will reduce ambiguity and possible overhead.

pygame.init()
ArrowConfig.init()

what follows is the initialization for pygame and our configuration.

#global variable initialization
updatetime = pygame.time.get_ticks() + ArrowConfig.UPDATE_SPEED
screen = pygame.display.set_mode(ArrowConfig.SCREENSIZE)
isdone = False

#sprite initialization
arrow = Arrow(ArrowConfig.INITIAL_DIRECTION, ArrowConfig.INITIAL_POSITION \
            , ArrowConfig.IMAGES)

next we initialize some variables to be used in the game. ‘updatetime’ holds the next time by which the display will update, the ‘screen’ represents the game screen, while ‘isdone’ states whether the game is over or not. ‘arrow’ on the other hand represents our sprite.

the implementation of the game flow is just a little simpler than the sample snake game.

    screen.fill(ArrowConfig.BACKGROUND) #color screen with default color
    direction = None
    for e in event.get():
        #checks key press and sets direction or end game
        if e.type == KEYUP:
            if e.key == K_ESCAPE:
                isdone = True
            elif e.key == K_UP:
                direction = Direction.UP
            elif e.key == K_DOWN:
                direction = Direction.DOWN
            elif e.key == K_RIGHT:
                direction = Direction.RIGHT
            elif e.key == K_LEFT:
                direction = Direction.LEFT

            #if sprite is facing wrong direction replace with appropriate sprite
            #else move sprite by one step to specified direction
            if arrow.direction != direction:
                arrow.change_direction(direction)
            else:
                arrow.move(direction, ArrowConfig.SCREENSIZE)

first, the screen will be filled by the set background color in our configuration file. next, we are going to check if any key was pressed. if ‘esc’ was pressed, we need to end the game by setting the ‘isdone’ variable to True. Otherwise, we get the direction then change a sprites direction or move it.

	
    currenttime = pygame.time.get_ticks()
    global updatetime
    if currenttime >= updatetime:
        screen.blit(arrow.image, arrow.rect)
        pygame.display.update()
        updatetime = currenttime + ArrowConfig.UPDATE_SPEED

we then check if it’s already time to update the screen. if it is, we update the screen and set the next update time. else we’re going to do nothing.

if you got Python2.7 installed with PyGame. you can try running this game template by downloading the code here. by default .py files open with python so you can just double click on ‘arrow.py’. or you can open console, redirect to the folder where you saved the files then type ‘python arrow.py’.

feel free to comment on this post. have a nice day everyone!

Tagged , , , , , , ,

Sample Snake Game in Python 2.7


The codes are available here.

I was kind of idle once again in the office. For some reason we could not smoothly work in our client’s office yet and proceed with the system integration testing of our work. I had a lot of time to kill and I figured I could use it to continue my study in python programming. Yes I know most CS students start with python, but for us it was C so I’m still learning the language now. I’ve read through the manual for the basic stuffs months ago but I never really worked on any exercise. And just last Tuesday (December 20) I thought, how else would you want to practice python programming than by creating a sample of the snake game? Yes I found it funny. I’m pretty shallow that way. But thinking it over, game programming is enjoyable and the snake game is pretty simple. It would be worth a shot. So here’s my work.

Note: If you want to try this on your own, please make sure that you have Python2.7 installed and the corresponding version of PyGame.

THE SPRITES

I put all the sprites in one file named sprites.py. The class names are pretty ridiculous for I was sort of doing things on the fly and I am sorry for that. I even used the name Apple instead of Food so for this game you are going to have an apple-eating snake.

To begin, we need to put the following line to import the pygame module:

import pygame

The Apple Class

class Apple(pygame.sprite.Sprite):
    #private constants
    _DEFAULT_COLOR = [255, 0, 0] #red
    _DEFAULT_SIZE = [10, 10]
    def __init__(self, color, size, position):
        #parameter validation
        if color == None:
            color = Apple._DEFAULT_COLOR
        if size == None:
            size = Apple._DEFAULT_SIZE
        if position == None:
            raise Exception('Invalid position.')

        #initialization
        self.color = color
        self.size = size
        self.image = pygame.Surface(size)
        self.image.fill(color)
        self.rect = self.image.get_rect()
        self.rect.topleft = position

This one’s pretty straight-forward. We have here an apple class accepting parameters for the color, size, and position upon creation of an instance. I provided default values for the color and size and a little parameter validation since it’s going to be a part of a class library.

Note: All sprites are just composed of square areas in the screen of about 10px X 10px filled by a certain color.

The Callable Class

class Callable:
    def __init__(self, anycallable):
        self.__call__ = anycallable

This class is only used to implement static functions in the sprite classes.

The Snake Class

The Snake class has with it three internal classes namely _SnakeTail, _SnakeHead, and SnakeMove with the first two as private. I figured, If I would like to use images rather than solid colors in the future, I would most certainly dedicate a different image to the head compared to the body. Hence, I decided to separate the snake’s head from its tail.

Like what I did in the Apple class, I also provided default values for the attributes.

    #private constants
    _DEFAULT_COLOR = [0, 255, 0] #green
    _DEFAULT_SIZE = [10, 10] #10px X 10px
    _DEFAULT_POSITION = [30, 30] #space given to tail of length 2

The _SnakeTail Class

    class _SnakeTail(pygame.sprite.Sprite):
        def __init__(self):
            #initialization
            self.tiles = []

        def add_tile(self, color, size, position):
            #creates a new tile
            tile = pygame.Surface(size)
            tile.fill(color)
            rect = tile.get_rect()
            rect.topleft = position

            self.tiles.append({'image':tile, 'rect':rect})

The snake’s tail is composed of an array of color-filled square areas that I call tiles for lack of a better term. It also has an add_tile function that will make the tail grow longer. The add_tile function creates another instance of a tile of a given color and size and adds it to the tail’s array of tiles. Once the tail is re-rendered on screen, it should appear longer.

The _SnakeHead Class

    class _SnakeHead(pygame.sprite.Sprite):
        def __init__(self, color, size, position):
            #initialization
            self.image = pygame.Surface(size)
            self.image.fill(color)
            self.rect = self.image.get_rect()
            self.rect.topleft = position

The _SnakeHead class is very similar to the Apple class.

The SnakeMove Class

    class SnakeMove():
        UP = '1Y'
        DOWN = '-1Y'
        RIGHT = '1X'
        LEFT = '-1X'

        #checks a direction's validity
        def SnakeMove_is_member(direction):
            if direction == Snake.SnakeMove.UP:
                return True
            elif direction == Snake.SnakeMove.DOWN:
                return True
            elif direction == Snake.SnakeMove.RIGHT:
                return True
            elif direction == Snake.SnakeMove.LEFT:
                return True

            return False

        #makes the function 'is_member' a static function
        SnakeMove_is_member = Callable(SnakeMove_is_member)

The creation of this class would have been avoided if I settled on accepting just some set of values for directions in making the snake move but it was against to what I’m used to. Since I wanted sprites.py to function like a standard class library I wanted it to implement a uniform way of using the classes and their functions and sort of inform developers about it. The SnakeMove class functions like an enum class in C#, this way developers won’t have to guess valid direction values once they deal with making the snake move. All they have to do is pass a constant from this class as a parameter to the Snake class’ move function.

The class has a SnakeMove_is_member static function which is used for validating the direction parameter in the Snake class’ move function. The static class was created with the help of the previously shown Callable class.

The Snake Class Functions

Initialization

    def __init__(self, color, size, position):
        #parameter validation
        if color == None:
            color = Snake._DEFAULT_COLOR
        if size == None:
            size = Snake._DEFAULT_SIZE
        if size[0] != size[1]:
            raise Exception('Invalid tile size. Width and height must be equal.')
        if position == None:
            position = Snake._DEFAULT_POSITION

        self.color = color
        self.size = size
        self.head = Snake._SnakeHead(color, size, position)
        self.tail = Snake._SnakeTail()
        tailposition = [(position[0] - size[0]), position[1]]
        self.tail.add_tile(color, size, tailposition)
        tailposition = [(position[0] - 2*size[0]), position[1]]
        self.tail.add_tile(color, size, tailposition)

The initialization of the snake class simple involves validating the parameters and assigning default values for missing paramaters and creating the instance for the snake’s head and tail. As shown in the code, the initial length of the tail is 2 tiles. All in all, the Snake sprite has a color, size, head, and tail attributes.

Movement

    def move(self, direction, frame_width, frame_height):
        #parameter validation
        if Snake.SnakeMove.SnakeMove_is_member(direction) != True:
            raise Exception('Invalid movement direction.')

        #initializes new position
        stepsize = self.head.image.get_rect()[2] #gets the size of the head tile
        newheadposition = [self.head.rect.topleft[0], self.head.rect.topleft[1]]
        if direction == Snake.SnakeMove.UP:
            newheadposition[1] = (newheadposition[1]-stepsize)%frame_height
        if direction  == Snake.SnakeMove.DOWN:
            newheadposition[1] = (newheadposition[1]+stepsize)%frame_height
        if direction == Snake.SnakeMove.RIGHT:
            newheadposition[0] = (newheadposition[0]+stepsize)%frame_width
        if direction == Snake.SnakeMove.LEFT:
            newheadposition[0] = (newheadposition[0]-stepsize)%frame_width

        if self.occupies_position(newheadposition):
            return False

        #moves the head to its new position
        newtileposition = self.head.rect.topleft
        self.head.rect.topleft = newheadposition

        #moves the tail tiles to its respective new positions
        for count in range(len(self.tail.tiles)):
            prevtileposition = self.tail.tiles[count]['rect'].topleft
            self.tail.tiles[count]['rect'].topleft = newtileposition
            newtileposition = prevtileposition

        return True

As mentioned earlier, the move function first checks if the supplied direction is valid. If not, it will raise an exception. If it is, it will proceed to determing the next position of each tile starting with the head.

stepsize = self.head.image.get_rect()[2] #gets the size of the head tile

In this line, we are assuming that the size of the head is equal with the all the other tiles in the snake’s body.

if self.occupies_position(newheadposition):
    return False

Here we are making sure that the snake is not trying to move to a space that its body already occupies. If it is, then the snake won’t be able to move and the game will be over.

The remaining lines deal with moving each tile to the position of the one before it. If all goes well then the function will return True, signifying that the movement was successful.

Collision Detection

    #checks if this snake's body occupies a given position
    def occupies_position(self, position):
        #parameter validation
        if position[0] == None or position[1] == None:
            return True

        if self.head.rect.topleft[0] == position[0] \
            and self.head.rect.topleft[1] == position[1]:
                return True

        for count in range(len(self.tail.tiles)):
            if self.tail.tiles[count]['rect'].topleft[0] == position[0] \
            and self.tail.tiles[count]['rect'].topleft[1] == position[1]:
                return True

        return False

PyGame already has a built-in function for collision detection involving objects with rect attribute but I found it quite late. I did this one and it was pretty good enough for me. As the function name implies, this function checks whether the snake is occupying a given position.

Lengthening the Tail

    def lengthen_tail(self, number, current_direction):
        #parameter validation
        if number is None:
            number = 1
        if Snake.SnakeMove.SnakeMove_is_member(current_direction) != True:
            raise Exception('Invalid movement direction.')

        size = self.size[0]
        color = self.color

        for count in range(number):
            lastindex = len(self.tail.tiles) - 1
            X = self.tail.tiles[lastindex]['rect'].topleft[0]
            Y = self.tail.tiles[lastindex]['rect'].topleft[1]

            #determines position of new tile
            if current_direction == Snake.SnakeMove.UP:
                Y = Y - size + (count*size)
            elif current_direction == Snake.SnakeMove.DOWN:
                Y = Y + size + (count*size)
            elif current_direction == Snake.SnakeMove.RIGHT:
                X = X - size + (count*size)
            elif current_direction == Snake.SnakeMove.LEFT:
                X = X + size + (count*size)

            self.tail.add_tile(color, self.size, [X, Y])

Since the _SnakeTail class is supposed to be private, I provided this function on the Snake class. This should be the one that developers using my sprites library use when making the Snake grow longer. I included an number parameter just in case someone wants to make the snake grow longer by more than one tile. Determining the position for the new tile involves checking the snake’s current direction to ensure that addition of tiles will be done on the right end and following the right direction of movement.

THE GAME

The main file for this snake game is game.py. It handles the display and game flow.

Initialization

import pygame
import pygame._view
from pygame import *
from sprites import Snake
from sprites import Apple
import random

The lines above shows the modules imported by the game file. Notice that only the Apple and Snake classes were imported from sprites.py.

pygame.init()

Initialize the game.

DEFAULT_SCREEN_SIZE = [640, 480]
INITIAL_DIRECTION = Snake.SnakeMove.RIGHT
DEFAULT_UPDATE_SPEED = 100

updatetime = pygame.time.get_ticks() + DEFAULT_UPDATE_SPEED

Some default values and update time initialization.

#screen initialization
screen = pygame.display.set_mode(DEFAULT_SCREEN_SIZE)
display.set_caption('Snake')

#sprite initialization
snake = Snake(None, None, None)
apple = None

Screen and sprites initialization.

is_done = False #signifies escape from game
is_over = False #signifies end of game by game rules
direction = None
score = 0
create_apple()

Initialization of variables that will be used in the game flow. Notice that we have is_done and is_over. create_apple was also called to create first instance of the apple.

Rendering

def render_snake():
    screen.blit(snake.head.image, snake.head.rect)
    for count in range(len(snake.tail.tiles)):
        screen.blit(snake.tail.tiles[count]['image']
            , snake.tail.tiles[count]['rect'])

This method renders the snake on screen. This simply displays all the tiles forming the image of the snake.

#renders the apple on screen
def render_apple():
    global apple
    screen.blit(apple.image, apple.rect)

Like the render_snake method, this method displays the apple on screen.

#creates a new apple
def create_apple():
    global apple
    global snake

    hlimit = (DEFAULT_SCREEN_SIZE[0]/Apple._DEFAULT_SIZE[0])-1
    vlimit = (DEFAULT_SCREEN_SIZE[1]/Apple._DEFAULT_SIZE[1])-1
    X, Y = None, None

    while snake.occupies_position([X, Y]) == True:
        X = random.randint(0, hlimit)*Apple._DEFAULT_SIZE[0]
        Y = random.randint(0, vlimit)*Apple._DEFAULT_SIZE[1]
    apple = Apple(None, None, [X, Y])

Notice that horiontal and vertical limits were computed first before generating a random position. This ensures that the position generated will be inside the area of the screen. Default values are used here ‘though, maybe we can make it configurable on a better version. We also keep on generating random positions if the current position is occupied by the snake.

The Game Flow

while is_done == False:
    screen.fill(0) #color screen black
    global direction
    if direction == None:
        direction = INITIAL_DIRECTION

    #checks for changes in direction and validates it
    for e in event.get():
        if e.type == KEYUP:
            if e.key == K_ESCAPE:
                is_done = True
            elif e.key == K_UP:
                if direction != Snake.SnakeMove.DOWN:
                    direction = Snake.SnakeMove.UP
            elif e.key == K_DOWN:
                if direction != Snake.SnakeMove.UP:
                    direction = Snake.SnakeMove.DOWN
            elif e.key == K_RIGHT:
                if direction != Snake.SnakeMove.LEFT:
                    direction = Snake.SnakeMove.RIGHT
            elif e.key == K_LEFT:
                if direction != Snake.SnakeMove.RIGHT:
                    direction = Snake.SnakeMove.LEFT

    #updates the display
    currenttime = pygame.time.get_ticks()
    global updatetime
    global is_over
    if is_over == False:
        if currenttime >= updatetime:
            moved = snake.move(direction, DEFAULT_SCREEN_SIZE[0], DEFAULT_SCREEN_SIZE[1])
            if moved == False:
                is_over = True
            if snake.occupies_position(apple.rect.topleft) == True:
                create_apple()
                snake.lengthen_tail(1, direction)
                global score
                score += 1
                display.set_caption('Snake: ' + str(score))

            render_apple()
            render_snake()
            pygame.display.update()
            updatetime += DEFAULT_UPDATE_SPEED
    else:
        display.set_caption('Snake: ' + str(score) + ' GAME OVER')

The flow as expected is implemented using a loop.

screen.fill(0) #color screen black

First we fill the screen with black.

    global direction
    if direction == None:
        direction = INITIAL_DIRECTION

    #checks for changes in direction and validates it
    for e in event.get():
        if e.type == KEYUP:
            if e.key == K_ESCAPE:
                is_done = True
            elif e.key == K_UP:
                if direction != Snake.SnakeMove.DOWN:
                    direction = Snake.SnakeMove.UP
            elif e.key == K_DOWN:
                if direction != Snake.SnakeMove.UP:
                    direction = Snake.SnakeMove.DOWN
            elif e.key == K_RIGHT:
                if direction != Snake.SnakeMove.LEFT:
                    direction = Snake.SnakeMove.RIGHT
            elif e.key == K_LEFT:
                if direction != Snake.SnakeMove.RIGHT:
                    direction = Snake.SnakeMove.LEFT

Then we check for changes in direction based on keyboard input. Notice that global direction was used to make things less confusing. After all only one direction is needed. Additional check was also placed to deem direction opposite the current one as invalid.

    #updates the display
    currenttime = pygame.time.get_ticks()
    global updatetime
    global is_over
    if is_over == False:
        if currenttime >= updatetime:
            moved = snake.move(direction, DEFAULT_SCREEN_SIZE[0], DEFAULT_SCREEN_SIZE[1])
            if moved == False:
                is_over = True
            if snake.occupies_position(apple.rect.topleft) == True:
                create_apple()
                snake.lengthen_tail(1, direction)
                global score
                score += 1
                display.set_caption('Snake: ' + str(score))

            render_apple()
            render_snake()
            pygame.display.update()
            updatetime += DEFAULT_UPDATE_SPEED
    else:
        display.set_caption('Snake: ' + str(score) + ' GAME OVER')

Updating the display depends on two things, one is if the game is not over yet and the other is if the update time was already reached.

    moved = snake.move(direction, DEFAULT_SCREEN_SIZE[0], DEFAULT_SCREEN_SIZE[1])
    if moved == False:
        is_over = True

If the game is not yet over and the update time was already reached, an attempt to move the snake is done. In case movement failed which is probably becaused the snake hit itself, the game will be over.

    if snake.occupies_position(apple.rect.topleft) == True:
        create_apple()
        snake.lengthen_tail(1, direction)
        global score
        score += 1
        display.set_caption('Snake: ' + str(score))

If movement was successful, it is determined if the snake passes through the position of the apple. If it does, then a new apple is created, the snake’s tail will be lengthened, the score will be incremented, and the score display will be updated.

    render_apple()
    render_snake()
    pygame.display.update()
    updatetime += DEFAULT_UPDATE_SPEED

To cap off the updates, all the elements will be re-rendered and the update time will be set to a future time.

On the other hand, if the game is already over, the updates will simply stop and the display will flash GAME OVER together with the score.

Wow this post is pretty lengthy but I hope someone might find it useful at least for comparisons haha. Feel free to comment ‘though I’d be moderating them. Have a nice day everyone!

Tagged , , , , ,

BotFactory


so i was idle lately (or must i say most of the time) and i have always wanted something to do that involves software development that is worth my while. no i’m not planning to develop an enterprise level application for profit, at least not at the moment. i simply want to test if i could make something good out of my learning. as we all know good programming skills is just as precious as having the capability to generate new ideas for an application. and that’s why i’m practicing.

anyway back in college i worked on an online implementation of feedforward artificial neural networks for my thesis or what we call special problem (SP). it was pretty successful. if it was not, i wouldn’t have graduated because a fully accomplished SP was a requirement to graduate. however, i of course have a number of disappointments. i guess i was on a rush those days that i wasn’t able to plan the system well. it was done and it passed scrutiny but behind it was quite a list of wrong decisions.

now that i have a lot more time to work on whatever i want, i would love to create a similar application. only this time it will be a windows application so that i can have the network training process run on the background as  a service as oppose to running it on the browser like what was in my SP.

this application i will call BotFactory. by that i don’t mean spam bots but really virtual robots that can be trained on certain tasks and assist their creators. i’m planning to use the same learning algorithm i used in my SP but this time i will employ the methods for speeding up the learning process. i wanted to do that in my SP before but i didn’t have enough time to test them so i just dropped them from the things i wanted to include in the system. i’m also planning to put into this little project all the things i know about software design and optimization at least just for practice. this can be good. who knows? maybe by the end of 2012 i’m already being assisted by a number of virtual robots in decision making haha. running the application should not be a problem. the processes involved particularly the training process is very computationally intensive but will only use very little resource. time complexity and is the thing that should get me worried. hopefully i’ll be able to think of a great optimization approach. wish me luck folks.

the details are still sketchy but if you would like to collaborate that will be cool. just leave a reply. (:

Tagged ,
Follow

Get every new post delivered to your Inbox.

Join 39 other followers