Pythonism

writing about my life

Game using Python Curses (Linux)

leave a comment »

I set out to try and make a short script to create a playable game using the fewest lines of code. I opted to run the game in a terminal, because setting up a low res graphics window using this was what I reckoned would be the shortest code listing.

Curses is in the Python standard library, so again we have something with minimal fuss to implement. I actually found the result to be quite playable, and may even try to develop other games using this as a framework. Because it’s simple there are many easy possibilities to tinker and modify, for the amateur coder. I guess what we have is about the same complexity as Pong. This should make anyone very full of admiration for programmers in the old days who could make games that ran on hardware with only a few KB of RAM available. ZX-81 being only 1KB unexpanded back in my childhood.

the only python dependency is Pyglet, so do:

$ sudo pip install pyglet

I used espeak to make some game sounds so you need that too, it’s very likely to be on most linux distros. as is Python 2.7, which is what’s needed here.

Run it in a terminal that’s been full-screened by F11. On my 1920×1080 display that gives you the whole screen.

The key controls are:

y = up
b = down
g = left
h = right

#!/usr/bin/python

# import stuff

import curses, pyglet, os
from random import randint as r
from time import time, sleep

# set up game sounds

os.system('espeak "dead" -s 250 -w a.wav')
os.system('espeak "game over mother" -w b.wav')
sleep(1)
alert = pyglet.media.load('a.wav', streaming=False)
game_over = pyglet.media.load('b.wav', streaming=False)

# create curses terminal window with colours

stdscr = curses.initscr()
curses.start_color()
curses.curs_set(0)
win = curses.newwin(62,238, 0, 0)
win.nodelay(1)
curses.init_pair(1, curses.COLOR_BLUE, curses.COLOR_BLUE)
curses.init_pair(2, curses.COLOR_RED, curses.COLOR_RED)

# define a predator controlled by the user

class Predator():

    def __init__(self,xpos,ypos,xvel,yvel):

        self.xpos=xpos
        self.ypos=ypos
        self.xvel=xvel
        self.yvel=yvel

    def move(self):

        self.xpos+=self.xvel
        self.ypos+=self.yvel

    def bounce(self):

        if self.xpos < 3 or self.xpos > 57:
            self.xvel *= -1
        if self.ypos < 3 or self.ypos > 233:
            self.yvel *= -1

    def draw(self):

        win.addstr(self.xpos,self.ypos,"  ",curses.color_pair(2))
        win.addstr(self.xpos+1,self.ypos,"  ",curses.color_pair(2))
        win.addstr(self.xpos,self.ypos+1,"  ",curses.color_pair(2))
        win.addstr(self.xpos+1,self.ypos+1,"  ",curses.color_pair(2))
        win.refresh()

    def steer(self):

        w = win.getch()
        if w == 98 and self.xvel < 3:
            self.xvel += 1
        if w == 121 and self.xvel > -3:
            self.xvel -= 1
        if w == 103 and self.yvel > -3:
            self.yvel -= 1
        if w == 104 and self.yvel < 3:
            self.yvel += 1


# define prey that can be eaten and bounces around the screen

class Prey():

    def __init__(self,xpos,ypos,xvel,yvel):

        self.xpos=xpos
        self.ypos=ypos
        self.xvel=xvel
        self.yvel=yvel

    def move(self):

        self.xpos+=self.xvel
        self.ypos+=self.yvel

    def bounce(self):

        if self.xpos == 1 or self.xpos == 60:
            self.xvel *= -1
        if self.ypos == 2 or self.ypos ==236:
            self.yvel *= -1

    def draw(self):

        win.addstr(self.xpos,self.ypos," ",curses.color_pair(1))
        win.refresh()

    def eaten(self):

        if abs(self.xpos - phil.xpos) < 3 and abs(self.ypos - phil.ypos) <3:
            return True


ti = time()
a=[]

# make some prey

for x in range(25):
    a.append(Prey(r(5,55),r(5,233),r(0,2)-1,r(0,2)-1))

# instantiate a predator

phil = Predator(30,119,0,0)

l=len(a)

while a:

    time_taken = time()-ti
    score = str(int((l-len(a))*17800)/(time_taken))
    score_line = " prey left: "+str(len(a))+" ---------"+" time taken:"+str(int(time_taken))+" ----- score: " + score + "  "

    win.box(0,0)
    win.addstr(0,76,score_line,1)
 
    for ghosh in a[:]:
        if ghosh.eaten():
            a.remove(ghosh)
            alert.play()

    for ghosh in a:
        ghosh.bounce()
        ghosh.move()
        ghosh.draw()


    phil.steer()
    phil.move()
    phil.bounce()
    phil.draw()

    sleep(0.03)
    win.clear()

for xx in range(2):

    game_over.play()
    sleep(2)
    win.addstr(30,111,"GAME OVER\n\n",1)
    win.addstr(32,110,"Score: " + score + "  \n\n",1)
    win.refresh()
   
Advertisements

Written by Luke Dunn

August 15, 2018 at 11:10 am

Posted in programming

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.

%d bloggers like this: