Golf game boilerplateA small Bejeweled-like game in PygameSimple top down shooter gameSnake game in PygamePython/Pygame Fighting GameSimon memory game in pygameFlappy Bird Style Game in Space SettingMouse Click Controlled Meteor Avoidance GameSimple Python Pygame GameFirst Pong gamePython Pygame treasure hunt game

What is the opposite of 'gravitas'?

Simple image editor tool to draw a simple box/rectangle in an existing image

Blender - show edges angles “direction”

Is infinity mathematically observable?

A known event to a history junkie

Can a Bard use an arcane focus?

Did US corporations pay demonstrators in the German demonstrations against article 13?

Hostile work environment after whistle-blowing on coworker and our boss. What do I do?

Can somebody explain Brexit in a few child-proof sentences?

Would it be legal for a US State to ban exports of a natural resource?

Do all polymers contain either carbon or silicon?

How will losing mobility of one hand affect my career as a programmer?

Is there a good way to store credentials outside of a password manager?

Visiting the UK as unmarried couple

Giant Toughroad SLR 2 for 200 miles in two days, will it make it?

Teaching indefinite integrals that require special-casing

Are Warlocks Arcane or Divine?

Can you use Azure DevOps with Sitecore Managed Cloud

Pronouncing Homer as in modern Greek

Are taller landing gear bad for aircraft, particulary large airliners?

Is there a problem with hiding "forgot password" until it's needed?

Can I use my Chinese passport to enter China after I acquired another citizenship?

What should I use for Mishna study?

Word describing multiple paths to the same abstract outcome



Golf game boilerplate


A small Bejeweled-like game in PygameSimple top down shooter gameSnake game in PygamePython/Pygame Fighting GameSimon memory game in pygameFlappy Bird Style Game in Space SettingMouse Click Controlled Meteor Avoidance GameSimple Python Pygame GameFirst Pong gamePython Pygame treasure hunt game













3












$begingroup$


I wrote a program in pygame that basically acts as a physics engine for a ball. You can hit the ball around and your strokes are counted, as well as an extra stroke for going out of bounds. If I do further develop this, I'd make the angle and power display toggleable, but I do like showing them right now:



import pygame as pg
import math

SCREEN_WIDTH = 1500
SCREEN_HEIGHT = 800
WINDOW_COLOR = (100, 100, 100)
BALL_COLOR = (255, 255, 255)
BALL_OUTLINE_COLOR = (255, 0, 0)
LINE_COLOR = (0, 0, 255)
ALINE_COLOR = (0, 0, 0)
START_X = int(.5 * SCREEN_WIDTH)
START_Y = int(.99 * SCREEN_HEIGHT)
POWER_MULTIPLIER = .85
SPEED_MULTIPLIER = 2
BALL_RADIUS = 10

pg.init()
pg.display.set_caption('Golf')
window = pg.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
pg.event.set_grab(True)
pg.mouse.set_cursor((8, 8), (0, 0), (0, 0, 0, 0, 0, 0, 0, 0), (0, 0, 0, 0, 0, 0, 0, 0))

strokeFont = pg.font.SysFont("monospace", 50)
STROKECOLOR = (255, 255, 0)

powerFont = pg.font.SysFont("arial", 15, bold=True)
POWERCOLOR = (0, 255, 0)

angleFont = pg.font.SysFont("arial", 15, bold=True)
ANGLECOLOR = (0, 255, 0)

penaltyFont = pg.font.SysFont("georgia", 40, bold=True)
PENALTYCOLOR = (255, 0, 0)


class Ball(object):
def __init__(self, x, y, rad, c, oc):
self.x = x
self.y = y
self.radius = rad
self.color = c
self.outlinecolor = oc

def show(self, window):
pg.draw.circle(window, self.outlinecolor, (self.x, self.y), self.radius)
pg.draw.circle(window, self.color, (self.x, self.y), self.radius - int(.4 * self.radius))

@staticmethod
def path(x, y, p, a, t):
vx, vy = p * math.cos(a), p * math.sin(a) #Velocities
dx, dy = vx * t, vy * t - 4.9 * t ** 2 #Distances Traveled
print(' x-pos: %spx' % str(round(dx + x)))
print(' y-pos: %spx' % str(round(abs(dy - y))))

return round(dx + x), round(y - dy)

@staticmethod
def quadrant(x,y,xm,ym):
if ym < y and xm > x:
return 1
elif ym < y and xm < x:
return 2
elif ym > y and xm < x:
return 3
elif ym > y and xm > x:
return 4
else:
return False


def draw_window():
window.fill(WINDOW_COLOR)
ball.show(window)
if not shoot:
arrow(window, ALINE_COLOR, ALINE_COLOR, aline[0], aline[1], 5)
arrow(window, LINE_COLOR, LINE_COLOR, line[0], line[1], 5)

stroke_text = 'Strokes: %s' % strokes
stroke_label = strokeFont.render(stroke_text, 1, STROKECOLOR)
if not strokes:
window.blit(stroke_label, (SCREEN_WIDTH - .21 * SCREEN_WIDTH, SCREEN_HEIGHT - .985 * SCREEN_HEIGHT))
else:
window.blit(stroke_label, (SCREEN_WIDTH - (.21+.02*math.floor(math.log10(strokes))) * SCREEN_WIDTH, SCREEN_HEIGHT - .985 * SCREEN_HEIGHT))

power_text = 'Shot Strength: %sN' % power_display
power_label = powerFont.render(power_text, 1, POWERCOLOR)
if not shoot: window.blit(power_label, (cursor_pos[0] + .008 * SCREEN_WIDTH, cursor_pos[1]))

angle_text = 'Angle: %s°' % angle_display
angle_label = angleFont.render(angle_text, 1, ANGLECOLOR)
if not shoot: window.blit(angle_label, (ball.x - .06 * SCREEN_WIDTH, ball.y - .01 * SCREEN_HEIGHT))

if Penalty:
penalty_text = 'Out of Bounds! +1 Stroke'
penalty_label = penaltyFont.render(penalty_text, 1, PENALTYCOLOR)
penalty_rect = penalty_label.get_rect(center=(SCREEN_WIDTH/2, .225*SCREEN_HEIGHT))
window.blit(penalty_label, penalty_rect)

pg.display.flip()


def angle(cursor_pos):
x, y, xm, ym = ball.x, ball.y, cursor_pos[0], cursor_pos[1]
if x-xm:
angle = math.atan((y - ym) / (x - xm))
elif y > ym:
angle = math.pi/2
else:
angle = 3*math.pi/2

q = ball.quadrant(x,y,xm,ym)
if q: angle = math.pi*math.floor(q/2) - angle

if round(angle*180/math.pi) == 360:
angle = 0

if x > xm and round(angle*180/math.pi) == 0:
angle = math.pi

return angle


def arrow(screen, lcolor, tricolor, start, end, trirad):
pg.draw.line(screen, lcolor, start, end, 2)
rotation = math.degrees(math.atan2(start[1] - end[1], end[0] - start[0])) + 90
pg.draw.polygon(screen, tricolor, ((end[0] + trirad * math.sin(math.radians(rotation)),
end[1] + trirad * math.cos(math.radians(rotation))),
(end[0] + trirad * math.sin(math.radians(rotation - 120)),
end[1] + trirad * math.cos(math.radians(rotation - 120))),
(end[0] + trirad * math.sin(math.radians(rotation + 120)),
end[1] + trirad * math.cos(math.radians(rotation + 120)))))


def distance(x,y):
return math.sqrt(x**2 + y**2)


x, y, time, power, ang, strokes = 0, 0, 0, 0, 0, 0
xb, yb = None, None
shoot, Penalty = False, False
p_ticks = 0

ball = Ball(START_X, START_Y, BALL_RADIUS, BALL_COLOR, BALL_OUTLINE_COLOR)
quit = False
BARRIER = 1

try:
while not quit:
seconds=(pg.time.get_ticks()-p_ticks)/1000
if seconds > 1.2: Penalty = False

cursor_pos = pg.mouse.get_pos()
line = [(ball.x, ball.y), cursor_pos]
line_ball_x, line_ball_y = cursor_pos[0] - ball.x, cursor_pos[1] - ball.y

aline = [(ball.x, ball.y), (ball.x + .015 * SCREEN_WIDTH, ball.y)]

if not shoot:
power_display = round(
distance(line_ball_x, line_ball_y) * POWER_MULTIPLIER / 10)

angle_display = round(angle(cursor_pos) * 180 / math.pi)

if shoot:
if ball.y < SCREEN_HEIGHT:
if BARRIER < ball.x < SCREEN_WIDTH:
time += .3 * SPEED_MULTIPLIER
print('n time: %ss' % round(time, 2))
po = ball.path(x, y, power, ang, time)
ball.x, ball.y = po[0], po[1]
else:
print('Out of Bounds!')
Penalty = True
p_ticks = pg.time.get_ticks()
strokes += 1
shoot = False
if BARRIER < xb < SCREEN_WIDTH:
ball.x = xb
else:
ball.x = START_X
ball.y = yb
else:
shoot = False
ball.y = START_Y

for event in pg.event.get():
if event.type == pg.QUIT:
quit = True
if event.type == pg.KEYDOWN:
if event.key == pg.K_ESCAPE:
quit = True
if event.type == pg.MOUSEBUTTONDOWN:
if not shoot:
shoot = True
x, y = ball.x, ball.y
xb, yb = ball.x, ball.y
time, power = 0, (
distance(line_ball_x, line_ball_y)) * POWER_MULTIPLIER / 10
print('nnBall Hit!')
print('npower: %sN' % round(power, 2))
ang = angle(cursor_pos)
print('angle: %s°' % round(ang * 180 / math.pi, 2))
print('cos(a): %s' % round(math.cos(ang), 2)), print('sin(a): %s' % round(math.sin(ang), 2))
strokes += 1

draw_window()

print("nShutting down...")
pg.quit()

except Exception as error:
print(f'A fatal error (error) has occurred. The program is shutting down.')
pg.quit()


Feedback of any kind is very welcome!










share|improve this question











