Remaking a classic arcade game using python

  • (3 Pages)
  • +
  • 1
  • 2
  • 3

36 Replies - 2909 Views - Last Post: 01 October 2019 - 09:42 PM Rate Topic: -----

#1 albert003   User is offline

  • D.I.C Addict

Reputation: 37
  • View blog
  • Posts: 791
  • Joined: 15-December 14

Remaking a classic arcade game using python

Posted 22 July 2019 - 08:09 PM

Thought I would challenge my python ability and try to remake the classic 1983 arcade game Spyhunter. I finished drawing the player car and I was able to move it around the screen perfectly. I am still in the process of drawing the enemy cars as well as the back ground and thought I'd better organize the whole thing before I make more progress on the game. Right now, I am using functions to draw everything so this example I show will be a mix and match of my original program and what I am planning to do. I realise the arcade game was probably written in C++ and I couldn't replicate everything but I thought I would try. I figure I would use inheritance and the game would be the derived class inheriting from the other classes. I'm still not sure whether this would be a good idea or not but I have an idea that each map of the game would be an object and would contain an internal counter, when the player reaches a certain time on that map, the game would move on to the next map.

This is the original arcade game which I am trying to replicate
https://www.youtube....h?v=fDXNvElulik

Whether it works or not, I think it would be an excellent challenge.

Could I get an honest opinion if I'm on the right track how I plan to organize the game or if anyone has input to make my game cleaner, organized or better I would appreciate it.

The picture is how the game currently looks in its current version using just functions. Apparently, I can't post the image of the game.

import pygame,random,math
from math import pi#
# Define some colors

black = (0, 0, 0)
white = (255, 255, 255)
green = (0, 255, 0)
red = (255, 0, 0)
darkgreen = (0,102,0)
pink = (255,0,255)
deepskyblue = (0,191,255)
dirt = (204,102,0)
carrot = (237,145,33)
grey = (224,224,224)
blue = (0, 0, 255)

pygame.init()

size = (830, 700)#x y
screen = pygame.display.set_mode(size)

pygame.display.set_caption("Spy Hunter")

done = False

clock = pygame.time.Clock()
font = pygame.font.SysFont('Calibri', 25, True, False)

ldirtroad = []
for i in range(3000):
    x = random.randrange(143, 180)
    y = random.randrange(0, 800)
    ldirtroad.append([x, y])

lredlist = []
for i in range(200):
    x = random.randrange(155, 168)
    y = random.randrange(0, 800)
    lredlist.append([x, y])

rdirtlist = []
for i in range(3000):
    x = random.randrange(621, 663)
    y = random.randrange(0, 800)
    rdirtlist.append([x, y])

rredlist = []
for i in range(200):
    x = random.randrange(635, 645)
    y = random.randrange(0, 800)
    rredlist.append([x, y])

trees1 = []
for i in range(25):
    x = random.randrange(108, 125)
    y = random.randrange(0, 50)
    trees1.append([x, y])


class Move(object):
    def __init__(self):
        self.xspeed = 0
        self.yspeed = 0
        self.xcord = 100
        self.ycord = 100
        
    def Crash(self):
        #car passes rough road
        #car crashes into another car
        pass
    
    def Bump(self):
        #bumping into a car moving it to one side
        pass
    
    def Swirve(self):
        #car runs over puddle and is moved to one
        #direction or the other
        pass
    
class Weapons(object):
    def __init__(self):
        self.smokescreen = 2
        self.oilslick = 2

    def Smoke(self):#player car smoke screen
        if self.smokescreen == 0:
            pass#Nothing happens
        else:
            self.smokescreen - 1

    def Oil(self):#player smoke screen
        if self.oilslick == 0:
            pass
        else:
            self.oildslick - 1

    def Guns(self):#front guns on car
        pass

class Cars(object):#Draws the cars for the game
    def __init__(self):
        self.lives = 3#number of player lives 

    def Player(self):
           pygame.draw.line(screen,white,[386 + x,453 + y],[415 + x,453 + y],10)#front wheels
            pygame.draw.line(screen,white,[386 + x,483 + y],[415 + x,483 + y],10)#back wheels
            pygame.draw.line(screen,white,[400 + x,440 + y],[400 + x,500 + y],20)#centre of car538
            pygame.draw.line(screen,white,[390 + x,442 + y],[390 + x,498 + y],2)
            pygame.draw.line(screen,white,[389 + x,444 + y],[389 + x,496 + y],2)
            pygame.draw.line(screen,white,[388 + x,446 + y],[388 + x,494 + y],2)
            pygame.draw.line(screen,white,[387 + x,448 + y],[387 + x,492 + y],2)
            pygame.draw.line(screen,grey,[393 + x,453 + y],[410 + x,453 + y],18)#front hood
            pygame.draw.line(screen,black,[392 + x,443 + y],[395 + x,443 + y],2)#left head light
            pygame.draw.line(screen,black,[405 + x,443 + y],[408 + x,443 + y],2)#right head light    
            pygame.draw.line(screen,black,[397 + x,447 + y],[397 + x,449 + y],2)#front air intake
            pygame.draw.line(screen,black,[397 + x,449 + y],[403 + x,449 + y],2)#horizontal line
            pygame.draw.line(screen,black,[404 + x,447 + y],[404 + x,450 + y],2)
            pygame.draw.line(screen,white,[410 + x,442 + y],[410 + x,498 + y],2)
            pygame.draw.line(screen,white,[411 + x,444 + y],[411 + x,496 + y],2)
            pygame.draw.line(screen,white,[412 + x,446 + y],[412 + x,494 + y],2)
            pygame.draw.line(screen,white,[413 + x,448 + y],[413 + x,492 + y],2)
            pygame.draw.ellipse(screen,grey,[391 + x,475 + y,25,27],11)#grey shade on back of car
            pygame.draw.line(screen,deepskyblue,[389 + x,449 + y],[389 + x,490 + y],3)
            pygame.draw.line(screen,deepskyblue,[413 + x,449 + y],[413 + x,490 + y],3)
            pygame.draw.line(screen,pink,[391 + x,448 + y],[391 + x,494 + y],3)
            pygame.draw.line(screen,pink,[411 + x,448 + y],[411 + x,494 + y],3)
            pygame.draw.line(screen,pink,[391 + x,494 + y],[394 + x,500 + y],3)#back left pink line
            pygame.draw.line(screen,pink,[411 + x,494 + y],[408 + x,500 + y],3)#back right pink line
            #pygame.draw.arc(screen,red,[50,50,50,50],0,pi)
            #first and second are x and y
            #third and fourth are the size
            pygame.draw.arc(screen,black,[392 + x,457 + y,20,10],0,pi,5)#Front window
            pygame.draw.line(screen,black,[401 + x,462 + y],[401 + x,475 + y],22)#side windows
            pygame.draw.ellipse(screen,black,[390 + x, 467 + y, 25, 27],11)
            pygame.draw.line(screen,white,[389 + x,460 + y],[393 + x,465 + y],2)#left front white line
            pygame.draw.line(screen,white,[407 + x,465 + y],[413 + x,460 + y],2)#right front white line
            pygame.draw.line(screen,white,[389 + x,480 + y],[393 + x,476 + y],2)#left centre white line
            pygame.draw.line(screen,white,[407 + x,476 + y],[413 + x,480 + y],2)#right centre white line
            pygame.draw.line(screen,black,[393 + x,486 + y],[408 + x,486 + y],7)#coves open area of ellipse
            pygame.draw.line(screen,white,[391 + x,488 + y],[396 + x,480 + y],2)#left rear line
            pygame.draw.line(screen,white,[406 + x,479 + y],[408 + x,488 + y],2)#right rear line
            pygame.draw.line(screen,white,[401 + x,464 + y],[401 + x,481 + y],13)#top of car 

    def Enforcer(self):
        #passanger shoots players driver
        pass

    def Switchblade(self):
        #knives come out of wheels causing player to crash
        pass

    def Redcar(self):
        #red car
        pass

    def Motorcycle(self):
        pass

    def Roadlord(self):
        #guns dont damage it only
        #oil slick, smoke sscreen or bumping to side of
        #road hurts it
        pass

    def WVbug(self):
        pass

    def Rig(self):
        #semi truck that brings a new player car
        #when it crashes
        pass

class Game(Cars,Weapons,Move):
    #will display each map for the game
    #there will be 10 maps
    def map1(self):
        pass

    def map2(self):
        pass
    
while not done:
    # --- Main event loop
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            done = True

        elif event.type == pygame.KEYDOWN:
            # Figure out if it was an arrow key. If so
            # adjust speed.
            if event.key == pygame.K_LEFT:
                xspeed = -3
            elif event.key == pygame.K_RIGHT:
                xspeed = 3
            elif event.key == pygame.K_UP:
                yspeed = -3
            elif event.key == pygame.K_DOWN:
                yspeed = 3
 
        # User let up on a key
        elif event.type == pygame.KEYUP:
            # If it is an arrow key, reset vector back to zero
            if event.key == pygame.K_LEFT or event.key == pygame.K_RIGHT:
                xspeed = 0
            elif event.key == pygame.K_UP or event.key == pygame.K_DOWN:
                yspeed = 0



    xcord = xcord + xspeed
    ycord = ycord + yspeed
    
    screen.fill(black)

    Car(screen,xcord,ycord)
    pygame.display.flip()

    clock.tick(60)

# Close the window and quit.
pygame.quit()


This post has been edited by albert003: 22 July 2019 - 08:16 PM


Is This A Good Question/Topic? 1
  • +

Replies To: Remaking a classic arcade game using python

#2 DK3250   User is offline

  • Pythonian
  • member icon

Reputation: 561
  • View blog
  • Posts: 1,791
  • Joined: 27-December 13

Re: Remaking a classic arcade game using python

Posted 23 July 2019 - 04:13 AM

Hi albert003,

Next time, please make sure that the code can actually run without banal errors. The code in post #1 does not.

A few comments though:

You spend a lot of lines on drawing the car - presumably you plan to re-draw everything at every screen update. I suggest you make the drawing once and for all in a small pygame.Surface; then you just need to move this surface around and you get all the pygame collision detection for free.

The methods of class Move belongs (in my opinion) to the class Car (singularis, not plural).

I don't have a full overview, but I think you need a class Background.
I'm not sure about the Weapons - they affect the Car methods, so maybe they belong there.

A Game class is fine, but I'd focus on the graphical elements first.
Was This Post Helpful? 3
  • +
  • -

#3 baavgai   User is offline

  • Dreaming Coder
  • member icon


Reputation: 7501
  • View blog
  • Posts: 15,544
  • Joined: 16-October 07

Re: Remaking a classic arcade game using python

Posted 23 July 2019 - 04:48 AM

