Sunday 22 April 2012

Fishing game: early stages

I'm playing around with Python, which seems to be a nice programming language. It's free to download and there are versions for all sorts of computers including PC, Mac and Linux. It is fairly lenient on syntax, with no silly semi-colons at the end of each line. You don't have to round off FOR loops or IF conditions with an EndFor or a curly bracket. It also seems to run fairly quickly and you can do lots of interesting things with it. People have written extensions to add extra functions, so it can be adapted to a huge variety of uses.

I have been working with a book called "Python Programming For The Absolute Beginner", which has covered the basics well. I'm now ready to try something a bit more challenging, so I have started a little game. This will be a "fishing" game, where you have to catch fish using a harpoon.

So far I have animated the water and created a boat which can be moved left and right using keys. There is a harpoon gun on the boat which can be rotated, and the boat bobs up and down as the waves move past.

I'll be creating fish which swim past under the boat, and you have to aim your harpoon at the fish. Different fish will give more points, and there will be fish to avoid such as sharks and electric eels. You'll be able to sell your catch to get better equipment such as a better boat, faster harpoon, stun grenade etc.

I've been getting used to object-oriented programming, which is quite a new concept for me. It's a way of organising your program by splitting it up into chunks which manage themselves. So, there's an object called Boat which has code to make it move, and bob up and down. Another object is the gun, and it need to contain code which allows it to rotate and follow the boat around.

Drawing the screen in Python takes some getting used to. There's a plug-in module called Pygame which handles the graphics, but you need to do quite a bit to get it working. In Small Basic you just have to say "here's a sprite", but in Python you have to say: "Create a sprite object. Open an image. Apply the image to the surface of the sprite. Copy the sprite's surface onto the screen's surface. Tell the screen to update itself."

You can also ignore sprites altogether and just draw the images directly onto the screen myself. In the example so far I have done both. The waves are drawn onto the screen manually, as is the gunbarrel. The boat and the gun-base are Sprites. I don't know which one I prefer. I don't even know why someone would do one rather than the other. If you know, please leave a comment.



So far, I like the way it's moving. The graphics are a touch ugly. Python doesn't seem to anti-alias, so the edges are quite rough. I'll work on tarting up the bitmaps later when I have it working properly.

Image resources are here.
Download the source code here.



#wave

import pygame,math

pygame.init()

window = pygame.display.set_mode((750, 600))
pygame.display.set_caption('Wave')
screen = pygame.display.get_surface()


def loadImageFile( fileName, useColorKey = False ):
   
    try:
        image = pygame.image.load( fileName )
    except pygame.error:
        raise IOError from "File " + fileName + " not found."

    # To speed things up, convert the images to SDL's internal format.
    image = image.convert()

    if useColorKey is True:
        # Use the color of the pixel located at (0,0) as our color-key
        colorkey = image.get_at( (0,0) )
        image.set_colorkey( colorkey, pygame.RLEACCEL )

    # Return the image
    return image


class Wave():
    """a moving wave"""
    def __init__(self,x):
        self.x = x
        self.surface = pygame.image.load("wave.png")

    def Drawme(self):
        screen.blit(self.surface, (self.x,10))

       
    def pos(self):
        return self.x

    def Moveme(self):
        self.x -= 3
        if self.x <-740:
            self.x += 1480