$endgroup$
















    3












    $begingroup$


    I wrote a program in pygame that basically acts as a physics engine for a ball. You can hit the ball around and your strokes are counted, as well as an extra stroke for going out of bounds. If I do further develop this, I'd make the angle and power display toggleable, but I do like showing them right now:



    import pygame as pg
    import math

    SCREEN_WIDTH = 1500
    SCREEN_HEIGHT = 800
    WINDOW_COLOR = (100, 100, 100)
    BALL_COLOR = (255, 255, 255)
    BALL_OUTLINE_COLOR = (255, 0, 0)
    LINE_COLOR = (0, 0, 255)
    ALINE_COLOR = (0, 0, 0)
    START_X = int(.5 * SCREEN_WIDTH)
    START_Y = int(.99 * SCREEN_HEIGHT)
    POWER_MULTIPLIER = .85
    SPEED_MULTIPLIER = 2
    BALL_RADIUS = 10

    pg.init()
    pg.display.set_caption('Golf')
    window = pg.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
    pg.event.set_grab(True)
    pg.mouse.set_cursor((8, 8), (0, 0), (0, 0, 0, 0, 0, 0, 0, 0), (0, 0, 0, 0, 0, 0, 0, 0))

    strokeFont = pg.font.SysFont("monospace", 50)
    STROKECOLOR = (255, 255, 0)

    powerFont = pg.font.SysFont("arial", 15, bold=True)
    POWERCOLOR = (0, 255, 0)

    angleFont = pg.font.SysFont("arial", 15, bold=True)
    ANGLECOLOR = (0, 255, 0)

    penaltyFont = pg.font.SysFont("georgia", 40, bold=True)
    PENALTYCOLOR = (255, 0, 0)


    class Ball(object):
    def __init__(self, x, y, rad, c, oc):
    self.x = x
    self.y = y
    self.radius = rad
    self.color = c
    self.outlinecolor = oc

    def show(self, window):
    pg.draw.circle(window, self.outlinecolor, (self.x, self.y), self.radius)
    pg.draw.circle(window, self.color, (self.x, self.y), self.radius - int(.4 * self.radius))

    @staticmethod
    def path(x, y, p, a, t):
    vx, vy = p * math.cos(a), p * math.sin(a) #Velocities
    dx, dy = vx * t, vy * t - 4.9 * t ** 2 #Distances Traveled
    print(' x-pos: %spx' % str(round(dx + x)))
    print(' y-pos: %spx' % str(round(abs(dy - y))))

    return round(dx + x), round(y - dy)

    @staticmethod
    def quadrant(x,y,xm,ym):
    if ym < y and xm > x:
    return 1
    elif ym < y and xm < x:
    return 2
    elif ym > y and xm < x:
    return 3
    elif ym > y and xm > x:
    return 4
    else:
    return False


    def draw_window():
    window.fill(WINDOW_COLOR)
    ball.show(window)
    if not shoot:
    arrow(window, ALINE_COLOR, ALINE_COLOR, aline[0], aline[1], 5)
    arrow(window, LINE_COLOR, LINE_COLOR, line[0], line[1], 5)

    stroke_text = 'Strokes: %s' % strokes
    stroke_label = strokeFont.render(stroke_text, 1, STROKECOLOR)
    if not strokes:
    window.blit(stroke_label, (SCREEN_WIDTH - .21 * SCREEN_WIDTH, SCREEN_HEIGHT - .985 * SCREEN_HEIGHT))
    else:
    window.blit(stroke_label, (SCREEN_WIDTH - (.21+.02*math.floor(math.log10(strokes))) * SCREEN_WIDTH, SCREEN_HEIGHT - .985 * SCREEN_HEIGHT))

    power_text = 'Shot Strength: %sN' % power_display
    power_label = powerFont.render(power_text, 1, POWERCOLOR)
    if not shoot: window.blit(power_label, (cursor_pos[0] + .008 * SCREEN_WIDTH, cursor_pos[1]))

    angle_text = 'Angle: %s°' % angle_display
    angle_label = angleFont.render(angle_text, 1, ANGLECOLOR)
    if not shoot: window.blit(angle_label, (ball.x - .06 * SCREEN_WIDTH, ball.y - .01 * SCREEN_HEIGHT))

    if Penalty:
    penalty_text = 'Out of Bounds! +1 Stroke'
    penalty_label = penaltyFont.render(penalty_text, 1, PENALTYCOLOR)
    penalty_rect = penalty_label.get_rect(center=(SCREEN_WIDTH/2, .225*SCREEN_HEIGHT))
    window.blit(penalty_label, penalty_rect)

    pg.display.flip()


    def angle(cursor_pos):
    x, y, xm, ym = ball.x, ball.y, cursor_pos[0], cursor_pos[1]
    if x-xm:
    angle = math.atan((y - ym) / (x - xm))
    elif y > ym:
    angle = math.pi/2
    else:
    angle = 3*math.pi/2

    q = ball.quadrant(x,y,xm,ym)
    if q: angle = math.pi*math.floor(q/2) - angle

    if round(angle*180/math.pi) == 360:
    angle = 0

    if x > xm and round(angle*180/math.pi) == 0:
    angle = math.pi

    return angle


    def arrow(screen, lcolor, tricolor, start, end, trirad):
    pg.draw.line(screen, lcolor, start, end, 2)
    rotation = math.degrees(math.atan2(start[1] - end[1], end[0] - start[0])) + 90
    pg.draw.polygon(screen, tricolor, ((end[0] + trirad * math.sin(math.radians(rotation)),
    end[1] + trirad * math.cos(math.radians(rotation))),
    (end[0] + trirad * math.sin(math.radians(rotation - 120)),
    end[1] + trirad * math.cos(math.radians(rotation - 120))),
    (end[0] + trirad * math.sin(math.radians(rotation + 120)),
    end[1] + trirad * math.cos(math.radians(rotation + 120)))))


    def distance(x,y):
    return math.sqrt(x**2 + y**2)


    x, y, time, power, ang, strokes = 0, 0, 0, 0, 0, 0
    xb, yb = None, None
    shoot, Penalty = False, False
    p_ticks = 0

    ball = Ball(START_X, START_Y, BALL_RADIUS, BALL_COLOR, BALL_OUTLINE_COLOR)
    quit = False
    BARRIER = 1

    try:
    while not quit:
    seconds=(pg.time.get_ticks()-p_ticks)/1000
    if seconds > 1.2: Penalty = False

    cursor_pos = pg.mouse.get_pos()
    line = [(ball.x, ball.y), cursor_pos]
    line_ball_x, line_ball_y = cursor_pos[0] - ball.x, cursor_pos[1] - ball.y

    aline = [(ball.x, ball.y), (ball.x + .015 * SCREEN_WIDTH, ball.y)]

    if not shoot:
    power_display = round(
    distance(line_ball_x, line_ball_y) * POWER_MULTIPLIER / 10)

    angle_display = round(angle(cursor_pos) * 180 / math.pi)

    if shoot:
    if ball.y < SCREEN_HEIGHT:
    if BARRIER < ball.x < SCREEN_WIDTH:
    time += .3 * SPEED_MULTIPLIER
    print('n time: %ss' % round(time, 2))
    po = ball.path(x, y, power, ang, time)
    ball.x, ball.y = po[0], po[1]
    else:
    print('Out of Bounds!')
    Penalty = True
    p_ticks = pg.time.get_ticks()
    strokes += 1
    shoot = False
    if BARRIER < xb < SCREEN_WIDTH:
    ball.x = xb
    else:
    ball.x = START_X
    ball.y = yb
    else:
    shoot = False
    ball.y = START_Y

    for event in pg.event.get():
    if event.type == pg.QUIT:
    quit = True
    if event.type == pg.KEYDOWN:
    if event.key == pg.K_ESCAPE:
    quit = True
    if event.type == pg.MOUSEBUTTONDOWN:
    if not shoot:
    shoot = True
    x, y = ball.x, ball.y
    xb, yb = ball.x, ball.y
    time, power = 0, (
    distance(line_ball_x, line_ball_y)) * POWER_MULTIPLIER / 10
    print('nnBall Hit!')
    print('npower: %sN' % round(power, 2))
    ang = angle(cursor_pos)
    print('angle: %s°' % round(ang * 180 / math.pi, 2))
    print('cos(a): %s' % round(math.cos(ang), 2)), print('sin(a): %s' % round(math.sin(ang), 2))
    strokes += 1

    draw_window()

    print("nShutting down...")
    pg.quit()

    except Exception as error:
    print(f'A fatal error (error) has occurred. The program is shutting down.')
    pg.quit()


    Feedback of any kind is very welcome!










    share|improve this question











    $endgroup$














      3












      3








      3





      $begingroup$


      I wrote a program in pygame that basically acts as a physics engine for a ball. You can hit the ball around and your strokes are counted, as well as an extra stroke for going out of bounds. If I do further develop this, I'd make the angle and power display toggleable, but I do like showing them right now:



      import pygame as pg
      import math

      SCREEN_WIDTH = 1500
      SCREEN_HEIGHT = 800
      WINDOW_COLOR = (100, 100, 100)
      BALL_COLOR = (255, 255, 255)
      BALL_OUTLINE_COLOR = (255, 0, 0)
      LINE_COLOR = (0, 0, 255)
      ALINE_COLOR = (0, 0, 0)
      START_X = int(.5 * SCREEN_WIDTH)
      START_Y = int(.99 * SCREEN_HEIGHT)
      POWER_MULTIPLIER = .85
      SPEED_MULTIPLIER = 2
      BALL_RADIUS = 10

      pg.init()
      pg.display.set_caption('Golf')
      window = pg.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
      pg.event.set_grab(True)
      pg.mouse.set_cursor((8, 8), (0, 0), (0, 0, 0, 0, 0, 0, 0, 0), (0, 0, 0, 0, 0, 0, 0, 0))

      strokeFont = pg.font.SysFont("monospace", 50)
      STROKECOLOR = (255, 255, 0)

      powerFont = pg.font.SysFont("arial", 15, bold=True)
      POWERCOLOR = (0, 255, 0)

      angleFont = pg.font.SysFont("arial", 15, bold=True)
      ANGLECOLOR = (0, 255, 0)

      penaltyFont = pg.font.SysFont("georgia", 40, bold=True)
      PENALTYCOLOR = (255, 0, 0)


      class Ball(object):
      def __init__(self, x, y, rad, c, oc):
      self.x = x
      self.y = y
      self.radius = rad
      self.color = c
      self.outlinecolor = oc

      def show(self, window):
      pg.draw.circle(window, self.outlinecolor, (self.x, self.y), self.radius)
      pg.draw.circle(window, self.color, (self.x, self.y), self.radius - int(.4 * self.radius))

      @staticmethod
      def path(x, y, p, a, t):
      vx, vy = p * math.cos(a), p * math.sin(a) #Velocities
      dx, dy = vx * t, vy * t - 4.9 * t ** 2 #Distances Traveled
      print(' x-pos: %spx' % str(round(dx + x)))
      print(' y-pos: %spx' % str(round(abs(dy - y))))

      return round(dx + x), round(y - dy)

      @staticmethod
      def quadrant(x,y,xm,ym):
      if ym < y and xm > x:
      return 1
      elif ym < y and xm < x:
      return 2
      elif ym > y and xm < x:
      return 3
      elif ym > y and xm > x:
      return 4
      else:
      return False


      def draw_window():
      window.fill(WINDOW_COLOR)
      ball.show(window)
      if not shoot:
      arrow(window, ALINE_COLOR, ALINE_COLOR, aline[0], aline[1], 5)
      arrow(window, LINE_COLOR, LINE_COLOR, line[0], line[1], 5)

      stroke_text = 'Strokes: %s' % strokes
      stroke_label = strokeFont.render(stroke_text, 1, STROKECOLOR)
      if not strokes:
      window.blit(stroke_label, (SCREEN_WIDTH - .21 * SCREEN_WIDTH, SCREEN_HEIGHT - .985 * SCREEN_HEIGHT))
      else:
      window.blit(stroke_label, (SCREEN_WIDTH - (.21+.02*math.floor(math.log10(strokes))) * SCREEN_WIDTH, SCREEN_HEIGHT - .985 * SCREEN_HEIGHT))

      power_text = 'Shot Strength: %sN' % power_display
      power_label = powerFont.render(power_text, 1, POWERCOLOR)
      if not shoot: window.blit(power_label, (cursor_pos[0] + .008 * SCREEN_WIDTH, cursor_pos[1]))

      angle_text = 'Angle: %s°' % angle_display
      angle_label = angleFont.render(angle_text, 1, ANGLECOLOR)
      if not shoot: window.blit(angle_label, (ball.x - .06 * SCREEN_WIDTH, ball.y - .01 * SCREEN_HEIGHT))

      if Penalty:
      penalty_text = 'Out of Bounds! +1 Stroke'
      penalty_label = penaltyFont.render(penalty_text, 1, PENALTYCOLOR)
      penalty_rect = penalty_label.get_rect(center=(SCREEN_WIDTH/2, .225*SCREEN_HEIGHT))
      window.blit(penalty_label, penalty_rect)

      pg.display.flip()


      def angle(cursor_pos):
      x, y, xm, ym = ball.x, ball.y, cursor_pos[0], cursor_pos[1]
      if x-xm:
      angle = math.atan((y - ym) / (x - xm))
      elif y > ym:
      angle = math.pi/2
      else:
      angle = 3*math.pi/2

      q = ball.quadrant(x,y,xm,ym)
      if q: angle = math.pi*math.floor(q/2) - angle

      if round(angle*180/math.pi) == 360:
      angle = 0

      if x > xm and round(angle*180/math.pi) == 0:
      angle = math.pi

      return angle


      def arrow(screen, lcolor, tricolor, start, end, trirad):
      pg.draw.line(screen, lcolor, start, end, 2)
      rotation = math.degrees(math.atan2(start[1] - end[1], end[0] - start[0])) + 90
      pg.draw.polygon(screen, tricolor, ((end[0] + trirad * math.sin(math.radians(rotation)),
      end[1] + trirad * math.cos(math.radians(rotation))),
      (end[0] + trirad * math.sin(math.radians(rotation - 120)),
      end[1] + trirad * math.cos(math.radians(rotation - 120))),
      (end[0] + trirad * math.sin(math.radians(rotation + 120)),
      end[1] + trirad * math.cos(math.radians(rotation + 120)))))


      def distance(x,y):
      return math.sqrt(x**2 + y**2)


      x, y, time, power, ang, strokes = 0, 0, 0, 0, 0, 0
      xb, yb = None, None
      shoot, Penalty = False, False
      p_ticks = 0

      ball = Ball(START_X, START_Y, BALL_RADIUS, BALL_COLOR, BALL_OUTLINE_COLOR)
      quit = False
      BARRIER = 1

      try:
      while not quit:
      seconds=(pg.time.get_ticks()-p_ticks)/1000
      if seconds > 1.2: Penalty = False

      cursor_pos = pg.mouse.get_pos()
      line = [(ball.x, ball.y), cursor_pos]
      line_ball_x, line_ball_y = cursor_pos[0] - ball.x, cursor_pos[1] - ball.y

      aline = [(ball.x, ball.y), (ball.x + .015 * SCREEN_WIDTH, ball.y)]

      if not shoot:
      power_display = round(
      distance(line_ball_x, line_ball_y) * POWER_MULTIPLIER / 10)

      angle_display = round(angle(cursor_pos) * 180 / math.pi)

      if shoot:
      if ball.y < SCREEN_HEIGHT:
      if BARRIER < ball.x < SCREEN_WIDTH:
      time += .3 * SPEED_MULTIPLIER
      print('n time: %ss' % round(time, 2))
      po = ball.path(x, y, power, ang, time)
      ball.x, ball.y = po[0], po[1]
      else:
      print('Out of Bounds!')
      Penalty = True
      p_ticks = pg.time.get_ticks()
      strokes += 1
      shoot = False
      if BARRIER < xb < SCREEN_WIDTH:
      ball.x = xb
      else:
      ball.x = START_X
      ball.y = yb
      else:
      shoot = False
      ball.y = START_Y

      for event in pg.event.get():
      if event.type == pg.QUIT:
      quit = True
      if event.type == pg.KEYDOWN:
      if event.key == pg.K_ESCAPE:
      quit = True
      if event.type == pg.MOUSEBUTTONDOWN:
      if not shoot:
      shoot = True
      x, y = ball.x, ball.y
      xb, yb = ball.x, ball.y
      time, power = 0, (
      distance(line_ball_x, line_ball_y)) * POWER_MULTIPLIER / 10
      print('nnBall Hit!')
      print('npower: %sN' % round(power, 2))
      ang = angle(cursor_pos)
      print('angle: %s°' % round(ang * 180 / math.pi, 2))
      print('cos(a): %s' % round(math.cos(ang), 2)), print('sin(a): %s' % round(math.sin(ang), 2))
      strokes += 1

      draw_window()

      print("nShutting down...")
      pg.quit()

      except Exception as error:
      print(f'A fatal error (error) has occurred. The program is shutting down.')
      pg.quit()


      Feedback of any kind is very welcome!










      share|improve this question











      $endgroup$




      I wrote a program in pygame that basically acts as a physics engine for a ball. You can hit the ball around and your strokes are counted, as well as an extra stroke for going out of bounds. If I do further develop this, I'd make the angle and power display toggleable, but I do like showing them right now:



      import pygame as pg
      import math

      SCREEN_WIDTH = 1500
      SCREEN_HEIGHT = 800
      WINDOW_COLOR = (100, 100, 100)
      BALL_COLOR = (255, 255, 255)
      BALL_OUTLINE_COLOR = (255, 0, 0)
      LINE_COLOR = (0, 0, 255)
      ALINE_COLOR = (0, 0, 0)
      START_X = int(.5 * SCREEN_WIDTH)
      START_Y = int(.99 * SCREEN_HEIGHT)
      POWER_MULTIPLIER = .85
      SPEED_MULTIPLIER = 2
      BALL_RADIUS = 10

      pg.init()
      pg.display.set_caption('Golf')
      window = pg.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
      pg.event.set_grab(True)
      pg.mouse.set_cursor((8, 8), (0, 0), (0, 0, 0, 0, 0, 0, 0, 0), (0, 0, 0, 0, 0, 0, 0, 0))

      strokeFont = pg.font.SysFont("monospace", 50)
      STROKECOLOR = (255, 255, 0)

      powerFont = pg.font.SysFont("arial", 15, bold=True)
      POWERCOLOR = (0, 255, 0)

      angleFont = pg.font.SysFont("arial", 15, bold=True)
      ANGLECOLOR = (0, 255, 0)

      penaltyFont = pg.font.SysFont("georgia", 40, bold=True)
      PENALTYCOLOR = (255, 0, 0)


      class Ball(object):
      def __init__(self, x, y, rad, c, oc):
      self.x = x
      self.y = y
      self.radius = rad
      self.color = c
      self.outlinecolor = oc

      def show(self, window):
      pg.draw.circle(window, self.outlinecolor, (self.x, self.y), self.radius)
      pg.draw.circle(window, self.color, (self.x, self.y), self.radius - int(.4 * self.radius))

      @staticmethod
      def path(x, y, p, a, t):
      vx, vy = p * math.cos(a), p * math.sin(a) #Velocities
      dx, dy = vx * t, vy * t - 4.9 * t ** 2 #Distances Traveled
      print(' x-pos: %spx' % str(round(dx + x)))
      print(' y-pos: %spx' % str(round(abs(dy - y))))

      return round(dx + x), round(y - dy)

      @staticmethod
      def quadrant(x,y,xm,ym):
      if ym < y and xm > x:
      return 1
      elif ym < y and xm < x:
      return 2
      elif ym > y and xm < x:
      return 3
      elif ym > y and xm > x:
      return 4
      else:
      return False


      def draw_window():
      window.fill(WINDOW_COLOR)
      ball.show(window)
      if not shoot:
      arrow(window, ALINE_COLOR, ALINE_COLOR, aline[0], aline[1], 5)
      arrow(window, LINE_COLOR, LINE_COLOR, line[0], line[1], 5)

      stroke_text = 'Strokes: %s' % strokes
      stroke_label = strokeFont.render(stroke_text, 1, STROKECOLOR)
      if not strokes:
      window.blit(stroke_label, (SCREEN_WIDTH - .21 * SCREEN_WIDTH, SCREEN_HEIGHT - .985 * SCREEN_HEIGHT))
      else:
      window.blit(stroke_label, (SCREEN_WIDTH - (.21+.02*math.floor(math.log10(strokes))) * SCREEN_WIDTH, SCREEN_HEIGHT - .985 * SCREEN_HEIGHT))

      power_text = 'Shot Strength: %sN' % power_display
      power_label = powerFont.render(power_text, 1, POWERCOLOR)
      if not shoot: window.blit(power_label, (cursor_pos[0] + .008 * SCREEN_WIDTH, cursor_pos[1]))

      angle_text = 'Angle: %s°' % angle_display
      angle_label = angleFont.render(angle_text, 1, ANGLECOLOR)
      if not shoot: window.blit(angle_label, (ball.x - .06 * SCREEN_WIDTH, ball.y - .01 * SCREEN_HEIGHT))

      if Penalty:
      penalty_text = 'Out of Bounds! +1 Stroke'
      penalty_label = penaltyFont.render(penalty_text, 1, PENALTYCOLOR)
      penalty_rect = penalty_label.get_rect(center=(SCREEN_WIDTH/2, .225*SCREEN_HEIGHT))
      window.blit(penalty_label, penalty_rect)

      pg.display.flip()


      def angle(cursor_pos):
      x, y, xm, ym = ball.x, ball.y, cursor_pos[0], cursor_pos[1]
      if x-xm:
      angle = math.atan((y - ym) / (x - xm))
      elif y > ym:
      angle = math.pi/2
      else:
      angle = 3*math.pi/2

      q = ball.quadrant(x,y,xm,ym)
      if q: angle = math.pi*math.floor(q/2) - angle

      if round(angle*180/math.pi) == 360:
      angle = 0

      if x > xm and round(angle*180/math.pi) == 0:
      angle = math.pi

      return angle


      def arrow(screen, lcolor, tricolor, start, end, trirad):
      pg.draw.line(screen, lcolor, start, end, 2)
      rotation = math.degrees(math.atan2(start[1] - end[1], end[0] - start[0])) + 90
      pg.draw.polygon(screen, tricolor, ((end[0] + trirad * math.sin(math.radians(rotation)),
      end[1] + trirad * math.cos(math.radians(rotation))),
      (end[0] + trirad * math.sin(math.radians(rotation - 120)),
      end[1] + trirad * math.cos(math.radians(rotation - 120))),
      (end[0] + trirad * math.sin(math.radians(rotation + 120)),
      end[1] + trirad * math.cos(math.radians(rotation + 120)))))


      def distance(x,y):
      return math.sqrt(x**2 + y**2)


      x, y, time, power, ang, strokes = 0, 0, 0, 0, 0, 0
      xb, yb = None, None
      shoot, Penalty = False, False
      p_ticks = 0

      ball = Ball(START_X, START_Y, BALL_RADIUS, BALL_COLOR, BALL_OUTLINE_COLOR)
      quit = False
      BARRIER = 1

      try:
      while not quit:
      seconds=(pg.time.get_ticks()-p_ticks)/1000
      if seconds > 1.2: Penalty = False

      cursor_pos = pg.mouse.get_pos()
      line = [(ball.x, ball.y), cursor_pos]
      line_ball_x, line_ball_y = cursor_pos[0] - ball.x, cursor_pos[1] - ball.y

      aline = [(ball.x, ball.y), (ball.x + .015 * SCREEN_WIDTH, ball.y)]

      if not shoot:
      power_display = round(
      distance(line_ball_x, line_ball_y) * POWER_MULTIPLIER / 10)

      angle_display = round(angle(cursor_pos) * 180 / math.pi)

      if shoot:
      if ball.y < SCREEN_HEIGHT:
      if BARRIER < ball.x < SCREEN_WIDTH:
      time += .3 * SPEED_MULTIPLIER
      print('n time: %ss' % round(time, 2))
      po = ball.path(x, y, power, ang, time)
      ball.x, ball.y = po[0], po[1]
      else:
      print('Out of Bounds!')
      Penalty = True
      p_ticks = pg.time.get_ticks()
      strokes += 1
      shoot = False
      if BARRIER < xb < SCREEN_WIDTH:
      ball.x = xb
      else:
      ball.x = START_X
      ball.y = yb
      else:
      shoot = False
      ball.y = START_Y

      for event in pg.event.get():
      if event.type == pg.QUIT:
      quit = True
      if event.type == pg.KEYDOWN:
      if event.key == pg.K_ESCAPE:
      quit = True
      if event.type == pg.MOUSEBUTTONDOWN:
      if not shoot:
      shoot = True
      x, y = ball.x, ball.y
      xb, yb = ball.x, ball.y
      time, power = 0, (
      distance(line_ball_x, line_ball_y)) * POWER_MULTIPLIER / 10
      print('nnBall Hit!')
      print('npower: %sN' % round(power, 2))
      ang = angle(cursor_pos)
      print('angle: %s°' % round(ang * 180 / math.pi, 2))
      print('cos(a): %s' % round(math.cos(ang), 2)), print('sin(a): %s' % round(math.sin(ang), 2))
      strokes += 1

      draw_window()

      print("nShutting down...")
      pg.quit()

      except Exception as error:
      print(f'A fatal error (error) has occurred. The program is shutting down.')
      pg.quit()


      Feedback of any kind is very welcome!







      python pygame physics






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited 3 hours ago









      Alex

      653313




      653313










      asked 3 hours ago









      alec935alec935

      1755




      1755




















          2 Answers
          2






          active

          oldest

          votes


















          2












          $begingroup$

          Overall it isn't bad.



          Direct imports for common symbols



          Based on your discretion, certain often-used and unambiguous symbols can be imported without their module namespace, i.e.



          from pg.font import SysFont
          # ...
          strokeFont = SysFont("monospace", 50)


          snake_case



          i.e. stroke_font for variables and function names. Also, Penalty should be lower-case because it isn't a class.



          debug printing



          This kind of thing:



          print(' x-pos: %spx' % str(round(dx + x)))


          can be improved in a few ways. Firstly, it looks like a debugging output and not actual game content, so typically you won't want to print this at all. That doesn't mean that you have to delete it, though - you can use actual Python logging at level debug to be able to select at the top level whether these statements are printed.



          Also: do you really need round? Could you instead go



          print(f' x-pos: dx + x:.0fpx')


          f-strings



          As in the previous example, you should consider using the new syntactical sugar of f-strings instead of the % operator.



          Global clutter



          It's tempting in Python to add a bunch of stuff (x, y, time, power, etc.) to the global scope. Don't give in! Put these into a game state object. Break up your global code into multiple subroutines, potentially in methods of the game state object.



          Shadowing



          Don't call something time. time is already a thing in Python.



          Math



          I kind of had to jump through some hoops to take advantage of atan2. I don't recommend doing this, but here's a one-liner alternative to your quadrant function:



          return int(4 + 2/pi*atan2(y - ym, xm - x)) % 4 + 1





          share|improve this answer











          $endgroup$




















            0












            $begingroup$

            Some of this is nit-pickery, some is more fundamental:



            Import Order



            PEP-8 suggests an ordering to imports. No reason not to use it:




            Imports should be grouped in the following order:



            Standard library imports.
            Related third party imports.
            Local application/library specific imports.


            You should put a blank line between each group of imports.




            Code Organization: Constants



            You have a bunch of "constants" defined. They're all-caps, which is good. They're declared together and at the top of the file, which is good. But they really shouldn't be global constants.



            For example, you have a Ball class. Yet there are global constants named BALL_COLOR and BALL_OUTLINE_COLOR and BALL_RADIUS. Why is that? If they're related to your class, make them class constants.



            class Ball:
            BODY_COLOR = (255, 255, 255)
            OUTLINE_COLOR = (255, 0, 0)
            RADIUS = 10


            Code Organization: Types



            In the same vein, you make a lot of use of tuples. But you just create them in-line and rely on convention to access them. Why not go ahead and use a collections.namedtuple or even two?



            import collections

            Size = collections.namedtuple('Size', 'width height')
            Position = collections.namedtuple('Position', 'x y')

            WINDOW_SIZE = Size(width=1500, height=800)
            START_POS = Position(x=0.5 * WINDOW_SIZE.width, y=0.99 * WINDOW_SIZE.height)


            Code Organization: Functions



            You have a lot of stuff at module scope. Sooner or later you'll want to either write a unit test, or run the debugger, or load your code into the command-line Python REPL. All of this is made easier if you move the module-scope statements into a main function, or some other-named function.



            def main():
            pg.init()
            pg.display.set_caption('Golf')
            ... etc ...


            You have a set of font/color variables that you create at module scope. There aren't currently enough drawing functions to create a Window class or anything, but you might consider putting them into a Config class. (And using snake_case names.)



            Also, you have a lot of pygame boilerplate mixed in with your game logic. I'd suggest separating the boilerplate into separate functions, something like:



            while still_playing:
            handle_events()
            update()
            render() # You call this "draw_window()" which is fine.


            Most of your logic, of course, will be in update(). In fact, since it mostly has to do with updating the position of the Ball object, it should mostly be in a call to ball.update_position(delay) (or some such name).



            You make use of a pair of temporaries x and y, but it seems like you could replace those with an old-position attribute on the Ball, or a second Ball object, or something.






            share|improve this answer









            $endgroup$












              Your Answer





              StackExchange.ifUsing("editor", function ()
              return StackExchange.using("mathjaxEditing", function ()
              StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix)
              StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
              );
              );
              , "mathjax-editing");

              StackExchange.ifUsing("editor", function ()
              StackExchange.using("externalEditor", function ()
              StackExchange.using("snippets", function ()
              StackExchange.snippets.init();
              );
              );
              , "code-snippets");

              StackExchange.ready(function()
              var channelOptions =
              tags: "".split(" "),
              id: "196"
              ;
              initTagRenderer("".split(" "), "".split(" "), channelOptions);

              StackExchange.using("externalEditor", function()
              // Have to fire editor after snippets, if snippets enabled
              if (StackExchange.settings.snippets.snippetsEnabled)
              StackExchange.using("snippets", function()
              createEditor();
              );

              else
              createEditor();

              );

              function createEditor()
              StackExchange.prepareEditor(
              heartbeatType: 'answer',
              autoActivateHeartbeat: false,
              convertImagesToLinks: false,
              noModals: true,
              showLowRepImageUploadWarning: true,
              reputationToPostImages: null,
              bindNavPrevention: true,
              postfix: "",
              imageUploader:
              brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
              contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
              allowUrls: true
              ,
              onDemand: true,
              discardSelector: ".discard-answer"
              ,immediatelyShowMarkdownHelp:true
              );



              );













              draft saved

              draft discarded


















              StackExchange.ready(
              function ()
              StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f216199%2fgolf-game-boilerplate%23new-answer', 'question_page');

              );

              Post as a guest















              Required, but never shown

























              2 Answers
              2






              active

              oldest

              votes








              2 Answers
              2






              active

              oldest

              votes









              active

              oldest

              votes






              active

              oldest

              votes









              2












              $begingroup$

              Overall it isn't bad.



              Direct imports for common symbols



              Based on your discretion, certain often-used and unambiguous symbols can be imported without their module namespace, i.e.



              from pg.font import SysFont
              # ...
              strokeFont = SysFont("monospace", 50)


              snake_case



              i.e. stroke_font for variables and function names. Also, Penalty should be lower-case because it isn't a class.



              debug printing



              This kind of thing:



              print(' x-pos: %spx' % str(round(dx + x)))


              can be improved in a few ways. Firstly, it looks like a debugging output and not actual game content, so typically you won't want to print this at all. That doesn't mean that you have to delete it, though - you can use actual Python logging at level debug to be able to select at the top level whether these statements are printed.



              Also: do you really need round? Could you instead go



              print(f' x-pos: dx + x:.0fpx')


              f-strings



              As in the previous example, you should consider using the new syntactical sugar of f-strings instead of the % operator.



              Global clutter



              It's tempting in Python to add a bunch of stuff (x, y, time, power, etc.) to the global scope. Don't give in! Put these into a game state object. Break up your global code into multiple subroutines, potentially in methods of the game state object.



              Shadowing



              Don't call something time. time is already a thing in Python.



              Math



              I kind of had to jump through some hoops to take advantage of atan2. I don't recommend doing this, but here's a one-liner alternative to your quadrant function:



              return int(4 + 2/pi*atan2(y - ym, xm - x)) % 4 + 1





              share|improve this answer











              $endgroup$

















                2












                $begingroup$

                Overall it isn't bad.



                Direct imports for common symbols



                Based on your discretion, certain often-used and unambiguous symbols can be imported without their module namespace, i.e.



                from pg.font import SysFont
                # ...
                strokeFont = SysFont("monospace", 50)


                snake_case



                i.e. stroke_font for variables and function names. Also, Penalty should be lower-case because it isn't a class.



                debug printing



                This kind of thing:



                print(' x-pos: %spx' % str(round(dx + x)))


                can be improved in a few ways. Firstly, it looks like a debugging output and not actual game content, so typically you won't want to print this at all. That doesn't mean that you have to delete it, though - you can use actual Python logging at level debug to be able to select at the top level whether these statements are printed.



                Also: do you really need round? Could you instead go



                print(f' x-pos: dx + x:.0fpx')


                f-strings



                As in the previous example, you should consider using the new syntactical sugar of f-strings instead of the % operator.



                Global clutter



                It's tempting in Python to add a bunch of stuff (x, y, time, power, etc.) to the global scope. Don't give in! Put these into a game state object. Break up your global code into multiple subroutines, potentially in methods of the game state object.



                Shadowing



                Don't call something time. time is already a thing in Python.



                Math



                I kind of had to jump through some hoops to take advantage of atan2. I don't recommend doing this, but here's a one-liner alternative to your quadrant function:



                return int(4 + 2/pi*atan2(y - ym, xm - x)) % 4 + 1





                share|improve this answer











                $endgroup$















                  2












                  2








                  2





                  $begingroup$

                  Overall it isn't bad.



                  Direct imports for common symbols



                  Based on your discretion, certain often-used and unambiguous symbols can be imported without their module namespace, i.e.



                  from pg.font import SysFont
                  # ...
                  strokeFont = SysFont("monospace", 50)


                  snake_case



                  i.e. stroke_font for variables and function names. Also, Penalty should be lower-case because it isn't a class.



                  debug printing



                  This kind of thing:



                  print(' x-pos: %spx' % str(round(dx + x)))


                  can be improved in a few ways. Firstly, it looks like a debugging output and not actual game content, so typically you won't want to print this at all. That doesn't mean that you have to delete it, though - you can use actual Python logging at level debug to be able to select at the top level whether these statements are printed.



                  Also: do you really need round? Could you instead go



                  print(f' x-pos: dx + x:.0fpx')


                  f-strings



                  As in the previous example, you should consider using the new syntactical sugar of f-strings instead of the % operator.



                  Global clutter



                  It's tempting in Python to add a bunch of stuff (x, y, time, power, etc.) to the global scope. Don't give in! Put these into a game state object. Break up your global code into multiple subroutines, potentially in methods of the game state object.



                  Shadowing



                  Don't call something time. time is already a thing in Python.



                  Math



                  I kind of had to jump through some hoops to take advantage of atan2. I don't recommend doing this, but here's a one-liner alternative to your quadrant function:



                  return int(4 + 2/pi*atan2(y - ym, xm - x)) % 4 + 1





                  share|improve this answer











                  $endgroup$



                  Overall it isn't bad.



                  Direct imports for common symbols



                  Based on your discretion, certain often-used and unambiguous symbols can be imported without their module namespace, i.e.



                  from pg.font import SysFont
                  # ...
                  strokeFont = SysFont("monospace", 50)


                  snake_case



                  i.e. stroke_font for variables and function names. Also, Penalty should be lower-case because it isn't a class.



                  debug printing



                  This kind of thing:



                  print(' x-pos: %spx' % str(round(dx + x)))


                  can be improved in a few ways. Firstly, it looks like a debugging output and not actual game content, so typically you won't want to print this at all. That doesn't mean that you have to delete it, though - you can use actual Python logging at level debug to be able to select at the top level whether these statements are printed.



                  Also: do you really need round? Could you instead go



                  print(f' x-pos: dx + x:.0fpx')


                  f-strings



                  As in the previous example, you should consider using the new syntactical sugar of f-strings instead of the % operator.



                  Global clutter



                  It's tempting in Python to add a bunch of stuff (x, y, time, power, etc.) to the global scope. Don't give in! Put these into a game state object. Break up your global code into multiple subroutines, potentially in methods of the game state object.



                  Shadowing



                  Don't call something time. time is already a thing in Python.



                  Math



                  I kind of had to jump through some hoops to take advantage of atan2. I don't recommend doing this, but here's a one-liner alternative to your quadrant function:



                  return int(4 + 2/pi*atan2(y - ym, xm - x)) % 4 + 1






                  share|improve this answer














                  share|improve this answer



                  share|improve this answer








                  edited 1 hour ago

























                  answered 1 hour ago









                  ReinderienReinderien

                  4,395822




                  4,395822























                      0












                      $begingroup$

                      Some of this is nit-pickery, some is more fundamental:



                      Import Order



                      PEP-8 suggests an ordering to imports. No reason not to use it:




                      Imports should be grouped in the following order:



                      Standard library imports.
                      Related third party imports.
                      Local application/library specific imports.


                      You should put a blank line between each group of imports.




                      Code Organization: Constants



                      You have a bunch of "constants" defined. They're all-caps, which is good. They're declared together and at the top of the file, which is good. But they really shouldn't be global constants.



                      For example, you have a Ball class. Yet there are global constants named BALL_COLOR and BALL_OUTLINE_COLOR and BALL_RADIUS. Why is that? If they're related to your class, make them class constants.



                      class Ball:
                      BODY_COLOR = (255, 255, 255)
                      OUTLINE_COLOR = (255, 0, 0)
                      RADIUS = 10


                      Code Organization: Types



                      In the same vein, you make a lot of use of tuples. But you just create them in-line and rely on convention to access them. Why not go ahead and use a collections.namedtuple or even two?



                      import collections

                      Size = collections.namedtuple('Size', 'width height')
                      Position = collections.namedtuple('Position', 'x y')

                      WINDOW_SIZE = Size(width=1500, height=800)
                      START_POS = Position(x=0.5 * WINDOW_SIZE.width, y=0.99 * WINDOW_SIZE.height)


                      Code Organization: Functions



                      You have a lot of stuff at module scope. Sooner or later you'll want to either write a unit test, or run the debugger, or load your code into the command-line Python REPL. All of this is made easier if you move the module-scope statements into a main function, or some other-named function.



                      def main():
                      pg.init()
                      pg.display.set_caption('Golf')
                      ... etc ...


                      You have a set of font/color variables that you create at module scope. There aren't currently enough drawing functions to create a Window class or anything, but you might consider putting them into a Config class. (And using snake_case names.)



                      Also, you have a lot of pygame boilerplate mixed in with your game logic. I'd suggest separating the boilerplate into separate functions, something like:



                      while still_playing:
                      handle_events()
                      update()
                      render() # You call this "draw_window()" which is fine.


                      Most of your logic, of course, will be in update(). In fact, since it mostly has to do with updating the position of the Ball object, it should mostly be in a call to ball.update_position(delay) (or some such name).



                      You make use of a pair of temporaries x and y, but it seems like you could replace those with an old-position attribute on the Ball, or a second Ball object, or something.






                      share|improve this answer









                      $endgroup$

















                        0












                        $begingroup$

                        Some of this is nit-pickery, some is more fundamental:



                        Import Order



                        PEP-8 suggests an ordering to imports. No reason not to use it:




                        Imports should be grouped in the following order:



                        Standard library imports.
                        Related third party imports.
                        Local application/library specific imports.


                        You should put a blank line between each group of imports.




                        Code Organization: Constants



                        You have a bunch of "constants" defined. They're all-caps, which is good. They're declared together and at the top of the file, which is good. But they really shouldn't be global constants.



                        For example, you have a Ball class. Yet there are global constants named BALL_COLOR and BALL_OUTLINE_COLOR and BALL_RADIUS. Why is that? If they're related to your class, make them class constants.



                        class Ball:
                        BODY_COLOR = (255, 255, 255)
                        OUTLINE_COLOR = (255, 0, 0)
                        RADIUS = 10


                        Code Organization: Types



                        In the same vein, you make a lot of use of tuples. But you just create them in-line and rely on convention to access them. Why not go ahead and use a collections.namedtuple or even two?



                        import collections

                        Size = collections.namedtuple('Size', 'width height')
                        Position = collections.namedtuple('Position', 'x y')

                        WINDOW_SIZE = Size(width=1500, height=800)
                        START_POS = Position(x=0.5 * WINDOW_SIZE.width, y=0.99 * WINDOW_SIZE.height)


                        Code Organization: Functions



                        You have a lot of stuff at module scope. Sooner or later you'll want to either write a unit test, or run the debugger, or load your code into the command-line Python REPL. All of this is made easier if you move the module-scope statements into a main function, or some other-named function.



                        def main():
                        pg.init()
                        pg.display.set_caption('Golf')
                        ... etc ...


                        You have a set of font/color variables that you create at module scope. There aren't currently enough drawing functions to create a Window class or anything, but you might consider putting them into a Config class. (And using snake_case names.)



                        Also, you have a lot of pygame boilerplate mixed in with your game logic. I'd suggest separating the boilerplate into separate functions, something like:



                        while still_playing:
                        handle_events()
                        update()
                        render() # You call this "draw_window()" which is fine.


                        Most of your logic, of course, will be in update(). In fact, since it mostly has to do with updating the position of the Ball object, it should mostly be in a call to ball.update_position(delay) (or some such name).



                        You make use of a pair of temporaries x and y, but it seems like you could replace those with an old-position attribute on the Ball, or a second Ball object, or something.






                        share|improve this answer









                        $endgroup$















                          0












                          0








                          0





                          $begingroup$

                          Some of this is nit-pickery, some is more fundamental:



                          Import Order



                          PEP-8 suggests an ordering to imports. No reason not to use it:




                          Imports should be grouped in the following order:



                          Standard library imports.
                          Related third party imports.
                          Local application/library specific imports.


                          You should put a blank line between each group of imports.




                          Code Organization: Constants



                          You have a bunch of "constants" defined. They're all-caps, which is good. They're declared together and at the top of the file, which is good. But they really shouldn't be global constants.



                          For example, you have a Ball class. Yet there are global constants named BALL_COLOR and BALL_OUTLINE_COLOR and BALL_RADIUS. Why is that? If they're related to your class, make them class constants.



                          class Ball:
                          BODY_COLOR = (255, 255, 255)
                          OUTLINE_COLOR = (255, 0, 0)
                          RADIUS = 10


                          Code Organization: Types



                          In the same vein, you make a lot of use of tuples. But you just create them in-line and rely on convention to access them. Why not go ahead and use a collections.namedtuple or even two?



                          import collections

                          Size = collections.namedtuple('Size', 'width height')
                          Position = collections.namedtuple('Position', 'x y')

                          WINDOW_SIZE = Size(width=1500, height=800)
                          START_POS = Position(x=0.5 * WINDOW_SIZE.width, y=0.99 * WINDOW_SIZE.height)


                          Code Organization: Functions



                          You have a lot of stuff at module scope. Sooner or later you'll want to either write a unit test, or run the debugger, or load your code into the command-line Python REPL. All of this is made easier if you move the module-scope statements into a main function, or some other-named function.



                          def main():
                          pg.init()
                          pg.display.set_caption('Golf')
                          ... etc ...


                          You have a set of font/color variables that you create at module scope. There aren't currently enough drawing functions to create a Window class or anything, but you might consider putting them into a Config class. (And using snake_case names.)



                          Also, you have a lot of pygame boilerplate mixed in with your game logic. I'd suggest separating the boilerplate into separate functions, something like:



                          while still_playing:
                          handle_events()
                          update()
                          render() # You call this "draw_window()" which is fine.


                          Most of your logic, of course, will be in update(). In fact, since it mostly has to do with updating the position of the Ball object, it should mostly be in a call to ball.update_position(delay) (or some such name).



                          You make use of a pair of temporaries x and y, but it seems like you could replace those with an old-position attribute on the Ball, or a second Ball object, or something.






                          share|improve this answer









                          $endgroup$



                          Some of this is nit-pickery, some is more fundamental:



                          Import Order



                          PEP-8 suggests an ordering to imports. No reason not to use it:




                          Imports should be grouped in the following order:



                          Standard library imports.
                          Related third party imports.
                          Local application/library specific imports.


                          You should put a blank line between each group of imports.




                          Code Organization: Constants



                          You have a bunch of "constants" defined. They're all-caps, which is good. They're declared together and at the top of the file, which is good. But they really shouldn't be global constants.



                          For example, you have a Ball class. Yet there are global constants named BALL_COLOR and BALL_OUTLINE_COLOR and BALL_RADIUS. Why is that? If they're related to your class, make them class constants.



                          class Ball:
                          BODY_COLOR = (255, 255, 255)
                          OUTLINE_COLOR = (255, 0, 0)
                          RADIUS = 10


                          Code Organization: Types



                          In the same vein, you make a lot of use of tuples. But you just create them in-line and rely on convention to access them. Why not go ahead and use a collections.namedtuple or even two?



                          import collections

                          Size = collections.namedtuple('Size', 'width height')
                          Position = collections.namedtuple('Position', 'x y')

                          WINDOW_SIZE = Size(width=1500, height=800)
                          START_POS = Position(x=0.5 * WINDOW_SIZE.width, y=0.99 * WINDOW_SIZE.height)


                          Code Organization: Functions



                          You have a lot of stuff at module scope. Sooner or later you'll want to either write a unit test, or run the debugger, or load your code into the command-line Python REPL. All of this is made easier if you move the module-scope statements into a main function, or some other-named function.



                          def main():
                          pg.init()
                          pg.display.set_caption('Golf')
                          ... etc ...


                          You have a set of font/color variables that you create at module scope. There aren't currently enough drawing functions to create a Window class or anything, but you might consider putting them into a Config class. (And using snake_case names.)



                          Also, you have a lot of pygame boilerplate mixed in with your game logic. I'd suggest separating the boilerplate into separate functions, something like:



                          while still_playing:
                          handle_events()
                          update()
                          render() # You call this "draw_window()" which is fine.


                          Most of your logic, of course, will be in update(). In fact, since it mostly has to do with updating the position of the Ball object, it should mostly be in a call to ball.update_position(delay) (or some such name).



                          You make use of a pair of temporaries x and y, but it seems like you could replace those with an old-position attribute on the Ball, or a second Ball object, or something.







                          share|improve this answer












                          share|improve this answer



                          share|improve this answer










                          answered 11 mins ago









                          Austin HastingsAustin Hastings

                          7,3621233




                          7,3621233



























                              draft saved

                              draft discarded
















































                              Thanks for contributing an answer to Code Review Stack Exchange!


                              • Please be sure to answer the question. Provide details and share your research!

                              But avoid


                              • Asking for help, clarification, or responding to other answers.

                              • Making statements based on opinion; back them up with references or personal experience.

                              Use MathJax to format equations. MathJax reference.


                              To learn more, see our tips on writing great answers.




                              draft saved


                              draft discarded














                              StackExchange.ready(
                              function ()
                              StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f216199%2fgolf-game-boilerplate%23new-answer', 'question_page');

                              );

                              Post as a guest















                              Required, but never shown





















































                              Required, but never shown














                              Required, but never shown












                              Required, but never shown







                              Required, but never shown

































                              Required, but never shown














                              Required, but never shown












                              Required, but never shown







                              Required, but never shown







                              Popular posts from this blog

                              Can not update quote_id field of “quote_item” table magento 2Magento 2.1 - We can't remove the item. (Shopping Cart doesnt allow us to remove items before becomes empty)Add value for custom quote item attribute using REST apiREST API endpoint v1/carts/cartId/items always returns error messageCorrect way to save entries to databaseHow to remove all associated quote objects of a customer completelyMagento 2 - Save value from custom input field to quote_itemGet quote_item data using quote id and product id filter in Magento 2How to set additional data to quote_item table from controller in Magento 2?What is the purpose of additional_data column in quote_item table in magento2Set Custom Price to Quote item magento2 from controller

                              How to solve knockout JS error in Magento 2 Planned maintenance scheduled April 23, 2019 at 23:30 UTC (7:30pm US/Eastern) Announcing the arrival of Valued Associate #679: Cesar Manara Unicorn Meta Zoo #1: Why another podcast?(Magento2) knockout.js:3012 Uncaught ReferenceError: Unable to process bindingUnable to process binding Knockout.js magento 2Cannot read property `scopeLabel` of undefined on Product Detail PageCan't get Customer Data on frontend in Magento 2Magento2 Order Summary - unable to process bindingKO templates are not loading in Magento 2.1 applicationgetting knockout js error magento 2Product grid not load -— Unable to process binding Knockout.js magento 2Product form not loaded in magento2Uncaught ReferenceError: Unable to process binding “if: function()return (isShowLegend()) ” magento 2

                              Nissan Patrol Зміст Перше покоління — 4W60 (1951-1960) | Друге покоління — 60 series (1960-1980) | Третє покоління (1980–2002) | Четверте покоління — Y60 (1987–1998) | П'яте покоління — Y61 (1997–2013) | Шосте покоління — Y62 (2010- ) | Посилання | Зноски | Навігаційне менюОфіційний український сайтТест-драйв Nissan Patrol 2010 7-го поколінняNissan PatrolКак мы тестировали Nissan Patrol 2016рвиправивши або дописавши її