juegos-python/8_Ball_Pool/8BallPool.py

377 lines
12 KiB
Python
Raw Permalink Normal View History

2023-04-10 00:48:44 +02:00
# -----------------------------------------------------------------------------
#
# 8 Ball Pool
# Language - Python
# Modules - pygame, sys, random, math
#
# Controls - Mouse, the length of Stick is propotional to Force applied
#
# By - Jatin Kumar Mandav
#
# Website - https://jatinmandav.wordpress.com
#
# YouTube Channel - https://www.youtube.com/channel/UCdpf6Lz3V357cIZomPwjuFQ
# Twitter - @jatinmandav
#
# -----------------------------------------------------------------------------
import pygame
import sys
from math import *
import random
pygame.init()
width = 660
height = 360
outerHeight = 400
margin = 30
display = pygame.display.set_mode((width, outerHeight))
pygame.display.set_caption("8 Ball Pool")
clock = pygame.time.Clock()
background = (51, 51, 51)
white = (236, 240, 241)
gray = (123, 125, 125)
black = (23, 32, 42)
yellow = (244, 208, 63)
blue = (52, 152, 219)
red = (203, 67, 53)
purple = (136, 78, 160)
orange = (230, 126, 34)
green = (40, 180, 99)
brown = (100, 30, 22)
stickColor = (249, 231, 159)
colors = [yellow, blue, red, purple, orange, green, brown, black, yellow, blue, red, purple, orange, green, brown]
balls = []
noBalls = 15
radius = 10
friction = 0.005
# Ball Class
class Ball:
def __init__(self, x, y, speed, color, angle, ballNum):
self.x = x + radius
self.y = y + radius
self.color = color
self.angle = angle
self.speed = speed
self.ballNum = ballNum
self.font = pygame.font.SysFont("Agency FB", 10)
# Draws Balls on Display Window
def draw(self, x, y):
pygame.draw.ellipse(display, self.color, (x - radius, y - radius, radius*2, radius*2))
if self.color == black or self.ballNum == "cue":
ballNo = self.font.render(str(self.ballNum), True, white)
display.blit(ballNo, (x - 5, y - 5))
else:
ballNo = self.font.render(str(self.ballNum), True, black)
if self.ballNum > 9:
display.blit(ballNo, (x - 6, y - 5))
else:
display.blit(ballNo, (x - 5, y - 5))
# Moves the Ball around the Screen
def move(self):
self.speed -= friction
if self.speed <= 0:
self.speed = 0
self.x = self.x + self.speed*cos(radians(self.angle))
self.y = self.y + self.speed*sin(radians(self.angle))
if not (self.x < width - radius - margin):
self.x = width - radius - margin
self.angle = 180 - self.angle
if not(radius + margin < self.x):
self.x = radius + margin
self.angle = 180 - self.angle
if not (self.y < height - radius - margin):
self.y = height - radius - margin
self.angle = 360 - self.angle
if not(radius + margin < self.y):
self.y = radius + margin
self.angle = 360 - self.angle
# Pocket Class
class Pockets:
def __init__(self, x, y, color):
self.r = margin/2
self.x = x + self.r + 10
self.y = y + self.r + 10
self.color = color
# Draws the Pockets on Pygame Window
def draw(self):
pygame.draw.ellipse(display, self.color, (self.x - self.r, self.y - self.r, self.r*2, self.r*2))
# Checks if ball has entered the Hole
def checkPut(self):
global balls
ballsCopy = balls[:]
for i in range(len(balls)):
dist = ((self.x - balls[i].x)**2 + (self.y - balls[i].y)**2)**0.5
if dist < self.r + radius:
if balls[i] in ballsCopy:
if balls[i].ballNum == 8:
gameOver()
else:
ballsCopy.remove(balls[i])
balls = ballsCopy[:]
# Cue Stick Class
class CueStick:
def __init__(self, x, y, length, color):
self.x = x
self.y = y
self.length = length
self.color = color
self.tangent = 0
# Applies force to Cue Ball
def applyForce(self, cueBall, force):
cueBall.angle = self.tangent
cueBall.speed = force
# Draws Cue Stick on Pygame Window
def draw(self, cuex, cuey):
self.x, self.y = pygame.mouse.get_pos()
self.tangent = (degrees(atan2((cuey - self.y), (cuex - self.x))))
pygame.draw.line(display, white, (cuex + self.length*cos(radians(self.tangent)), cuey + self.length*sin(radians(self.tangent))), (cuex, cuey), 1)
pygame.draw.line(display, self.color, (self.x, self.y), (cuex, cuey), 3)
# Checks Collision
def collision(ball1, ball2):
dist = ((ball1.x - ball2.x)**2 + (ball1.y - ball2.y)**2)**0.5
if dist <= radius*2:
return True
else:
return False
# Checks if Cue Ball hits any Ball
def checkCueCollision(cueBall):
for i in range(len(balls)):
if collision(cueBall, balls[i]):
if balls[i].x == cueBall.x:
angleIncline = 2*90
else:
u1 = balls[i].speed
u2 = cueBall.speed
balls[i].speed = ((u1*cos(radians(balls[i].angle)))**2 + (u2*sin(radians(cueBall.angle)))**2)**0.5
cueBall.speed = ((u2*cos(radians(cueBall.angle)))**2 + (u1*sin(radians(balls[i].angle)))**2)**0.5
tangent = degrees((atan((balls[i].y - cueBall.y)/(balls[i].x - cueBall.x)))) + 90
angle = tangent + 90
balls[i].angle = (2*tangent - balls[i].angle)
cueBall.angle = (2*tangent - cueBall.angle)
balls[i].x += (balls[i].speed)*sin(radians(angle))
balls[i].y -= (balls[i].speed)*cos(radians(angle))
cueBall.x -= (cueBall.speed)*sin(radians(angle))
cueBall.y += (cueBall.speed)*cos(radians(angle))
# Checks Collision Between Balls
def checkCollision():
for i in range(len(balls)):
for j in range(len(balls) - 1, i, -1):
if collision(balls[i], balls[j]):
if balls[i].x == balls[j].x:
angleIncline = 2*90
else:
u1 = balls[i].speed
u2 = balls[j].speed
balls[i].speed = ((u1*cos(radians(balls[i].angle)))**2 + (u2*sin(radians(balls[j].angle)))**2)**0.5
balls[j].speed = ((u2*cos(radians(balls[j].angle)))**2 + (u1*sin(radians(balls[i].angle)))**2)**0.5
tangent = degrees((atan((balls[i].y - balls[j].y)/(balls[i].x - balls[j].x)))) + 90
angle = tangent + 90
balls[i].angle = (2*tangent - balls[i].angle)
balls[j].angle = (2*tangent - balls[j].angle)
balls[i].x += (balls[i].speed)*sin(radians(angle))
balls[i].y -= (balls[i].speed)*cos(radians(angle))
balls[j].x -= (balls[j].speed)*sin(radians(angle))
balls[j].y += (balls[j].speed)*cos(radians(angle))
def border():
pygame.draw.rect(display, gray, (0, 0, width, 30))
pygame.draw.rect(display, gray, (0, 0, 30, height))
pygame.draw.rect(display, gray, (width - 30, 0, width, height))
pygame.draw.rect(display, gray, (0, height - 30, width, height))
def score():
font = pygame.font.SysFont("Agency FB", 30)
pygame.draw.rect(display, (51, 51, 51), (0, height, width, outerHeight))
for i in range(len(balls)):
balls[i].draw((i + 1)*2*(radius + 1), height + radius + 10)
text = font.render("Remaining Balls: " + str(len(balls)), True, stickColor)
display.blit(text, (width/2 + 50, height + radius/2))
def reset():
global balls, noBalls
noBalls = 15
balls = []
s = 70
b1 = Ball(s, height/2 - 4*radius, 0, colors[0], 0, 1)
b2 = Ball(s + 2*radius, height/2 - 3*radius, 0, colors[1], 0, 2)
b3 = Ball(s, height/2 - 2*radius, 0, colors[2], 0, 3)
b4 = Ball(s + 4*radius, height/2 - 2*radius, 0, colors[3], 0, 4)
b5 = Ball(s + 2*radius, height/2 - 1*radius, 0, colors[4], 0, 5)
b6 = Ball(s, height/2, 0, colors[5], 0, 6)
b7 = Ball(s + 6*radius, height/2 - 1*radius, 0, colors[6], 0, 7)
b8 = Ball(s + 4*radius, height/2, 0, colors[7], 0, 8)
b9 = Ball(s + 8*radius, height/2, 0, colors[8], 0, 9)
b10 = Ball(s + 6*radius, height/2 + 1*radius, 0, colors[9], 0, 10)
b11 = Ball(s + 2*radius, height/2 + 1*radius, 0, colors[10], 0, 11)
b12 = Ball(s, height/2 + 2*radius, 0, colors[11], 0, 12)
b13 = Ball(s + 4*radius, height/2 + 2*radius, 0, colors[12], 0, 13)
b14 = Ball(s + 2*radius, height/2 + 3*radius, 0, colors[13], 0, 14)
b15 = Ball(s, height/2 + 4*radius, 0, colors[14], 0, 15)
balls.append(b1)
balls.append(b2)
balls.append(b3)
balls.append(b4)
balls.append(b5)
balls.append(b6)
balls.append(b7)
balls.append(b8)
balls.append(b9)
balls.append(b10)
balls.append(b11)
balls.append(b12)
balls.append(b13)
balls.append(b14)
balls.append(b15)
def gameOver():
font = pygame.font.SysFont("Agency FB", 75)
if len(balls) == 0:
text = font.render("You Won!", True, (133, 193, 233))
else:
text = font.render("You Lost! Black in Hole!", True, (241, 148, 138))
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
close()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_q:
close()
if event.key == pygame.K_r:
poolTable()
display.blit(text, (50, height/2))
pygame.display.update()
clock.tick()
def close():
pygame.quit()
sys.exit()
# Main Function
def poolTable():
loop = True
reset()
noPockets = 6
pockets = []
p1 = Pockets(0, 0, black)
p2 = Pockets(width/2 - p1.r*2, 0, black)
p3 = Pockets(width - p1.r - margin - 5, 0, black)
p4 = Pockets(0, height - margin - 5 - p1.r, black)
p5 = Pockets(width/2 - p1.r*2, height - margin - 5 - p1.r, black)
p6 = Pockets(width - p1.r - margin - 5, height - margin - 5 - p1.r, black)
pockets.append(p1)
pockets.append(p2)
pockets.append(p3)
pockets.append(p4)
pockets.append(p5)
pockets.append(p6)
cueBall = Ball(width/2, height/2, 0, white, 0, "cue")
cueStick = CueStick(0, 0, 100, stickColor)
start = 0
end = 0
while loop:
for event in pygame.event.get():
if event.type == pygame.QUIT:
close()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_q:
close()
if event.key == pygame.K_r:
poolTable()
if event.type == pygame.MOUSEBUTTONDOWN:
start = [cueBall.x, cueBall.y]
x, y = pygame.mouse.get_pos()
end = [x ,y]
dist = ((start[0] - end[0])**2 + (start[1] - end[1])**2)**0.5
force = dist/10.0
if force > 10:
force = 10
cueStick.applyForce(cueBall, force)
display.fill(background)
cueBall.draw(cueBall.x, cueBall.y)
cueBall.move()
if not (cueBall.speed > 0):
cueStick.draw(cueBall.x, cueBall.y)
for i in range(len(balls)):
balls[i].draw(balls[i].x, balls[i].y)
for i in range(len(balls)):
balls[i].move()
checkCollision()
checkCueCollision(cueBall)
border()
for i in range(noPockets):
pockets[i].draw()
for i in range(noPockets):
pockets[i].checkPut()
if len(balls) == 1 and balls[0].ballNum == 8:
gameOver()
score()
pygame.display.update()
clock.tick(60)
poolTable()