class Boat(pygame.sprite.Sprite):
    """a sprite that bobs"""
    def __init__(self,gunbase,gunbarrel):
        self.depth=0
        self.gunbase = gunbase
        self.gunbarrel = gunbarrel
        pygame.sprite.Sprite.__init__(self)
        self.image = loadImageFile("boat.bmp",True)
        self.rect = self.image.get_rect()
        self.rect.topleft=(350,10)
        self.dir=0

       
    def turn(self, direction):
        "turn some amount"
        oldCenter = self.rect.center
        self.dir = direction
        if direction==-1:
            self.image = loadImageFile("boat1.bmp", True)
        elif direction==1:
            self.image = loadImageFile("boat2.bmp", True)
        self.rect = self.image.get_rect()
        self.rect.center = oldCenter

    def Move(self,dist):
        if self.rect.left+dist >0 and self.rect.right+dist<750:
            self.rect.move_ip(dist,0)
            self.gunbase.rect.move_ip(dist,0)
            self.gunbarrel.movex(dist)

    def Bob(self,wave1,wave2):
        x = wave1.pos()
        if x > self.rect.center[0]:
            x = wave2.pos()
        olddepth = self.depth
        diff = math.fabs((x - self.rect.center[0]-40)%750)
        self.depth= (math.fabs(375-diff))/375
        self.rect.top = (self.depth*20+5)
        self.gunbase.rect.top = (self.rect.top+50)
        self.gunbarrel.setY(self.rect.top+70)
        if self.depth <(olddepth) and self.dir!=-1:
            #rotate up
            self.turn(-1)
        elif self.depth>(olddepth)and self.dir!=1:
            #rotate down
            self.turn(1)

class Gunbase(pygame.sprite.Sprite):
    """An attached gunbase"""
    def __init__(self):
        pygame.sprite.Sprite.__init__(self)
        self.image = loadImageFile("gunbase.bmp",True)
        self.rect = self.image.get_rect()
        self.rect.topleft=(400,100)

class Turret:
    def __init__(self):
        self.x = 413
        self.y = 80
        self.image = pygame.image.load("gun.bmp")
        self.imageblack = pygame.image.load("gun.bmp")
        image = self.image
        self.baseImage = self.image
        self.dir = 0
        image.set_colorkey(image.get_at((0,0)))
       

    def turn(self, amount):
        self.dir += amount
        self.image = pygame.transform.rotate(self.baseImage, self.dir)
        self.rect = self.image.get_rect()


    def movex (self, dist):
        self.x +=dist

    def setY(self,y):
        self.y = y
               
    def draw (self):
        screen.blit(self.image, [(self.x - self.image.get_rect().width/2),(self.y - self.image.get_rect().height/2)])

    def drawblack (self):
        screen.blit(self.imageblack, [(self.x - self.image.get_rect().width/2),(self.y - self.image.get_rect().height/2)])

    def turrettipx(self):
        return math.floor(self.x + (math.sin(math.radians(self.dir))*20))

    def turrettipy(self):
        return math.floor(self.y + (math.cos(math.radians(self.dir))*20))

def main():
    done=False
    clock = pygame.time.Clock()
    mainscreen = pygame.Rect(0,65,750,535)
    topbar = pygame.Rect(0,0,750,65)
    wave1 = Wave(0)
    wave2 = Wave(740)
    gunbarrel = Turret()
    gunbase = Gunbase()
    boat = Boat(gunbase,gunbarrel)
    while done==False:
        #movewave
        wave1.Moveme()
        wave2.Moveme()
        #draw wave
        screen.fill([168,254,255],mainscreen)
        screen.fill([255,255,255],topbar)
        wave1.Drawme()
        wave2.Drawme()
        dist=0
        for event in pygame.event.get(): # User did something
            if event.type == pygame.QUIT: # If user clicked close
                done=True # Flag that we are done so we exit this loop
        keys = pygame.key.get_pressed()
        if keys[pygame.K_RIGHT]:
            dist=3
        elif keys[pygame.K_LEFT]:
            dist=-3
        if keys[pygame.K_a]:
            gunbarrel.turn(-5)
       
        #move boat
        boat.Move(dist)
        #bob boat
        boat.Bob(wave1,wave2)
        boatsprite=pygame.sprite.RenderPlain(boat)
        boatsprite.update()
        boatsprite.draw(screen)
        gunbasesprite=pygame.sprite.RenderPlain(gunbase)
        gunbasesprite.update()
        gunbasesprite.draw(screen)
        gunbarrel.draw()
        #draw turrent tip
        #pygame.draw.circle(screen,[0,0,0],[gunbarrel.turrettipx(),gunbarrel.turrettipy()],5,0)

        # Go ahead and update the screen with what we've drawn.
        # This MUST happen after all the other drawing commands.
        pygame.display.flip()
        clock.tick(80)
    pygame.quit()

main()

No comments:

Post a Comment