It was actually finished month ago but I lost the endurance to sit and split the game in several files. So I did it today and now its here for review.
I am not new to programming, but I am new to Python and game development. So I would like to hear whats ok and whats not ok and how to do it right.
The game was written in my language and I translated variables, methods and class names to English an hour ago so you might notice some weird expressions.
I started to pass object properties that I needed in class methods but switched to passing whole object, so you will see the difference. I am not sure is proper way to do it and is it efficient, but..
The game intentionally does not use sprites and images as I wanted to see is it possible to make this simple game without using images.
Thanks
PS For some reason I am not allowed to upload files so here is the code.
File: MyPong.py
# -*- coding: utf-8 -*-
import pygame
from pygame.locals import *
from Pad import Pad
from Ball import Ball
from Text import Text
from Game import Game
#Creating instances
game = Game()
my_pad = Pad(0, 0, 100, 20, [255, 0, 255])
my_pad.rect.topleft = (100,430)
ai_pad = Pad(0, 0, 100, 20, [255, 100, 100])
ai_pad.rect.topleft=(0, 30)
ball = Ball(10,[0, 100, 50])
text_pause = Text("PAUSE", (255,255,255), None, game.background.get_rect().center, 100)
my_result = Text("Player: %s" % my_pad.points, (150,255,0), (0, 0), (50,50), 30)
ai_result = Text("AI: %s" % ai_pad.points, (150,255,0), (game.width-50, 0), (50,50), 30)
while game.all_ok:
game.update(my_pad, ai_pad, ball)
if game.pause:
if game.game_over:
text_pause = Text("GAME OVER - The winner is: %s" % game.winner, (255,255,255), None, game.background.get_rect().center, 50)
game.screen.blit(text_pause.text, text_pause.poz)
else:
my_pad.calculate_position(game.width)
ai_pad.calculate_ai(ball.rect.center, game.width)
ball.calculate_position(game, my_pad, ai_pad, my_result, ai_result)
my_pad.rect.left+=my_pad.movement
game.background.fill(game.background_color)
game.screen.blit(game.background, game.background_rect)
game.screen.blit(my_result.text, my_result.poz)
game.screen.blit(ai_result.text, ai_result.poz)
game.screen.blit(my_pad.picture, my_pad.rect)
game.screen.blit(ai_pad.picture, ai_pad.rect)
game.screen.blit(ball.picture, ball.rect)
game.clock.tick(game.refresh_rate)
pygame.display.flip()
File: Pad.py# -*- coding: utf-8 -*-
import pygame
from pygame.locals import *
class Pad(object):
def __init__(self, x, y, width, height, color):
self.x = x
self.y = y
self.width = width
self.height = height
self.ball_speed = 3
self.pad_direction = 0
self.movement = 0
self.points = 0
self.color = color
self.picture, self.rect = self.draw_rectangle()
def draw_rectangle(self):
rectangle = pygame.Rect(self.x, self.y, self.width, self.height)
picture = pygame.Surface(( self.width, self.height))
pygame.draw.rect(picture, self.color , rectangle)
return picture , picture.get_rect()
def calculate_position(self, width):
#Calculate pad position if its in the screen
if self.rect.left>=0 and self.rect.left+self.rect.width<=width:
self.movement = self.ball_speed * self.pad_direction
#If ball is out of the left border
elif self.rect.left < 0:
self.rect.left = 0
self.movement = 0
self.pad_direction = 0
#If ball is out of the right border
elif self.rect.left+self.rect.width>width:
self.rect.left = width - self.rect.width
self.movement = 0
self.pad_direction = 0
def calculate_ai(self, ball_position, width):
diff = abs(ball_position[0]-self.rect.center[0])
if self.rect.center[0] > ball_position[0]:
if self.rect.left < 0:
self.rect.left = 0
else:
self.rect.centerx -=3
else:
if self.rect.right > width:
self.rect.right = width
self.rect.centerx +=3
File: Ball.py
# -*- coding: utf-8 -*-
import pygame
from pygame.locals import *
from random import randint
class Ball(object):
def __init__(self, radius, color):
self.directionX = -1
self.directionY = -1
self.positionX=randint(100,540)
self.positionY=randint(100,380)
self.radius = radius
self.color = color
self.ball_speed = 4
self.picture, self.rect = self.draw_circle(self.radius, self.color)
self.picture.set_colorkey((0,0,0))
#Initial positioning is random
self.rect.center = self.positionX, self.positionY
def draw_circle(self, radius, color):
size = radius*2
picture = pygame.Surface((size, size))
pygame.draw.circle(picture, color, (radius, radius), radius)
return picture, picture.get_rect()
def calculate_position(self, game, my_pad, ai_pad, my_result, ai_result):
if not game.goal:
if self.rect.top <= 0:
my_pad.points +=1
my_result.text = my_result.font.render("Player: %s" % my_pad.points, 1, (150,255,0))
game.goal = 1
elif self.rect.bottom > game.height:
game.goal = 1
ai_pad.points +=1
ai_result.text = ai_result.font.render("AI: %s" % ai_pad.points, 1, (150,255,0))
if ai_pad.points == 11 or my_pad.points == 11:
if ai_pad.points == 11:
game.winner = "AI"
else:
game.winner = "Player"
game.game_over = 1
game.pause = 1
#If the ball is out of the right border, corection and changing the direction X
if self.positionX > game.width-self.radius:
self.positionX = self.positionX - self.ball_speed
self.directionX = -1
#If the ball is out of the left border, corection and direction change
if self.positionX < 0+self.radius:
self.positionX = self.positionX + self.ball_speed
self.directionX = 1
elif self.rect.bottom < 0 or self.rect.top > game.height:
game.goal = 0
self.positionX = randint(100,540)
self.positionY = randint(100,380)
if randint(0,1):
self.directionY = 1
else:
self.directionY = -1
#updating new position
self.positionX += self.ball_speed * self.directionX
self.positionY += self.ball_speed * self.directionY
self.rect.center = self.positionX, self.positionY
File: Text.py
# -*- coding: utf-8 -*-
import pygame
from pygame.locals import *
class Text(object):
def __init__(self, text, color, position, center, size):
self.font = pygame.font.Font(None,size)
self.text = text
self.color = color
self.text = self.font.render(self.text, 1, self.color)
self.poz = self.text.get_rect()
self.poz.center = center
if position <> None:
self.poz.topleft = position
self.picture = pygame.Surface((self.poz.width, self.poz.height))
File: Game.py
# -*- coding: utf-8 -*-
import pygame
from pygame.locals import *
class Game(object):
def __init__(self):
pygame.init()
self.width, self.height = 640, 480
self.screen_resolution = (self.width, self.height)
if pygame.display.mode_ok(self.screen_resolution):
self.screen = pygame.display.set_mode(self.screen_resolution)
self.refresh_rate = 40
self.clock = pygame.time.Clock()
self.pause = 0
self.goal = 0
self.all_ok = 1
self.background_color = [0, 0, 0]
self.background = pygame.Surface((self.width, self.height))
self.background_rect = self.background.get_rect()
self.game_over = 0
self.winner = ""
def update(self, my_pad, ai_pad, ball):
keys = pygame.key.get_pressed()
if keys[K_LEFT] or keys[K_RIGHT]:
if keys[K_LEFT]:
my_pad.pad_direction = -1
elif keys[K_RIGHT]:
my_pad.pad_direction = 1
else:
my_pad.pad_direction = 0
events = pygame.event.get()
for event in events:
if event.type == QUIT or (event.type == KEYDOWN and event.key in [K_ESCAPE, K_q]):
#quiting
self.all_ok = 0
elif event.type ==KEYDOWN and event.key == K_SPACE:
if self.pause == 0:
self.pause =1
else:
self.pause = 0
if not self.pause:
mylist = (my_pad.rect, ai_pad.rect)
colision = ball.rect.collidelist(mylist)
if colision == 0: # Ball hit the pad
#from above
if ball.rect.top < my_pad.rect.top and ball.rect.bottom > my_pad.rect.top:
ball.directionY = ball.directionY * -1
ball.positionY = ball.positionY - ball.ball_speed
#from side
elif ball.rect.top < my_pad.rect.bottom:
ball.directionX = ball.directionX * -1
ball.positionX = ball.positionX - ball.ball_speed
elif colision == 1:
if ball.rect.top <= ai_pad.rect.bottom:
ball.directionY = ball.directionY * -1
ball.positionY = ball.positionY + ball.ball_speed