第一次提交

master
could_dream111 3 years ago
parent 530500b2c0
commit 4f9d832a39

8
.idea/.gitignore vendored

@ -0,0 +1,8 @@
# 默认忽略的文件
/shelf/
/workspace.xml
# 基于编辑器的 HTTP 客户端请求
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="PYTHON_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/venv" />
</content>
<orderEntry type="jdk" jdkName="Python 3.9 (Ant)" jdkType="Python SDK" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

@ -0,0 +1,12 @@
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="PyPep8Inspection" enabled="true" level="WEAK WARNING" enabled_by_default="true">
<option name="ignoredErrors">
<list>
<option value="E302" />
</list>
</option>
</inspection_tool>
</profile>
</component>

@ -0,0 +1,6 @@
<component name="InspectionProjectProfileManager">
<settings>
<option name="USE_PROJECT_PROFILE" value="false" />
<version value="1.0" />
</settings>
</component>

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.9 (Ant)" project-jdk-type="Python SDK" />
</project>

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/billiards.iml" filepath="$PROJECT_DIR$/.idea/billiards.iml" />
</modules>
</component>
</project>

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
</component>
</project>

@ -0,0 +1,20 @@
import abc
import pygame
from config.sys import *
class DrawableItem(metaclass=abc.ABCMeta):
@abc.abstractmethod
def draw(self, window: pygame.Surface):
pass
@staticmethod
def _get_relative_pos(pos: tuple[float, float]) -> tuple[float, float]:
return (SCREEN_WIDTH - TABLE_WIDTH) / 2 + pos[0], (SCREEN_HEIGHT - TABLE_HEIGHT) / 2 + pos[1]
@staticmethod
def _get_table_pos(pos: tuple[float, float]) -> tuple[float, float]:
return pos[0] - (SCREEN_WIDTH - TABLE_WIDTH) / 2, pos[1] - (SCREEN_HEIGHT - TABLE_HEIGHT) / 2

@ -0,0 +1,63 @@
import pygame.draw
from common.drawableItem import DrawableItem
from enums.Color import BLACK
from enums.category import Category
from config.sys import *
import pymunk
class BaseBilliard(DrawableItem):
def __init__(self, score: int, category: Category, color: tuple[int, int, int], pos=(0, 0)):
self.__score = score
self.__category = category
self.__color = color
self.__rigid_body = pymunk.Body(BALL_MASS, 1)
self.__rigid_body.position = pos
self.__shape = pymunk.Circle(self.__rigid_body, BALL_RADIUS)
self.__shape.elasticity = 1.0
@property
def score(self):
return self.__score
@property
def category(self):
return self.__category
@property
def color(self):
return self.__color
@property
def rigid_body(self):
return self.__rigid_body
@property
def shape(self):
return self.__shape
@property
def pos(self):
return self.__rigid_body.position
@pos.setter
def pos(self, pos: tuple[float, float]):
self.__rigid_body.position = pos
def draw(self, window):
pygame.draw.circle(window, self.__color, self._get_relative_pos(self.pos), BALL_RADIUS)
pygame.draw.circle(window, BLACK, self._get_relative_pos(self.pos), BALL_RADIUS, 1)
pass
def resistance(self):
length = self.__rigid_body.velocity.length
if length == 0:
return
if length < TABLE_FRICTION_FACTOR / FPS:
self.__rigid_body.velocity = pymunk.Vec2d.zero()
return
v = self.__rigid_body.velocity.scale_to_length(length - TABLE_FRICTION_FACTOR / FPS)
if v.length <= 1:
v = (0, 0)
self.__rigid_body.velocity = v

@ -0,0 +1,43 @@
import pygame
import pymunk
from common.drawableItem import DrawableItem
from common.game.billiards.baseBilliard import BaseBilliard
from config.sys import CUE_LENGTH, CUE_WIDTH, BALL_RADIUS
from enums.Color import BLACK, WHITE
class Cue(DrawableItem):
def __init__(self, cue_ball: BaseBilliard):
self.__cue_ball = cue_ball
self.__mouse_pos: tuple[float, float] = (0, 0)
pass
def draw(self, window: pygame.Surface):
if not self.__cue_ball:
return
if self.__cue_ball.rigid_body.velocity != pymunk.Vec2d.zero():
print(self.__cue_ball.rigid_body.velocity)
return
cue_ball_pos = self.__cue_ball.pos
mouse_pos = pymunk.Vec2d(self.__mouse_pos[0], self.__mouse_pos[1])
cue_vector_x = (self._get_relative_pos(cue_ball_pos) - mouse_pos)[0]
cue_vector_y = (self._get_relative_pos(cue_ball_pos) - mouse_pos)[1]
cue_vector = pymunk.Vec2d(cue_vector_x, cue_vector_y).scale_to_length(CUE_LENGTH)
pygame.draw.line(window, WHITE, self._get_relative_pos(cue_ball_pos),
mouse_pos - (mouse_pos - self._get_relative_pos(cue_ball_pos)).scale_to_length(BALL_RADIUS), 1)
pygame.draw.circle(window, WHITE, mouse_pos, BALL_RADIUS, 1)
pygame.draw.line(window, BLACK, self._get_relative_pos(cue_ball_pos),
self._get_relative_pos(cue_ball_pos) + cue_vector, CUE_WIDTH)
pass
@property
def mouse_pos(self):
return self.__mouse_pos
@mouse_pos.setter
def mouse_pos(self, mouse_pos):
self.__mouse_pos = mouse_pos

@ -0,0 +1,27 @@
import pygame
import pymunk
from common.drawableItem import DrawableItem
from common.game.billiards.baseBilliard import BaseBilliard
from config.sys import HOLE_RADIUS, BALL_RADIUS
from enums.Color import GARY
class Hole(DrawableItem):
def __init__(self, pos):
self.__pos = pos
pass
def draw(self, window: pygame.Surface):
pygame.draw.circle(window, GARY, self._get_relative_pos(self.__pos), HOLE_RADIUS)
def goal(self, space: pymunk.Space, balls: list[BaseBilliard]):
for _ in balls:
pos = pygame.Vector2(_.rigid_body.position.x - self.__pos[0], _.rigid_body.position.y - self.__pos[1])
if pos.length() <= HOLE_RADIUS:
_.rigid_body.position = pymunk.Vec2d(-BALL_RADIUS, -BALL_RADIUS)
space.remove(_.rigid_body)
balls.remove(_)
pass

@ -0,0 +1,62 @@
import pygame.draw
import pymunk
from common.drawableItem import DrawableItem
from common.game.hole import Hole
from config.sys import *
from enums.Color import BLACK, GREEN
class Table(DrawableItem):
def __init__(self):
self.__size = TABLE_SIZE
self.__cushing_body = [
pymunk.Body(body_type=pymunk.Body.STATIC),
pymunk.Body(body_type=pymunk.Body.STATIC),
pymunk.Body(body_type=pymunk.Body.STATIC),
pymunk.Body(body_type=pymunk.Body.STATIC),
pymunk.Body(body_type=pymunk.Body.STATIC),
pymunk.Body(body_type=pymunk.Body.STATIC)
]
self.__cushing_shape: list[pymunk.Segment] = [
pymunk.Segment(self.__cushing_body[0], (0, HOLE_RADIUS), (0, TABLE_HEIGHT - HOLE_RADIUS), 1),
pymunk.Segment(self.__cushing_body[1], (HOLE_RADIUS, TABLE_HEIGHT),
(TABLE_WIDTH / 2 - HOLE_RADIUS, TABLE_HEIGHT), 1),
pymunk.Segment(self.__cushing_body[2], (TABLE_WIDTH / 2 + HOLE_RADIUS, TABLE_HEIGHT),
(TABLE_WIDTH - HOLE_RADIUS, TABLE_HEIGHT), 1),
pymunk.Segment(self.__cushing_body[3], (TABLE_WIDTH, TABLE_HEIGHT - HOLE_RADIUS),
(TABLE_WIDTH, HOLE_RADIUS), 1),
pymunk.Segment(self.__cushing_body[4], (HOLE_RADIUS, 0),
(TABLE_WIDTH / 2 - HOLE_RADIUS, 0), 1),
pymunk.Segment(self.__cushing_body[5], (TABLE_WIDTH / 2 + HOLE_RADIUS, 0),
(TABLE_WIDTH - HOLE_RADIUS, 0), 1),
]
self.__holes = [
Hole((0, 0)), Hole((TABLE_WIDTH / 2, 0)), Hole((TABLE_WIDTH, 0)),
Hole((0, TABLE_HEIGHT)), Hole((TABLE_WIDTH / 2, TABLE_HEIGHT)), Hole((TABLE_WIDTH, TABLE_HEIGHT))
]
for _ in self.__cushing_shape:
_.elasticity = 1.0
pass
def draw(self, window):
pos1 = self._get_relative_pos((0, 0))
pos2 = (TABLE_WIDTH, TABLE_HEIGHT)
pygame.draw.rect(window, GREEN, (pos1, pos2))
for _ in self.__cushing_shape:
pygame.draw.line(window, BLACK, self._get_relative_pos(_.a), self._get_relative_pos(_.b), TABLE_LINE_WIDTH)
for _ in self.__holes:
_.draw(window)
pass
@property
def cushing_body(self):
return self.__cushing_body
@property
def cushing_shape(self):
return self.__cushing_shape
def goal(self, space, balls):
for _ in self.__holes:
_.goal(space, balls)

@ -0,0 +1,14 @@
BALL_RADIUS = 10.5
BALL_MASS = 5
TABLE_SIZE = (TABLE_WIDTH, TABLE_HEIGHT) = (892.25, 444.5)
HOLE_RADIUS = BALL_RADIUS * 1.8
TABLE_LINE_WIDTH = 3
TABLE_FRICTION_FACTOR = 60
CUE_WIDTH = 8
CUE_LENGTH = 128
SCREEN_SIZE = (SCREEN_WIDTH, SCREEN_HEIGHT) = (1200, 700)
TITLE = 'Python Billiard'
FPS = 60

@ -0,0 +1,4 @@
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
GREEN = (0, 128, 0)
GARY = (128, 128, 128)

@ -0,0 +1,15 @@
from enum import Enum
class Category(Enum):
CUE_BALL = 0
RED_BALL = 1
YELLOW_BALL = 2
GREEN_BALL = 3
BROWN_BALL = 4
BLUE_BALL = 5
PINK_BALL = 6
BLACK_BALL = 7
COLORED_BALLS = [_ for _ in range(2, 8)]
pass

@ -0,0 +1,76 @@
import pygame
import pymunk
from common import drawableItem
from common.game.billiards.baseBilliard import BaseBilliard
from common.game.cue import Cue
from common.game.table import Table
from config.sys import *
from enums.Color import *
from enums.category import *
def new_ball(space, pos):
ball = BaseBilliard(0, Category.BLACK_BALL, BLACK, pos)
body = ball.rigid_body
shape = ball.shape
space.add(body, shape)
balls.append(ball)
return shape
table = Table()
balls: list[BaseBilliard] = [BaseBilliard(0, Category.CUE_BALL, WHITE, (200, 150))]
cue = Cue(balls[0])
pygame.init()
window = pygame.display.set_mode(SCREEN_SIZE)
pygame.display.set_caption(TITLE)
clock = pygame.time.Clock()
space = pymunk.Space()
space.gravity = (0, 0)
for _ in range(6):
space.add(table.cushing_body[_], table.cushing_shape[_])
space.add(balls[0].rigid_body, balls[0].shape)
force = 5
add_force = False
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
exit()
if event.type == pygame.MOUSEMOTION:
cue.mouse_pos = event.pos
if event.type == pygame.MOUSEBUTTONDOWN:
if event.button == 1:
add_force = True
if event.type == pygame.MOUSEBUTTONUP:
if event.button == 1:
pos_x = event.pos[0] - (SCREEN_WIDTH - TABLE_WIDTH) / 2
pos_y = event.pos[1] - (SCREEN_HEIGHT - TABLE_HEIGHT) / 2
balls[0].rigid_body.velocity = pymunk.Vec2d(pos_x - balls[0].rigid_body.position.x,
pos_y - balls[0].rigid_body.position.y).scale_to_length(force)
add_force = False
force = 5
if event.button == 3:
pos_x = event.pos[0] - (SCREEN_WIDTH - TABLE_WIDTH) / 2
pos_y = event.pos[1] - (SCREEN_HEIGHT - TABLE_HEIGHT) / 2
new_ball(space, (pos_x, pos_y))
# balls[0].rigid_body.velocity = (256, 0)
if add_force:
force += 5
if force >= 512:
force = 512
window.fill(WHITE)
table.goal(space, balls)
table.draw(window)
cue.draw(window)
for _ in balls:
_.resistance()
_.draw(window)
space.step(1 / FPS)
pygame.display.update()
clock.tick(FPS)
Loading…
Cancel
Save