View PostDK3250, on 23 July 2019 - 06:13 AM, said:

I suggest you make the drawing once and for all in a small pygame.Surface; then you just need to move this surface around and you get all the pygame collision detection for free.

This. 100% this. Actually, 50% this. The other 50% should be given looking at pygame.sprite. Sprite is the ancient name from games design for stuff that moves. It's basically the same idea as the surface, and in fact you can use a surface as a sprite, but sprite offers the extra tools for the job.
Was This Post Helpful? 3
  • +
  • -

#4 albert003   User is offline

  • D.I.C Addict

Reputation: 37
  • View blog
  • Posts: 791
  • Joined: 15-December 14

Re: Remaking a classic arcade game using python

Posted 23 July 2019 - 02:11 PM

Good advice, I remade the program using sprites and I thought I could use the constructor to draw each detail of the car then make an object. I figured out how to draw a single line using sprite but I can't figure out how to add to it and put more lines. am I on the right track?. All I can figure out is to draw a single line.

This is the program so far



import pygame,random
 
black = (0, 0, 0)
white = (255, 255, 255)
green = (0, 255, 0)
red = (255, 0, 0)
darkgreen = (0,102,0)
pink = (255,0,255)
deepskyblue = (0,191,255)
dirt = (204,102,0)
carrot = (237,145,33)
grey = (224,224,224)
blue = (0, 0, 255)

pygame.init()

size = (830, 700)#x y
screen = pygame.display.set_mode(size)

class Car(pygame.sprite.Sprite):
    def __init__(self):
        self.oilslick = 3
        self.smokescreen = 3
        self.lives = 3
        super(Car, self).__init__()
        self.surf = pygame.Surface((200, 60))
        self.surf.fill((white))
        self.rect = self.surf.get_rect()
        self.surf = pygame.Surface((10, 55))
        self.surf.fill((white))
        self.rect = self.surf.get_rect() 

    def Move(self):#moves car on screen
        pass

    def Oil(self):#oild slick
        pass

    def smoke(self):#smoke screen
        pass

    def chances(self):#player gets 3 lives in the game
        self.lives = 3
        pass

    
ldirtroad = []
for i in range(3000):
    x = random.randrange(143, 180)
    y = random.randrange(0, 800)
    ldirtroad.append([x, y])

lredlist = []
for i in range(200):
    x = random.randrange(155, 168)
    y = random.randrange(0, 800)
    lredlist.append([x, y])

rdirtlist = []
for i in range(3000):
    x = random.randrange(621, 663)
    y = random.randrange(0, 800)
    rdirtlist.append([x, y])

rredlist = []
for i in range(200):
    x = random.randrange(635, 645)
    y = random.randrange(0, 800)
    rredlist.append([x, y])


    
def Leftdrawdirtonsides():
    pygame.draw.line(screen, carrot, [160, 0], [160, 800], 27)#Left side
    for i in range(len(ldirtroad)):
        # Draw the dirt flakes on service road
        pygame.draw.circle(screen, carrot, ldirtroad[i], 1)

    for i in range(len(lredlist)):
        # Draw the red flakes on service road
        pygame.draw.circle(screen, red, lredlist[i], 1)

def Rightdrawdirtonsides():
    pygame.draw.line(screen, carrot, [640, 0], [640, 800], 27)#Right side
    for i in range(len(rdirtlist)):#
        # Draw the dirt flakes on service road
        pygame.draw.circle(screen, carrot, rdirtlist[i], 1)

    for i in range(len(rredlist)):
        # Draw the red flakes on service road
        pygame.draw.circle(screen, red, rredlist[i], 1)

def Grass():
    pygame.draw.line(screen, darkgreen, [0, 0], [0, 800], 310)#left side
    pygame.draw.line(screen, darkgreen, [735, 0], [735, 800], 210)#right side 165


player = Car()


done = False
 
def Player():
    screen.blit(player.surf,(620,500))
    screen.blit(player.surf,(625,500))
    
clock = pygame.time.Clock()
 
 
# -------- Main Program Loop -----------
while not done:
    for event in pygame.event.get(): 
        if event.type == pygame.QUIT: 
            done = True
 
    
    screen.fill(black)
    Grass()
    Leftdrawdirtonsides()
    Rightdrawdirtonsides()

    # Draw all the spites
    
    Player()
    pygame.display.flip()
 
    clock.tick(60)
 
pygame.quit()



Was This Post Helpful? 1
  • +
  • -

#5 DK3250   User is offline

  • Pythonian
  • member icon

Reputation: 561
  • View blog
  • Posts: 1,791
  • Joined: 27-December 13

Re: Remaking a classic arcade game using python

Posted 23 July 2019 - 04:31 PM

In this answer I'll only focus on your Car class.

From the pygame doc:

Quote

When subclassing the Sprite, be sure to call the base initializer before adding the Sprite to Groups. For example:

class Block(pygame.sprite.Sprite):

    # Constructor. Pass in the color of the block,
    # and its x and y position
    def __init__(self, color, width, height):
       # Call the parent class (Sprite) constructor
       pygame.sprite.Sprite.__init__(self)

       # Create an image of the block, and fill it with a color.
       # This could also be an image loaded from the disk.
       self.image = pygame.Surface([width, height])   # Se note below..!
       self.image.fill(color)

       # Fetch the rectangle object that has the dimensions of the image
       # Update the position of this object by setting the values of rect.x and rect.y
       self.rect = self.image.get_rect()

Note:
The example shows how to create a surface.
In this surface you must draw the car image i.e. a modified form of line 106-143 of post #1. Make a separate function/method for this. It will keep your code more clean.

What you do in line 25 doesn't make sense to me.
The example uses this form:
pygame.sprite.Sprite.__init__(self)

I guess you can use super() in stead, but then you must use the correct syntax:
super().__init__(args)
I've not tried this myself, so slightly unsure if it works.

You make two surfaces with the same name, - only the last one will take effect.

As baavgai says, the pygame sprite can make some shortcuts for you - but it's almost a whole small API in its own right. Either you need to learn this 'micro-language' or stay with pygame.surface and pygame.rect - in this particular game with few colliding sprites, it may be the easiest way...
Was This Post Helpful? 2
  • +
  • -

#6 DK3250   User is offline

  • Pythonian
  • member icon

Reputation: 561
  • View blog
  • Posts: 1,791
  • Joined: 27-December 13

Re: Remaking a classic arcade game using python

Posted 24 July 2019 - 02:21 AM

I like the visual result of the track and the dirt borders. I don't like the code, however. And I think you need a strategy for scrolling the background.

So, first I'll show how I'd clean-up your dirt track code.

Then we'll discuss the scrolling.

Combining the dirt-track and the scrolling and have sides active for sideways collision is next step.

Clean-up of dirtroad code:
You loop 3000 times generating small orange circles. Most of the circles, however, ends up in the full orange line. I suggest you only generate circles outside the orange line - and reduce the number of loops accordingly.
You distinguish between left and right sides; but can easily combine the two list (ldirtroad and rdirtroad) into a single 'dirtroad'.
Same with the red dots, you only need one list:
dirtroad = []
for i in range(1000):
    x = random.choice(list(range(143, 148))+
                      list(range(173, 180))+
                      list(range(621, 628))+
                      list(range(653, 663)))
    y = random.randrange(0, 800)
    dirtroad.append([x, y])

redlist = []
for i in range(400):
    x = random.choice(list(range(155, 168))+
                      list(range(635, 645)))
    y = random.randrange(0, 800)
    redlist.append([x, y])

I hope you see how orange x-positions are picked such that they only appear outside the full orange line, but include right and left side in a single loop of length 1000.

Naturally, the draw functions must be changed accordingly:
def draw_dirtonsides():
    pygame.draw.line(screen, carrot, [160, 0], [160, 800], 27)#Left side
    pygame.draw.line(screen, carrot, [640, 0], [640, 800], 27)#Right side

    for dirt in dirtroad:
        # Draw the dirt flakes on service road sides
        pygame.draw.circle(screen, carrot, dirt, 1)

    for red in redlist:
        # Draw the red flakes on service road
        pygame.draw.circle(screen, RED, red, 1)

I changed the color name from 'red' to 'RED'.
Note the pythonic loop structure:
for item in itemlist:
    # do something

End of clean-up.

Scroll:
Have you considered how to scroll the background? I guess not, otherwise the code would look different.
If you go back to the link from post #1 and look at the video, you will notice that the background has about 10 different track shapes (single track, double track, curved, narrow, etc.) running repeatedly - each can be 'decorated' with a number of different side features: Trees, dessert, geometric, etc. The end of last track fits to the start of first track.

So, you need to make 10 (or so) individual surfaces each with a fixed track configuration but with flexible (semi-random) track-side decorations. You can start with only 3 such background images.

The scrolling is then provided by moving the blit position of the two active background surfaces in each pass of the main loop.

ok, this was a big mouthful; take your time to work through it and let us see the outcome... B)
Was This Post Helpful? 1
  • +
  • -

#7 albert003   User is offline

  • D.I.C Addict

Reputation: 37
  • View blog
  • Posts: 791
  • Joined: 15-December 14

Re: Remaking a classic arcade game using python

Posted 25 July 2019 - 03:51 PM

It seems that using pygame.sprite.Sprite.__init__(self) is a more preferred way than using super. I have a good idea how to move the player car as well as the back ground. I'm still working on the details but for now, I am trying to work on drawing each car for the game. Once the drawings are finished and I can move the cars I'll work on moving the background.

I have 2 questions for you.
1. I made the changes you suggested as well and for some reason the red flakes are blue on the screen instead of red. I went line by line on my code and I can't figure out why its doing that when the game runs. Could you please tell me why or give me a hint how to fix it?

2. I see what you meant by using sprites is an easier way to draw the details of the game. I figured out how to draw two separate lines on the screen, I've been working on that part of the code trying to get each line to be a separate length and colour. I looked on pygame.org and found there are two functions called
pygame.sprite.Group()
add.()
Do I have the right idea how to make the sprites different lengths and colours?

This is the program
import pygame,random
 
black = (0, 0, 0)
white = (255, 255, 255)
green = (0, 255, 0)
red = (255, 0, 0)
darkgreen = (0,102,0)
pink = (255,0,255)
deepskyblue = (0,191,255)
dirt = (204,102,0)
carrot = (237,145,33)
grey = (224,224,224)
blue = (0, 0, 255)

pygame.init()

size = (830, 700)#x y
screen = pygame.display.set_mode(size)

class Car(pygame.sprite.Sprite):
    def __init__(self,white,red):
        self.oilslick = 3
        self.smokescreen = 3
        self.lives = 3
        pygame.sprite.Sprite.__init__(self)
        self.right1 = pygame.Surface((100, 2))
        self.right1.fill((red))
        #self.rect = self.right1.get_rect()
        self.surf = pygame.Surface((10, 50))
        self.surf.fill((white))
        #self.rect = self.surf.get_rect() 
        self.spritelisty = pygame.sprite.Group
        
    def Move(self):#moves car on screen
        pass

    def Oil(self):#oild slick
        pass

    def smoke(self):#smoke screen
        pass

    def chances(self):#player gets 3 lives in the game
        self.lives = 3
        pass

#object of player car
player = Car(white,red)

#list of every sprite
allsprites = pygame.sprite.Group()
allsprites.add(player)
###
dirtroad = []
for i in range(1000):
    x = random.choice(list(range(143, 148))+
                      list(range(173, 180))+
                      list(range(621, 628))+
                      list(range(653, 663)))
    y = random.randrange(0, 800)
    dirtroad.append([x, y])

redlist = []
for RED in range(400):
    x = random.choice(list(range(155, 168))+
                      list(range(635, 645)))
    y = random.randrange(0, 800)
    redlist.append([x,y])
    
def draw_dirtonsides():
    pygame.draw.line(screen, carrot, [160, 0], [160, 800], 27)#Left side
    pygame.draw.line(screen, carrot, [640, 0], [640, 800], 27)#Right side

    for dirt in dirtroad:
        # Draw the dirt flakes on service road sides
        pygame.draw.circle(screen, carrot, dirt, 1)

    for red in redlist:
        # Draw the red flakes on service road
        pygame.draw.circle(screen, RED, red, 1)    

def Grass():
    pygame.draw.line(screen, darkgreen, [0, 0], [0, 800], 310)#left side
    pygame.draw.line(screen, darkgreen, [735, 0], [735, 800], 210)#right side 165



done = False
 
def Player():
    screen.blit(player.surf,(610,500))#right1
    screen.blit(player.surf,(625,500))#centre
    
clock = pygame.time.Clock()
 
 
# -------- Main Program Loop -----------
while not done:
    for event in pygame.event.get(): 
        if event.type == pygame.QUIT: 
            done = True
 
    
    screen.fill(black)
    Grass()


    # Draw all the spites
    draw_dirtonsides()
    Player()
    pygame.display.flip()
 
    clock.tick(60)
 
pygame.quit()





Was This Post Helpful? 0
  • +
  • -

#8 DK3250   User is offline

  • Pythonian
  • member icon

Reputation: 561
  • View blog
  • Posts: 1,791
  • Joined: 27-December 13

Re: Remaking a classic arcade game using python

Posted 25 July 2019 - 09:49 PM

1.
You have a mix of 'RED' and 'red'.

I suggest you use capitals, 'RED', for the color i.e. in line 6 and 48; line 80 is ok.
Then you can use 'red' as a normal variable - as it is in line 78 and 80.

In line 64 you use 'RED' as a counter; often, such counters are named i, j or k - or in this case '_' (underscore) indicating that the counter value is not used for calculations.
As it is the value of 'RED' ends at 399 in line 64. Later in line 80 this value is interpreted as a hexadecimal color code, - hence the dark dots.

2.
Actually, I'm trying to talk you away from using pygames sprite object. I know that baavgai recommended this, but I think it will complicate things for you and you'll gain very little.
If you use it, super().__init__() works just fine.
Anyway, sprites are meant for things that move; a fixed line in the background does not (the whole background may move, but that's a different thing).

Comments:
What are you trying to accomplish in line 21? You send two constants to the constructor of Car. That doesn't make sense.

The small function starting line 90 is named 'Player'; a better name would be 'draw' - but why draw the same car two times in two different positions?
The function should be a method of Car.

Honestly, albert003, your code is full of lines without meaning: Line 26-28, 32, 50-53 - the program run just as well without these. You really need to tidy up your code.

I've worked ahead a bit, this game is not the simplest one you could choose.
I'll help you along, but prepared for a long and, sometimes, difficult journey.
Was This Post Helpful? 1
  • +
  • -

#9 albert003   User is offline

  • D.I.C Addict

Reputation: 37
  • View blog
  • Posts: 791
  • Joined: 15-December 14

Re: Remaking a classic arcade game using python

Posted 26 July 2019 - 01:42 PM

The cause of the red flakes appearing a different colour makes a lot of sense.

I was trying to figure out how to draw the lines on the screen and what I presented here was my last try and figuring it out. I was actually able to figure it out after I read your message on post #5 quote. Thank you for that hint.

These are the cars that are in the game.
http://www.igcd.net/game.php?id=297409

My idea is make a function for each car in the game and then I will work on moving the back ground of the game. Then once I draw each car, I will work on movement and collision.

I have a new question for you.

1. I figured out how to draw various lines using your suggestion, am I only able to draw lines using this method? I will need to be able to draw an arc and a ellipse when I need to draw the front and rear windows.


import pygame,random
 
black = (0, 0, 0)
white = (255, 255, 255)
green = (0, 255, 0)
RED = (255, 0, 0)
darkgreen = (0,102,0)
pink = (255,0,255)
deepskyblue = (0,191,255)
dirt = (204,102,0)
carrot = (237,145,33)
grey = (224,224,224)
blue = (0, 0, 255)

pygame.init()

size = (830, 700)#x y
screen = pygame.display.set_mode(size)

class Car(pygame.sprite.Sprite):
    def __init__(self,colour,width,height):
        self.oilslick = 3
        self.smokescreen = 3
        self.lives = 3
        super(Car, self).__init__()
        self.image = pygame.Surface([width,height])
        self.image.fill(colour)
        self.rect = self.image.get_rect()
        
    def Move(self):#moves car on screen
        pass

    def Oil(self):#oild slick
        pass

    def smoke(self):#smoke screen
        pass

    def chances(self):#player gets 3 lives in the game
        self.lives = 3
        pass

    def position(self,x,y):
        self.rect.x = x
        self.rect.y = y

def Draw():#draws player car
    block_group = pygame.sprite.Group()
    centre = Car(white,20,72)#object
    leftone = Car(white,2,68)
    centre.position(625,500)
    leftone.position(623,502)
    block_group.add(centre,leftone)
    block_group.draw(screen)
    

dirtroad = []
for i in range(1000):
    x = random.choice(list(range(143, 148))+
                      list(range(173, 180))+
                      list(range(621, 628))+
                      list(range(653, 663)))
    y = random.randrange(0, 800)
    dirtroad.append([x, y])

redlist = []
for j in range(400):
    x = random.choice(list(range(155, 168))+
                      list(range(635, 645)))
    y = random.randrange(0, 800)
    redlist.append([x,y])
    
def draw_dirtonsides():
    pygame.draw.line(screen, carrot, [160, 0], [160, 800], 27)#Left side
    pygame.draw.line(screen, carrot, [640, 0], [640, 800], 27)#Right side

    for dirt in dirtroad:
        # Draw the dirt flakes on service road sides
        pygame.draw.circle(screen, carrot, dirt, 1)

    for red in redlist:
        # Draw the red flakes on service road
        pygame.draw.circle(screen, RED, red, 1)    

def Grass():
    pygame.draw.line(screen, darkgreen, [0, 0], [0, 800], 310)#left side
    pygame.draw.line(screen, darkgreen, [735, 0], [735, 800], 210)#right side 165



done = False
 

    
clock = pygame.time.Clock()
 
 
# -------- Main Program Loop -----------
while not done:
    for event in pygame.event.get(): 
        if event.type == pygame.QUIT: 
            done = True
 
    
    screen.fill(black)
    Grass()
    Draw()

    # Draw all the spites
    draw_dirtonsides()
    Draw()
    pygame.display.flip()
 
    clock.tick(60)
 
pygame.quit()


Was This Post Helpful? 0
  • +
  • -

#10 DK3250   User is offline

  • Pythonian
  • member icon

Reputation: 561
  • View blog
  • Posts: 1,791
  • Joined: 27-December 13

Re: Remaking a classic arcade game using python

Posted 27 July 2019 - 06:42 AM

You spend too much time on the drawing thing. After all, the drawings are just that - images that you can make in whatever way you want. Probably much more efficient to use a specialised drawing program like Piskel or Paint.
That goes for the cars and the background as well. You can even use a photo if you want to...!

You should use you time making the code! The code can then load the pictures by pygame.image.load(); I know you have used this before.

So, albert003, focus on the code and make the pictures when you have the time.

This post has been edited by DK3250: 27 July 2019 - 06:43 AM
Reason for edit:: Typo

Was This Post Helpful? 0
  • +
  • -

#11 albert003   User is offline

  • D.I.C Addict

Reputation: 37
  • View blog
  • Posts: 791
  • Joined: 15-December 14

Re: Remaking a classic arcade game using python

Posted 29 July 2019 - 03:29 PM

I figured out how to display the score for the game and make it count off as the game runs. I still need to figure out to make the score move and only add points when the players car is moving forward, then stop when its idle or the car crashed. I wanted to get the score worked out before I connected the player moving forward to getting points. The problem is that in the original game, on the top right corner it shows 000000. The only way I could make it work was to add seven 0's instead of six and start the game at 999999. I tried to slice the first number (Which still doesn't work)but that seems like I'm doing this the hard way. Is there a simpler way to do this?.

This is the program


import pygame,random


from time import sleep
black = (0, 0, 0)
white = (255, 255, 255)
green = (0, 255, 0)
RED = (255, 0, 0)
darkgreen = (0,102,0)
pink = (255,0,255)
deepskyblue = (0,191,255)
dirt = (204,102,0)
carrot = (237,145,33)
grey = (224,224,224)
blue = (0, 0, 255)

pygame.init()

size = (830, 700)#x y
screen = pygame.display.set_mode(size)

myfont = pygame.font.SysFont(None, 30)
font = pygame.font.Font(None, 25)

class Car(pygame.sprite.Sprite):
    def __init__(self,colour,width,height):
        self.oilslick = 3
        self.smokescreen = 3
        self.lives = 3
        super(Car, self).__init__()
        self.image = pygame.Surface([width,height])
        self.image.fill(colour)
        self.rect = self.image.get_rect()
        
    def Move(self):#moves car on screen
        pass

    def Oil(self):#oild slick
        pass

    def smoke(self):#smoke screen
        pass

    def chances(self):#player gets 3 lives in the game
        self.lives = 3
        pass

    def position(self,x,y):
        self.rect.x = x
        self.rect.y = y

dirtroad = []
for i in range(1000):
    x = random.choice(list(range(143, 148))+
                      list(range(173, 180))+
                      list(range(621, 628))+
                      list(range(653, 663)))
    y = random.randrange(0, 800)
    dirtroad.append([x, y])

redlist = []
for j in range(400):
    x = random.choice(list(range(155, 168))+
                      list(range(635, 645)))
    y = random.randrange(0, 800)
    redlist.append([x,y])
    
def draw_dirtonsides():
    pygame.draw.line(screen, carrot, [160, 0], [160, 800], 27)#Left side
    pygame.draw.line(screen, carrot, [640, 0], [640, 800], 27)#Right side

    for dirt in dirtroad:
        # Draw the dirt flakes on service road sides
        pygame.draw.circle(screen, carrot, dirt, 1)

    for red in redlist:
        # Draw the red flakes on service road
        pygame.draw.circle(screen, RED, red, 1)    

def Grass():
    pygame.draw.line(screen, darkgreen, [0, 0], [0, 800], 310)#left side
    pygame.draw.line(screen, darkgreen, [735, 0], [735, 800], 210)#right side 165


def Trees():
    pygame.draw.circle(screen, blue, [120, 150], 12)
done = False
 
def Gamescore():
    score = 9999999
    
    scoretext = myfont.render(str(score +1), True, (white))
    #scoretext[1:]
    screen.blit(scoretext, (140, 50))
    pygame.draw.line(screen,white,[9,10],[9,30],10)
    score += 1
    sleep(1)

    
clock = pygame.time.Clock()
 
 
# -------- Main Program Loop -----------
while not done:
    for event in pygame.event.get(): 
        if event.type == pygame.QUIT: 
            done = True
 
    
    screen.fill(black)
    Grass()
    Trees()
    draw_dirtonsides()
    Gamescore()
    pygame.display.flip()
    
    clock.tick(60)
 
pygame.quit()

 

This post has been edited by albert003: 29 July 2019 - 04:20 PM

Was This Post Helpful? 0
  • +
  • -

#12 DK3250   User is offline

  • Pythonian
  • member icon

Reputation: 561
  • View blog
  • Posts: 1,791
  • Joined: 27-December 13

Re: Remaking a classic arcade game using python

Posted 30 July 2019 - 01:21 AM

The problem with score is padding the integer with zeros.
I usually convert to string and use rjust() for padding.
Sample code:
score = 0
for i in range(50):
    print(str(score).rjust(6, '0'))
    score += 1

Outputs:
000000
000001
000002
000003
000004
000005
000006
000007
000008
000009
..
..

I'm sure you can implement this in your gamescore() function...
Was This Post Helpful? 1
  • +
  • -

#13 DK3250   User is offline

  • Pythonian
  • member icon

Reputation: 561
  • View blog
  • Posts: 1,791
  • Joined: 27-December 13

Re: Remaking a classic arcade game using python

Posted 30 July 2019 - 02:28 AM

ok, I looked on your code and need to comment on your main loop.
In the main loop you do this:
Grass()
Trees()
draw_dirtonsides()

This means that again and again you draw the same graphics. Bad - very bad.

Just as the car only needs to be drawn once into a surface; the background should only be drawn once in a surface. Moreover so, as you later want to scroll this whole surface..!!

Another thing: Why do you divert from the name conventions in python? Function names are normally in lower case, this includes the starting letter.
Was This Post Helpful? 1
  • +
  • -

#14 baavgai   User is offline

  • Dreaming Coder
  • member icon


Reputation: 7501
  • View blog
  • Posts: 15,544
  • Joined: 16-October 07

Re: Remaking a classic arcade game using python

Posted 30 July 2019 - 04:57 AM

Once again, I do appreciate your enthusiasm. And, once again, I'd ask that you curb it a little and actually take the time to comprehend the advise you're given, rather than hastily skimming it for a quick fix.

So, here's your code with nothing really changed except organization.
import random
import pygame
from time import sleep

black = (0, 0, 0)
white = (255, 255, 255)
green = (0, 255, 0)
RED = (255, 0, 0)
darkgreen = (0, 102, 0)
pink = (255, 0, 255)
deepskyblue = (0, 191, 255)
dirt = (204, 102, 0)
carrot = (237, 145, 33)
grey = (224, 224, 224)
blue = (0, 0, 255)

DISPLAY_SIZE = (830, 700)


def build_dirt():
    dirtroad = []
    for i in range(1000):
        x = random.choice(list(range(143, 148))+
                        list(range(173, 180))+
                        list(range(621, 628))+
                        list(range(653, 663)))
        y = random.randrange(0, 800)
        dirtroad.append([x, y])
    redlist = []
    for j in range(400):
        x = random.choice(list(range(155, 168)) + list(range(635, 645)))
        y = random.randrange(0, 800)
        redlist.append([x, y])
    return dirtroad, redlist


def draw_dirtonsides(screen, dirtroad, redlist):
    pygame.draw.line(screen, carrot, [160, 0], [160, 800], 27)  # Left side
    pygame.draw.line(screen, carrot, [640, 0], [640, 800], 27)  # Right side
    for dirt in dirtroad:
        pygame.draw.circle(screen, carrot, dirt, 1)

    for red in redlist:
        pygame.draw.circle(screen, RED, red, 1)


def draw_grass(screen):
    pygame.draw.line(screen, darkgreen, [0, 0], [0, 800], 310)  # left side
    pygame.draw.line(screen, darkgreen, [735, 0], [735, 800], 210)  # right side 165


def draw_trees(screen):
    pygame.draw.circle(screen, blue, [120, 150], 12)


def draw_gamescore(screen, myfont, score):
    scoretext = myfont.render(str(score + 1), True, (white))
    screen.blit(scoretext, (140, 50))
    pygame.draw.line(screen, white, [9, 10], [9, 30], 10)


def main():
    # define score, or any state, outside the game loop
    done = False
    score = 9999999
    dirtroad, redlist = build_dirt()
    pygame.init()
    screen = pygame.display.set_mode(DISPLAY_SIZE)

    myfont = pygame.font.SysFont(None, 30)
    clock = pygame.time.Clock()

    # -------- Main Program Loop -----------
    while not done:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                done = True
                # don't just mark done, bail from this loop
                break  # this leaves the for loop
        # check to see if we're done, before we go any farther
        if done:
            break  # this leaves the while loop
        screen.fill(black)
        # pass variables to display elements
        draw_grass(screen)
        draw_trees(screen)
        draw_dirtonsides(screen, dirtroad, redlist)
        # note, here, we pass the score, but don't modify it inside draw
        draw_gamescore(screen, myfont, score)
        sleep(1)
        pygame.display.flip()
        clock.tick(60)
        score += 1

    pygame.quit()

main()



Notice how there are no globals, that draw functions get passed the surface they write on, as well as any other objects they need. That "global" state is exclusively kept in main. Programming as about problem solving and organization. Without organization, the solution will become too confusing for even the original author to move forward. Sincerely, you need to work on organization.

Right, now that we have something organized, lets refactor a little more. We can easily identify the background that isn't going to change and build that once.
import random
import pygame
from time import sleep

DISPLAY_SIZE = (830, 700)


class Color:
    black = (0, 0, 0)
    white = (255, 255, 255)
    green = (0, 255, 0)
    red = (255, 0, 0)
    darkgreen = (0, 102, 0)
    pink = (255, 0, 255)
    deepskyblue = (0, 191, 255)
    dirt = (204, 102, 0)
    carrot = (237, 145, 33)
    grey = (224, 224, 224)
    blue = (0, 0, 255)


def build_background(screen):
    def draw_grass():
        pygame.draw.line(screen, Color.darkgreen, [0, 0], [0, 800], 310)
        pygame.draw.line(screen, Color.darkgreen, [735, 0], [735, 800], 210)

    def draw_trees():
        pygame.draw.circle(screen, Color.blue, [120, 150], 12)

    def draw_dirtonsides():
        # note, we needn't store this data, we are drawing it once
        pygame.draw.line(screen, Color.carrot, [160, 0], [160, 800], 27)
        pygame.draw.line(screen, Color.carrot, [640, 0], [640, 800], 27)
        dirt_on_side_domain = list(range(143, 148)) + list(range(173, 180)) + list(range(621, 628)) + list(range(653, 663))
        red_speck_domain = list(range(155, 168)) + list(range(635, 645))

        for _ in range(1000):
            pt = random.choice(dirt_on_side_domain), random.randrange(0, 800)
            pygame.draw.circle(screen, Color.carrot, pt, 1)
        for _ in range(400):
            pt = random.choice(red_speck_domain), random.randrange(0, 800)
            pygame.draw.circle(screen, Color.red, pt, 1)

    screen.fill(Color.black)
    draw_grass()
    draw_trees()
    draw_dirtonsides()
    return screen


def draw_gamescore(screen, myfont, score):
    scoretext = myfont.render(str(score + 1), True, Color.white)
    screen.blit(scoretext, (140, 50))
    pygame.draw.line(screen, Color.white, [9, 10], [9, 30], 10)


def main():
    # define score, or any state, outside the game loop
    done = False
    score = 9999999

    pygame.init()
    screen = pygame.display.set_mode(DISPLAY_SIZE)
    background = build_background(pygame.Surface(DISPLAY_SIZE))
    myfont = pygame.font.SysFont(None, 30)
    clock = pygame.time.Clock()

    # -------- Main Program Loop -----------
    while not done:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                done = True
                # don't just mark done, bail from this loop
                break  # this leaves the for loop
        # check to see if we're done, before we go any farther
        if done:
            break  # this leaves the while loop
        screen.blit(background, (0, 0))
        draw_gamescore(screen, myfont, score)
        pygame.display.flip()
        sleep(1)
        clock.tick(60)
        score += 1

    pygame.quit()

main()



Now we've drawn our background and need never draw it again. More, we now have that surface as a reference, which is vitally important for any game that plans to move things around in front of a background.

Good luck.
Was This Post Helpful? 1
  • +
  • -

#15 DK3250   User is offline

  • Pythonian
  • member icon

Reputation: 561
  • View blog
  • Posts: 1,791
  • Joined: 27-December 13

Re: Remaking a classic arcade game using python

Posted 02 August 2019 - 08:02 AM

More about backgrounds:

In the latest example from baavgai the code for a single simple background already takes up about 30% of the code.
You need many more backgrounds, and most will be much more complicated than this modest vertical track.
Furthermore, the backgrounds need a little functionality such that you can detect whether the car is on track or in the dirt.
And you may want to add some 'decorations' (trees, bushes, etc.) further increasing the code volume.

So, if you really want to code the backgrounds (which is ok) I suggest you do it in a separate module. Are you familiar with how to make a module?

As mentioned before, you can also do all the backgrounds in a dedicated drawing program; then importing the finished drawing by pygame.image.load().

No matter how the backgrounds are made you need to think about how you will apply the track/dirt functionality. I suggest you read up on pygame's mask object for this part...
Was This Post Helpful? 0
  • +
  • -

  • (3 Pages)
  • +
  • 1
  • 2
  • 3