Jong

After having programmed my own Tetris clone – Jetris –, I thought of another game to clone. A really fun and fairly simple game came to my mind: Pong.
After a few hours I managed to do it and here it is.
I even implemented the computer being able to play, although it never loses… If a hitter is controlled by the computer is indicated by its color (green for players, red for the computer).
To get more information about Pong, visit this Wikipedia entry.

Controls (general)

  • Escape pauses and unpauses the game
  • ‘r’ resets the game

Controls (left player)

  • ‘w’ moves the (left) hitter up
  • ‘s’ moves the (left) hitter down
  • Left arrow key while pause changes if player is computer or user controlled

Controls (right player)

  • Up arrow key moves the (right) hitter up
  • Down arrow key moves the (right) hitter down
  • Right arrow key while pause changes if player is computer or user controlled

A Paused Game The Player Having No Chance Against The Computer Two Computers Playing Forever


# Python 2.7.7 Code
# Pygame 1.9.1 (for Python 2.7.7)
# Jonathan Frech 6th of June, 2015

# importing needed modules
import pygame, sys, time, math, os, random

""" CLASSES """
# dummy class for global variables
class dummy():
	pass

# create the seven segment numbers
class sevenFont():
	def __init__(self):
		self.color = [0, 255, 0]
		
		self.numeralwidth, self.numeralheight = 4, 7
		self.numeralsize = [self.numeralwidth, self.numeralheight]
		
		# encode all the segments
		self.segments = [
			[ [1, 0], [2, 0] ],
			[ [3, 1], [3, 2] ],
			[ [3, 4], [3, 5] ],
			[ [1, 6], [2, 6] ],
			[ [0, 4], [0, 5] ],
			[ [0, 1], [0, 2] ],
			[ [1, 3], [2, 3] ]
		]
		
		# encode all 10 numerals
		self.numerals = [
			"012345",
			"12",
			"01346",
			"01236",
			"1256",
			"02356",
			"023456",
			"012",
			"0123456",
			"012356"
		]
	
	# return a surface containing the font
	def getSurface(self, _num):
		surf = pygame.Surface([(self.numeralwidth + 1) * len(_num) - 1, self.numeralheight])
		
		for _ in range(0, len(_num)):
			for __ in self.numerals[ int(_num[_]) ]:
				p1 = [
					self.segments[int(__)][0][0] + (_ * (self.numeralwidth + 1)),
					self.segments[int(__)][0][1]
				]
				p2 = [
					self.segments[int(__)][1][0] + (_ * (self.numeralwidth+1)),
					self.segments[int(__)][1][1]
				]
				
				pygame.draw.line(surf, self.color, p1, p2)
		
		return surf

# player clas
class player():
	# init function
	def __init__(self, _playerid, _controls, _com = False):
		self.playerid = _playerid
		self.controls = _controls
		self.com = _com
		
		self.height = 9
		
		self.reset()
		self.colorCom()
	
	# resets player (position and points)
	def reset(self):
		if self.playerid == 0:
			self.pos = [1, main.GAMEHEIGHT/2 - self.height/2]
		elif self.playerid == 1:
			self.pos = [main.GAMEWIDTH - 2, main.GAMEHEIGHT/2 - self.height/2]
		
		self.points = 0
	
	# changes color based on whether or not player is controlled by computer
	def colorCom(self):
		if self.com:
			self.color = [255, 0, 0]
		else:
			self.color = [0, 255, 0]
	
	# swaps if player is controlled by computer
	def swapCom(self):
		if self.com:
			self.com = False
		else:
			self.com = True
		
		self.colorCom()
		
	# tick function
	def tick(self):
		# computer control
		if self.com:
			# ball is moving towards player
			if (self.playerid == 0 and main.BALL.velocity[0] < 0) or (self.playerid == 1 and main.BALL.velocity[0] > 0):
				# ball is in the player's half of the board
				if math.fabs(self.pos[0] - main.BALL.pos[0]) <= main.GAMEWIDTH/2 - 1: 					if self.pos[1] > main.BALL.pos[1] - self.height/2:
						self.pos[1] -= 1
					elif self.pos[1] < main.BALL.pos[1] - self.height/2:
						self.pos[1] += 1
		
		# user control
		else:
			if self.controls[0] in main.KEYSDOWN:
				self.pos[1] -= 1
			elif self.controls[1] in main.KEYSDOWN:
				self.pos[1] += 1
		
		# upper / lower limits
		if self.pos[1] < 0: 			self.pos[1] = 0 		elif self.pos[1] + self.height > main.GAMEHEIGHT:
			self.pos[1] = main.GAMEHEIGHT - self.height
	
	# render function
	def render(self, _surface):
		# draw player
		pygame.draw.line(_surface, self.color, self.pos, [self.pos[0], self.pos[1] + self.height - 1])
		
		# draw points (render font)
		n = str(self.points)
		n = ("0" * (2 - len(n))) + n
		s = main.GAMEFONT.getSurface(n)
		r = s.get_rect()
		if self.playerid == 0:
			p = [main.GAMECENTER[0] - r.right - 1, 1]
		elif self.playerid == 1:
			p = [main.GAMECENTER[0] + 2, 1]
		_surface.blit(s, p)
		
		# debug
		#_surface.set_at([self.pos[0], self.pos[1] + self.height/2], [255, 0, 0])
	
	# gain a point and check gameover
	def gainPoint(self):
		self.points += 1
		main.LASTSCORED = self.playerid
		
		if self.points >= 11:
			main.GAMEOVER = True
			main.GAMEWINNER = self.playerid

# ball class
class ball():
	# init function
	def __init__(self, _pos):
		self.startpos = _pos
		
		self.color = main.GAMECOLOR
		self.reset()
	
	# reset function (puts ball in center)
	def reset(self):
		self.pos = self.startpos[:]
		if main.LASTSCORED == 0:
			if random.randint(0, 1) == 0:
				self.velocity = [-1, 1]
			else:
				self.velocity = [-1, -1]
		elif main.LASTSCORED == 1:
			if random.randint(0, 1) == 0:
				self.velocity = [1, 1]
			else:
				self.velocity = [1, -1]
		
		self.movecooldown = 60
	
	# tick function
	def tick(self):
		# up / down
		if self.pos[1] <= 0 or self.pos[1] >= main.GAMEHEIGHT - 1:
			self.velocity[1] *= -1
		
		# player
		else:
			for _ in [main.PLAYER0, main.PLAYER1]:
				# x range
				if self.pos[0] >= _.pos[0] and self.pos[0] <= _.pos[0]:
				
					# ball to the top / bottom
					if self.pos[1] == _.pos[1] - 1 or self.pos[1] == _.pos[1] + _.height:
						self.velocity[1] *= -1
		
		# left / right (ball gets out of the field)
		if self.pos[0] <= 0 or self.pos[0] >= main.GAMEWIDTH - 1:
			if math.fabs(self.pos[0] - main.PLAYER0.pos[0]) < math.fabs(self.pos[0] - main.PLAYER1.pos[0]): 				# player0 lost 				main.PLAYER1.gainPoint() 			elif math.fabs(self.pos[0] - main.PLAYER0.pos[0]) > math.fabs(self.pos[0] - main.PLAYER1.pos[0]):
				# player1 lost
				main.PLAYER0.gainPoint()
			
			self.reset()
		
		# player
		else:
			for _ in [main.PLAYER0, main.PLAYER1]:
				# y range
				if self.pos[1] >= _.pos[1] and self.pos[1] <= _.pos[1] + _.height - 1:
					# ball to the left / right side
					if self.pos[0] == _.pos[0] - 1 or self.pos[0] == _.pos[0] + 1:
						self.velocity[0] *= -1
		
		self.movecooldown -= 1
		if self.movecooldown <= 0: 			self.pos[0] += self.velocity[0] 			self.pos[1] += self.velocity[1] 	 	# render function 	def render(self, _surface): 		_surface.set_at(self.pos, self.color) """ FUNCTIONS """ # quits the program def quit(): 	sys.exit() """ TICK; RENDER """ # tick function def tick(): 	# handle events 	for event in pygame.event.get(): 		# quit 		if event.type == pygame.QUIT: 			quit() 		 		# keyup 		if event.type == pygame.KEYUP: 			# handle 'main.KEYSDOWN' 			if event.key in main.KEYSDOWN: 				main.KEYSDOWN.remove(event.key) 		 		# keydown 		if event.type == pygame.KEYDOWN: 			# handle 'main.KEYSDOWN' 			if event.key not in main.KEYSDOWN: 				main.KEYSDOWN.append(event.key) 			 			# quit 			if event.key == pygame.K_q: 				if pygame.key.get_mods() == 2**10: 					quit() 			 			# reset game 			elif event.key == main.KEY_RESET: 				reset() 			 			# toggle pause 			elif event.key == main.KEY_PAUSE: 				if main.GAMEPAUSED: 					main.GAMEPAUSED = False 				else: 					main.GAMEPAUSED = True 			 			# toggle com 			if main.GAMEPAUSED: 				if event.key == main.KEY_COMSWAP0: 					main.PLAYER0.swapCom() 				 				elif event.key == main.KEY_COMSWAP1: 					main.PLAYER1.swapCom() 	 	# tick players and ball 	if not main.GAMEOVER and not main.GAMEPAUSED: 		main.PLAYER0.tick() 		main.PLAYER1.tick() 		main.BALL.tick() 	 	# check game being focused 	if not pygame.key.get_focused(): 		main.GAMEPAUSED = True # render function def render(): 	# fill 	main.GAMESURF.fill(main.GAMEBACKCOLOR) 	 	# draw dotted line in center 	for _ in range(1, main.GAMEWIDTH, 2): 		if _ != main.GAMECENTER[1]: 			main.GAMESURF.set_at([main.GAMECENTER[0], _], main.GAMECOLOR2) 		pygame.draw.rect(main.GAMESURF, main.GAMECOLOR2, [main.GAMECENTER[0] - 2, main.GAMECENTER[1] - 2, 5, 5], 1) 	 	# draw players and ball 	main.PLAYER0.render(main.GAMESURF) 	main.PLAYER1.render(main.GAMESURF) 	main.BALL.render(main.GAMESURF) 	 	# draw arrow which indicates the winner 	if main.GAMEWINNER != None: 		if main.GAMEWINNER == 0: 			p = [main.GAMECENTER[0]-10, main.GAMECENTER[1]] 			pygame.draw.line(main.GAMESURF, main.GAMECOLOR, p, [main.GAMECENTER[0]-4, main.GAMECENTER[1]]) 			 			pygame.draw.line(main.GAMESURF, main.GAMECOLOR, p, [main.GAMECENTER[0]-2-5, main.GAMECENTER[1]-3]) 			pygame.draw.line(main.GAMESURF, main.GAMECOLOR, p, [main.GAMECENTER[0]-2-5, main.GAMECENTER[1]+3]) 		 		elif main.GAMEWINNER == 1: 			p = [main.GAMECENTER[0]+10, main.GAMECENTER[1]] 			pygame.draw.line(main.GAMESURF, main.GAMECOLOR, p, [main.GAMECENTER[0]+4, main.GAMECENTER[1]]) 			 			pygame.draw.line(main.GAMESURF, main.GAMECOLOR, p, [main.GAMECENTER[0]+2+5, main.GAMECENTER[1]-3]) 			pygame.draw.line(main.GAMESURF, main.GAMECOLOR, p, [main.GAMECENTER[0]+2+5, main.GAMECENTER[1]+3]) 	 	# draw pause indication 	if main.GAMEPAUSED: 		for _ in range(0, main.GAMEWIDTH * 2, 10): 			pygame.draw.line(main.GAMESURF, main.GAMECOLOR2, [_, 0], [0, _]) 	 	# blit and flip 	main.SCREEN.blit(pygame.transform.scale(main.GAMESURF, main.SIZE), [0, 0]) 	pygame.display.flip() """ RESET; INIT """ # resets game def reset(): 	main.PLAYER0.reset() 	main.PLAYER1.reset() 	main.LASTSCORED = random.randint(0, 1) 	 	main.BALL = ball(main.GAMECENTER[:]) 	 	main.GAMEOVER = False 	main.GAMEWINNER = None # initialize program def init(): 	main.GAMEWIDTH, main.GAMEHEIGHT = 100, 50+1 	main.GAMESIZE = [main.GAMEWIDTH, main.GAMEHEIGHT] 	main.GAMECENTER = [main.GAMEWIDTH/2, main.GAMEHEIGHT/2] 	main.GAMESURF = pygame.Surface(main.GAMESIZE) 	main.GAMESCALE = 10 	 	main.GAMEBACKCOLOR = [0, 0, 0] 	main.GAMECOLOR = [0, 255, 0] 	main.GAMECOLOR2 = [255, 255, 255] 	 	main.KEY_PLAYER0UP   = pygame.K_w 	main.KEY_PLAYER0DOWN = pygame.K_s 	main.KEY_PLAYER1UP   = pygame.K_UP 	main.KEY_PLAYER1DOWN = pygame.K_DOWN 	 	main.KEY_COMSWAP0    = pygame.K_LEFT 	main.KEY_COMSWAP1    = pygame.K_RIGHT 	 	main.KEY_PAUSE       = pygame.K_ESCAPE 	main.KEY_RESET       = pygame.K_r 	 	main.GAMEPAUSED = True 	main.PLAYER0 = player(0, [main.KEY_PLAYER0UP, main.KEY_PLAYER0DOWN]) 	main.PLAYER1 = player(1, [main.KEY_PLAYER1UP, main.KEY_PLAYER1DOWN]) 	reset() 	 	main.WIDTH, main.HEIGHT = main.GAMEWIDTH * main.GAMESCALE, main.GAMEHEIGHT * main.GAMESCALE 	main.SIZE = [main.WIDTH, main.HEIGHT] 	main.SCREEN = pygame.display.set_mode(main.SIZE) 	 	main.CAPTION = "Jong" 		 	main.TICKS = 0 	main.KEYSDOWN = [] 	 	# functions 	main.GAMEFONT = sevenFont() 	pygame.display.set_caption(main.CAPTION) """ RUN """ # run function (uses tick() and render()) def run(): 	ticksPerSecond = 60 	lastTime = time.time() * 1000000000 	nsPerTick =  1000000000.0 / float(ticksPerSecond) 	 	ticks = 0 	frames = 0 	 	lastTimer = time.time() * 1000 	delta = 0.0 	 	while True: 		now = time.time() * 1000000000 		delta += float(now - lastTime) / float(nsPerTick) 		lastTime = now 		shouldRender = False 				 		while delta >= 1:
			ticks += 1
			main.TICKS += 1
			tick()
			delta -= 1
			shouldRender = True
		
		if shouldRender:
			frames += 1
			render()
		
		if time.time() * 1000 - lastTimer >= 1000:
			lastTimer += 1000
			
			# debug
			# print("Frames: " + str(frames) + ", ticks: " + str(ticks))
			
			frames = 0
			ticks = 0

# main variable
main = dummy()
init()

# start program
run()
Advertisements

2 thoughts on “Jong

  1. Pingback: JClock III | J-Blog

  2. Pingback: Jeakout | J-Blog

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 )

Twitter picture

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

Facebook photo

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

Google+ photo

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

Connecting to %s