Last active
December 20, 2015 12:39
-
-
Save mmurdoch/6133047 to your computer and use it in GitHub Desktop.
Circle Bounce
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-- Copyright Matthew Murdoch | |
-- Remix under the terms of the MIT license (see http://opensource.org/licenses/MIT) | |
Point = class() | |
function Point:init(x, y) | |
self._x = x | |
self._y = y | |
end | |
function Point:x() | |
return self._x | |
end | |
function Point:set_x(x) | |
self._x = x | |
end | |
function Point:y() | |
return self._y | |
end | |
function Point:set_y(y) | |
self._y = y | |
end | |
Size = class() | |
function Size:init(width, height) | |
self._width = width | |
self._height = height | |
end | |
function Size:width() | |
return self._width | |
end | |
function Size:height() | |
return self._height | |
end | |
Velocity = class() | |
function Velocity:init(dx, dy) | |
self._dx = dx | |
self._dy = dy | |
end | |
function Velocity:dx() | |
return self._dx | |
end | |
function Velocity:dy() | |
return self._dy | |
end | |
function Velocity:bounce_off_vertical() | |
self._dx = -self._dx | |
end | |
function Velocity:bounce_off_horizontal() | |
self._dy = -self._dy | |
end | |
Rectangle = class() | |
function Rectangle:init(bottom_left, size) | |
self._bottom_left = bottom_left | |
self._size = size | |
self._fill_color = color(0, 0, 0) | |
end | |
function Rectangle:center() | |
return Point(self:left() + self:width()/2, self:bottom() + self:height()/2) | |
end | |
function Rectangle:left() | |
return self._bottom_left:x() | |
end | |
function Rectangle:right() | |
return self._bottom_left:x() + self:width() | |
end | |
function Rectangle:top() | |
return self._bottom_left:y() + self:height() | |
end | |
function Rectangle:bottom() | |
return self._bottom_left:y() | |
end | |
function Rectangle:width() | |
return self._size:width() | |
end | |
function Rectangle:height() | |
return self._size:height() | |
end | |
function Rectangle:fill_color() | |
return self._fill_color | |
end | |
function Rectangle:set_fill_color(fill_color) | |
self._fill_color = fill_color | |
end | |
function Rectangle:contains(point) | |
if point:x() > self:left() and point:x() < self:right() and | |
point:y() > self:bottom() and point:y() < self:top() then | |
return true | |
end | |
return false | |
end | |
-- Shrinks the rectangle by an equal amount on each side. | |
-- | |
-- by: the amount by which to shrink each side | |
function Rectangle:shrink(by) | |
return Rectangle(Point(self:left()+by, self:bottom()+by), | |
Size(self:width()-2*by, self:height()-2*by)) | |
end | |
function Rectangle:draw() | |
fill(self:fill_color().r, self:fill_color().g, self:fill_color().b) | |
rect(self:left(), self:bottom(), self:width(), self:height()) | |
end | |
Circle = class() | |
function Circle:init(center, radius) | |
self._center = center | |
self._radius = radius | |
self._fill_color = color(0, 0, 0) | |
self._velocity = Velocity(0, 0) | |
end | |
function Circle:center() | |
return self._center | |
end | |
function Circle:radius() | |
return self._radius | |
end | |
function Circle:left() | |
return self:center():x() - self:radius() | |
end | |
function Circle:right() | |
return self:center():x() + self:radius() | |
end | |
function Circle:top() | |
return self:center():y() + self:radius() | |
end | |
function Circle:bottom() | |
return self:center():y() - self:radius() | |
end | |
function Circle:diameter() | |
return 2 * self:radius() | |
end | |
function Circle:velocity() | |
return self._velocity | |
end | |
function Circle:set_velocity(velocity) | |
self._velocity = velocity | |
end | |
function Circle:fill_color() | |
return self._fill_color | |
end | |
function Circle:set_fill_color(fill_color) | |
self._fill_color = fill_color | |
end | |
function Circle:move(bounds) | |
self:center():set_x(self:center():x() + self:velocity():dx()) | |
if self:left() < bounds:left() then | |
self:center():set_x(self:center():x() + bounds:left() - self:left()) | |
self:velocity():bounce_off_vertical() | |
elseif self:right() > bounds:right() then | |
self:center():set_x(self:center():x() + bounds:right() - self:right()) | |
self:velocity():bounce_off_vertical() | |
end | |
self:center():set_y(self:center():y() + self:velocity():dy()) | |
if self:bottom() < bounds:bottom() then | |
self:center():set_y(self:center():y() + bounds:bottom() - self:bottom()) | |
self:velocity():bounce_off_horizontal() | |
elseif self:top() > bounds:top() then | |
self:center():set_y(self:center():y() + bounds:top() - self:top()) | |
self:velocity():bounce_off_horizontal() | |
end | |
end | |
function Circle:draw() | |
fill(self:fill_color().r, self:fill_color().g, self:fill_color().b) | |
ellipse(self:center():x(), self:center():y(), self:diameter(), self:diameter()) | |
end | |
CircleBounce = class() | |
function CircleBounce:init() | |
self._circles = {} | |
self._box = nil | |
end | |
function CircleBounce:box() | |
if self._box == nil then | |
local screen = Rectangle(Point(0, 0), Size(WIDTH, HEIGHT)) | |
self._box = screen:shrink(100) | |
self._box:set_fill_color(color(128, 64, 0)) | |
end | |
return self._box | |
end | |
function CircleBounce:draw() | |
self:box():draw() | |
for _, circle in ipairs(self._circles) do | |
circle:move(self:box()) | |
circle:draw() | |
end | |
end | |
function CircleBounce:touch_began(touch) | |
local touch_location = Point(touch.x, touch.y) | |
if self:box():contains(touch_location) then | |
local center = touch_location | |
local radius = math.random(5, 50) | |
local circle = Circle(center, radius) | |
local max_speed = 15 | |
local random_dx = math.random(-max_speed, max_speed) | |
local random_dy = math.random(-max_speed, max_speed) | |
local random_velocity = Velocity(random_dx, random_dy) | |
local random_color = color(math.random(0, 255), math.random(0, 255), math.random(0, 255)) | |
circle:set_fill_color(random_color) | |
circle:set_velocity(random_velocity) | |
table.insert(self._circles, circle) | |
end | |
end | |
displayMode(FULLSCREEN) | |
circle_bounce = CircleBounce() | |
function draw() | |
circle_bounce:draw() | |
end | |
function touched(touch) | |
if touch.state == BEGAN then | |
circle_bounce:touch_began(touch) | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment