Welcome, guest | Sign In | My Account | Store | Cart

This module gives a simple implementation of the physics behind bouncing balls.

Python, 143 lines
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
'''Module for physics simulation.

This module provides two classes that allow the
approximation of physics behind bouncing balls.'''

################################################################################

__version__ = '$Revision: 0 $'
__date__ = 'February 20, 2007'
__author__ = 'Stephen "Zero" Chappell <my.bios@gmail.com>'
__credits__ = '''\
S. Schaub, for introducing me to programming.
B. Brown, for teaching me some math courses.
C. Parker, for freely providing boids pseudocode.'''

################################################################################

import math as _math
import sys as _sys

################################################################################

class Vector:

    'Vector(x, y) -> Vector'

    def __init__(self, x, y):
        'Initialize the Vector object.'
        self.x = float(x)
        self.y = float(y)

    def __repr__(self):
        'Return the vector\'s representation.'
        return 'Vector(%r, %r)' % (self.x, self.y)

    def __iter__(self):
        'Return an iterator.'
        yield self.x
        yield self.y

    def __add__(self, vector):
        'Return the sum of vector addition.'
        return Vector(self.x + vector.x, self.y + vector.y)

    def __sub__(self, vector):
        'Return the difference of vector subtraction.'
        return Vector(self.x - vector.x, self.y - vector.y)

    def __mul__(self, number):
        'Return the product of vector multiplication.'
        return Vector(self.x * number, self.y * number)

    def __div__(self, number):
        'Return the quotient of vector division.'
        return Vector(self.x / number, self.y / number)

    def __iadd__(self, vector):
        'Execute addition in-place.'
        self.x += vector.x
        self.y += vector.y
        return self

    def __isub__(self, vector):
        'Execute subtraction in-place.'
        self.x -= vector.x
        self.y -= vector.y
        return self

    def __imul__(self, number):
        'Execute multiplication in-place.'
        self.x *= number
        self.y *= number
        return self

    def __idiv__(self, number):
        'Execute division in-place.'
        self.x /= number
        self.y /= number
        return self

    def __abs__(self):
        'Return the vector\'s magnitude.'
        return _math.hypot(self.x, self.y)

    def unit(self):
        'Return the unit vector.'
        return self / abs(self)

################################################################################

class Ball:

    'Ball(x, y, radius) -> Ball'

    def __init__(self, x, y, radius):
        'Initialize the Ball object.'
        self.pos = Vector(x, y)
        self.vel = Vector(0, 0)
        self.err = Vector(0, 0)
        self.rad = radius

    def crash(self, ball):
        'Try to crash two balls together.'
        p = ball.pos - self.pos
        a = abs(p)
        if a <= self.rad + ball.rad:
            v = self.vel - ball.vel
            s = _sub(_ang(p), _ang(v))
            if s < _PI_D_2:
                e =  p * (_math.cos(s) * abs(v) / a)
                ball.err += e
                self.err -= e

    def correct(self):
        'Update the ball\'s velocity.'
        self.vel += self.err
        self.err = Vector(0, 0)

    def move(self, frames_per_second):
        'Update the ball\'s position.'
        self.pos += self.vel / frames_per_second

################################################################################

_PI_M_2 = _math.pi * 2
_PI_D_2 = _math.pi / 2

################################################################################

def _ang(vector):
    'Private module function.'
    return _math.atan2(vector.x, vector.y) % _PI_M_2

def _sub(angle_a, angle_b):
    'Private module function.'
    diff = abs(angle_a - angle_b)
    return _PI_M_2 - diff if diff > _math.pi else diff

################################################################################

if __name__ == '__main__':
    _sys.stdout.write('Content-Type: text/plain\n\n')
    _sys.stdout.write(file(_sys.argv[0]).read())

Please see Kaos Rain (MKv3) for sample usage.