Skip to content
This repository has been archived by the owner on Aug 24, 2018. It is now read-only.

Zach Campbell #66

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
202 changes: 170 additions & 32 deletions src/ball.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,61 +2,199 @@

from pygame.math import Vector2


class Ball:
"""
base class for bouncing objects
"""

def __init__(self, bounds, position, velocity, color, radius):
self.position = position
self.velocity = velocity
self.bounds = bounds
self.color = color
self.radius = radius
self.mass = (4 / 3) * math.pi * radius ** 3

def update(self):
# bounce at edges. TODO: Fix sticky edges
if self.position.x < 0 + self.radius or self.position.x > self.bounds[0] - self.radius: # screen width
# bounce at edges.
# screen width
next_pos = self.position + self.velocity
x_left_edge_next = next_pos.x < 0 + self.radius
x_right_edge_next = next_pos.x > self.bounds[0] - self.radius
y_top_edge_next = next_pos.y < 0 + self.radius
y_bottom_edge_next = next_pos.y > self.bounds[1] - self.radius

if self.velocity.length() > 20:
self.velocity = self.velocity.normalize() * 20

if x_left_edge_next:
self.position.x = self.radius * 2 - next_pos.x
self.velocity.x *= -1
if self.position.y < 0 + self.radius or self.position.y > self.bounds[1] - self.radius: # screen height
elif x_right_edge_next:
self.position.x = (self.bounds[0] - self.radius) * 2 - next_pos.x
self.velocity.x *= -1
else:
self.position.x += self.velocity.x
if y_top_edge_next:
self.position.y = self.radius * 2 - next_pos.y
self.velocity.y *= -1
elif y_bottom_edge_next:
self.position.y = (self.bounds[1] - self.radius) * 2 - next_pos.y
self.velocity.y *= -1
self.position += self.velocity
else:
self.position.y += self.velocity.y




def draw(self, screen, pygame):
# cast x and y to int for drawing
pygame.draw.circle(screen, self.color, [int(self.position.x), int(self.position.y)], self.radius)
pygame.draw.circle(
screen,
self.color,
[int(self.position.x), int(self.position.y)],
self.radius,
)

# class BouncingBall(???):
# """
# ball effected by gravity
# """
# # TODO:

# class RainbowBall(???):
# """
# Ball that changes colors
# """
# # TODO:
class FrictionBall(Ball):
def update(self):
self.velocity *= .99
super().update()

# class BouncingRainbow(???):
# """
# Ball that changes color and is affected by gravity
# """
# # TODO:

# class KineticBall(???):
# """
# A ball that collides with other collidable balls using simple elastic circle collision
# """
# # TODO:
class BouncingBall(Ball):
"""
ball effected by gravity
"""

def update(self):
next_pos = self.position + self.velocity
if (
self.position.y > self.bounds[1] - self.radius * 1.01
and abs(self.velocity.y) < self.radius / 32
):
self.position.y = self.bounds[1] - self.radius
self.velocity.y = 0
elif not (
next_pos.y >= self.bounds[1] - self.radius and self.velocity.y < self.radius
):
self.velocity.y += .98
super().update()


class RainbowBall(Ball):
"""
Ball that changes colors
"""

def update(self):
self.color[0] = (self.color[0] + 1) % 256
self.color[1] = (self.color[1] + 3) % 256
self.color[2] = (self.color[2] + 5) % 256
super().update()


class BouncingRainbow(FrictionBall, BouncingBall, RainbowBall):
"""
Ball that changes color and is affected by gravity and friction
"""

def update(self):
FrictionBall.update(self)
BouncingBall.update(self)
RainbowBall.update(self)


class KineticBall(Ball):
"""
A ball that collides with other collidable balls using simple elastic
circle collision
"""

def __init__(self, bounds, position, velocity, color, radius, other_shapes):
self.other_shapes = [
shape for shape in other_shapes if hasattr(shape, "radius")
]
super().__init__(bounds, position, velocity, color, radius)

def update(self):
for shape in self.other_shapes:
if shape == self:
continue
initial_dist = self.position - shape.position
v_diff = self.velocity - shape.velocity

product = initial_dist * v_diff
s_diff = v_diff * v_diff
if s_diff == 0:
continue
s_dist = initial_dist * initial_dist
radii = self.radius + shape.radius
t = (
product * -1 - (product ** 2 - (s_diff) * (s_dist - radii ** 2)) ** .5
) / (s_diff)
if not isinstance(t, complex) and (t >= 0 and t < 1):
self.position = self.position + self.velocity * t
shape.position = shape.position + shape.velocity * t
self_vec = Vector2(self.velocity.x, self.velocity.y)
shape_vec = Vector2(shape.velocity.x, shape.velocity.y)
masses = self.mass + shape.mass

self.velocity -= (
(2 * shape.mass / (masses))
* (
(self_vec - shape_vec).dot(self.position - shape.position)
/ (self.position - shape.position).length_squared()
)
* (self.position - shape.position)
)

shape.velocity -= (
(2 * self.mass / (masses))
* (
(shape_vec - self_vec).dot(shape.position - self.position)
/ (shape.position - self.position).length_squared()
)
* (shape.position - self.position)
)

self.position = self.position + self.velocity * (1 - t)
shape.position = shape.position + shape.velocity * (1 - t)

