Skip to content

Instantly share code, notes, and snippets.

@mmurdoch
Last active December 20, 2015 12:39
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mmurdoch/6133047 to your computer and use it in GitHub Desktop.
Save mmurdoch/6133047 to your computer and use it in GitHub Desktop.
Circle Bounce
-- 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