super().update()


class KineticBouncing(BouncingBall, KineticBall):
"""
A ball that collides with other collidable balls using simple elastic
circle collision
And is affected by gravity
"""

def update(self):
BouncingBall.update(self)
KineticBall.update(self)


class Planet(KineticBall):
def __init__(self, bounds, position, velocity, color, radius, other_shapes):
super().__init__(bounds, position, velocity, color, radius, other_shapes)

def update(self):

for shape in self.other_shapes:
distance = self.position.distance_to(shape.position)
grav_power = 5 * (self.mass * shape.mass) / distance ** 2

grav_direction = (self.position - shape.position).normalize()
shape.velocity += (grav_power * grav_direction) / self.mass
self.velocity = self.velocity * .9
super().update()

# class KineticBouncing(???):
# """
# A ball that collides with other collidable balls using simple elastic circle collision
# And is affected by gravity
# """


# class AllTheThings(???):
# """
# A ball that does everything!
# """
# """
18 changes: 10 additions & 8 deletions src/block.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import pygame
import random

from pygame.math import Vector2
from pygame import Rect
# import random
#
# from pygame.math import Vector2
# from pygame import Rect


class Block:
"""
Expand All @@ -21,11 +23,11 @@ def update(self):
pass

def set_rectangle(self, position, width, height):
# Creates a rectangle of the given width and height centered at the x/y coordinates
return pygame.Rect(position.x - (width/2),
position.y - (height/2),
width,
height)
# Creates a rectangle of the given width and height centered at the x/y
# coordinates
return pygame.Rect(
position.x - (width / 2), position.y - (height / 2), width, height
)

def draw(self, screen, pygame):
pygame.draw.rect(screen, self.color, self.rectangle)
81 changes: 56 additions & 25 deletions src/draw.py
Original file line number Diff line number Diff line change
@@ -1,60 +1,91 @@
import pygame #TODO: Fix intellisense
import random
import pygame # TODO: Fix intellisense

# import random

from pygame.math import Vector2

from ball import *
from block import *
from ball import (
Ball,
RainbowBall,
BouncingBall,
BouncingRainbow,
KineticBall,
KineticBouncing,
FrictionBall,
Planet,
)

SCREEN_SIZE = [640, 480]
BACKGROUND_COLOR = [255, 255, 255]


def debug_create_balls(object_list):
ball = Ball(SCREEN_SIZE, Vector2(50, 50), Vector2(3, 3), [255, 0, 0], 10)
ball = Ball(SCREEN_SIZE, Vector2(90, 100), Vector2(-5, -5), [255, 0, 0], 6)
object_list.append(ball)
# ball = RainbowBall(SCREEN_SIZE, Vector2(25, 25), Vector2(3, 2), [0, 255, 0], 10)
# object_list.append(ball)
# ball = BouncingBall(SCREEN_SIZE, Vector2(500, 20), Vector2(10, 4), [0, 255, 0], 15)
# object_list.append(ball)
# ball = FrictionBall(SCREEN_SIZE, Vector2(500, 20), Vector2(10, 4), [0, 0, 0], 3)
# object_list.append(ball)
# ball = BouncingRainbow(
# SCREEN_SIZE, Vector2(100, 300), Vector2(0, 2), [0, 255, 0], 15
# )
# object_list.append(ball)
# ball = KineticBall(
# SCREEN_SIZE, Vector2(200, 200), Vector2(3, 0), [0, 255, 255], 15, object_list
# )
# object_list.append(ball)
# ball = KineticBouncing(
# SCREEN_SIZE, Vector2(23, 15), Vector2(-5, 3), [122, 122, 122], 10, object_list
# )
# object_list.append(ball)
ball = Ball(SCREEN_SIZE, Vector2(400, 100), Vector2(5, 5), [60, 60, 60], 6)
object_list.append(ball)
ball = Planet(
SCREEN_SIZE, Vector2(320, 240), Vector2(0, 0), [60, 60, 60], 70, object_list
)
object_list.append(ball)

# TODO: Create other ball types for testing

def debug_create_blocks(object_list):
block = Block(SCREEN_SIZE, Vector2(100,100), 20, 20, [0,255,0])
object_list.extend((block, ))



def main():
pygame.init()
screen = pygame.display.set_mode(SCREEN_SIZE)

# Used to manage how fast the screen updates
clock = pygame.time.Clock()
object_list = [] # list of objects of all types in the toy

object_list = [] # list of objects of all types in the toy

debug_create_balls(object_list)
debug_create_blocks(object_list)

while True: # TODO: Create more elegant condition for loop

while True: # TODO: Create more elegant condition for loop
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
# Logic Loop
for event in pygame.event.get():
if event.type == pygame.KEYDOWN: #TODO: Get working
if event.type == pygame.KEYDOWN: # TODO: Get working
if event.key == pygame.K_SPACE:
# TODO: Add behavior when button pressed
pass

for ball in object_list:
ball.update()
for shape in object_list:
shape.update()

# Draw Loop
screen.fill(BACKGROUND_COLOR)
for ball in object_list:
ball.draw(screen, pygame)
for shape in object_list:
shape.draw(screen, pygame)

clock.tick(60)
pygame.display.flip()

# Close everything down
pygame.quit()



if __name__ == "__main__":
main()