Skip to content

Instantly share code, notes, and snippets.

@mirichi
Last active December 26, 2015 14:19
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 mirichi/3672a136c62d0faab4da to your computer and use it in GitHub Desktop.
Save mirichi/3672a136c62d0faab4da to your computer and use it in GitHub Desktop.
Chipmunkらくらくラッパ
require 'chipmunk'
require 'dxruby'
# Chipmunkラッパ(DXRuby1.5dev用)
module CP
TO_RAD = Math::PI / 180.0
TO_DEG = 180.0 / Math::PI
class Vec2
ZERO = Vec2.new(0,0)
end
end
class CPSprite < Sprite
attr_accessor :body, :shape, :param
### param
# x(sprite)
# y(sprite)
# image(sprite)
# collision(sprite)
# rotatable(body)
# static(body)
# mass(body)
# elasticity(shape)
# friction(shape)
# layers(shape)
def initialize(param)
param[:x] ||= 0
param[:y] ||= 0
image = param[:image]
param[:elasticity] ||= 0.5
param[:friction] ||= 0.9
param[:static] ||= false
param[:mass] ||= 1
param[:rotatable] ||= true
param[:offset_sync] ||= false
param[:layers] ||= CP::ALL_LAYERS
super(param[:x], param[:y], param[:image])
@param = param
self.collision = param[:collision]
end
end
class CPSpace
attr_reader :sprites, :space, :static_sprite, :constraints
def initialize(g)
@space = CP::Space.new
@space.gravity = CP::Vec2.new(0, g)
@sprites = []
@constraints = []
# Rubyバインダにはなぜか実装されていないのでStaticBodyを自前で用意する
@static_sprite = CPSprite.new({})
self.add_static_sprite(@static_sprite)
end
def add_static_sprite(sprite)
# マウスジョイントなどの見えない固定用オブジェクトを登録する
sprite.body = CP::Body.new_static
sprite.body.p = CP::Vec2.new(sprite.x, sprite.y)
@sprites.push(sprite)
sprite.param[:static] = true
return
end
def add(sprite)
mass = sprite.param[:mass]
rotatable = sprite.param[:rotatable]
col = sprite.collision
static = sprite.param[:static]
offset_sync = sprite.param[:offset_sync]
if col
case col.size
when 3
moment = rotatable ? CP::moment_for_circle(mass, 0, col[2], CP::Vec2::ZERO) : CP::INFINITY
when 4
x1 = col[0] - sprite.center_x
y1 = col[1] - sprite.center_y
x2 = col[2] - sprite.center_x
y2 = col[3] - sprite.center_y
verts = [CP::Vec2.new(x1, y1), CP::Vec2.new(x1, y2), CP::Vec2.new(x2, y2), CP::Vec2.new(x2, y1)]
moment = rotatable ? CP::moment_for_poly(mass, verts, CP::Vec2::ZERO) : CP::INFINITY
when 6
x1 = col[0] - sprite.center_x
y1 = col[1] - sprite.center_y
x2 = col[2] - sprite.center_x
y2 = col[3] - sprite.center_y
x3 = col[4] - sprite.center_x
y3 = col[5] - sprite.center_y
verts = [CP::Vec2.new(x1, y1), CP::Vec2.new(x3, y3), CP::Vec2.new(x2, y2)]
moment = rotatable ? CP::moment_for_poly(mass, verts, CP::Vec2::ZERO) : CP::INFINITY
else
raise
end
else
x1 = -sprite.image.width / 2
y1 = -sprite.image.height / 2
x2 = sprite.image.width / 2
y2 = sprite.image.height / 2
verts = [CP::Vec2.new(x1, y1), CP::Vec2.new(x1, y2), CP::Vec2.new(x2, y2), CP::Vec2.new(x2, y1)]
moment = rotatable ? CP::moment_for_poly(mass, verts, CP::Vec2::ZERO) : CP::INFINITY
end
sprite.body = static ? CP::Body.new_static : CP::Body.new(mass, moment)
if offset_sync
sprite.body.p = CP::Vec2.new(sprite.x, sprite.y)
sprite.offset_sync = true
else
sprite.body.p = CP::Vec2.new(sprite.x + sprite.center_x, sprite.y + sprite.center_y)
sprite.offset_sync = false
end
sprite.body.a = sprite.angle * CP::TO_RAD
sprite.body.v = CP::Vec2::ZERO
if col
case col.size
when 3
sprite.shape = CP::Shape::Circle.new(sprite.body, col[2], CP::Vec2.new(0,0))
else
sprite.shape = CP::Shape::Poly.new(sprite.body, verts, CP::Vec2::ZERO)
end
else
sprite.shape = CP::Shape::Poly.new(sprite.body, verts, CP::Vec2::ZERO)
end
sprite.shape.e = sprite.param[:elasticity]
sprite.shape.u = sprite.param[:friction]
sprite.shape.layers = sprite.param[:layers]
if static
@space.add_static_shape(sprite.shape)
else
@space.add_body(sprite.body)
@space.add_shape(sprite.shape)
end
sprite.body.object = sprite
sprite.shape.object = sprite
@sprites.push(sprite)
end
def add_constraint(*a)
@space.add_constraint(*a)
@constraints.concat(a)
end
def step(dt)
@space.step(dt)
@sprites.each do |s|
if !s.param[:static]
if s.offset_sync
s.x = s.body.p.x
s.y = s.body.p.y
else
s.x = s.body.p.x - s.center_x
s.y = s.body.p.y - s.center_y
end
s.angle = s.body.a * CP::TO_DEG
end
s.update
end
end
def remove_sprite(spr)
@space.remove_body(spr.body)
@space.remove_shape(spr.shape)
@sprites.delete(spr)
end
def remove_constraint(c)
@space.remove_constraint(c)
@constraints.delete(c)
end
def draw
Sprite.draw @sprites
Sprite.draw @constraints
end
end
class CPPivotJoint < CP::Constraint::PivotJoint
@@image = Image.new(5, 5, [0, 200, 0])
def draw
tmp_a = Vector.new(body_a.p.x, body_a.p.y) + Vector.new(anchr1.x, anchr1.y).rotate(body_a.a*CP::TO_DEG)
Window.draw(tmp_a.x - 2, tmp_a.y - 2, @@image, 100)
tmp_b = Vector.new(body_b.p.x, body_b.p.y) + Vector.new(anchr2.x, anchr2.y).rotate(body_b.a*CP::TO_DEG)
Window.draw(tmp_b.x - 2, tmp_b.y - 2, @@image, 100)
Window.draw_line(tmp_a.x, tmp_a.y, tmp_b.x, tmp_b.y, [0, 200, 0], 100)
end
end
# ここからメイン
Window.bgcolor = [128, 128, 128]
# 画像作成
image_circle = Image.new(20, 20).circle_fill(10, 10, 10, [120, 120, 255]).circle(10, 10, 10, C_BLACK).line(0, 10, 9, 10, C_BLACK)
image_box = Image.new(20, 20, [255, 120, 120]).box(0, 0, 19, 19, C_BLACK)
image_triangle = Image.new(20, 20).triangle_fill(10, 0, 19, 19, 0, 19, [120, 255, 120]).triangle(10, 0, 19, 19, 0, 19, C_BLACK)
# space作成
space = CPSpace.new(300)
# 床
floor = CPSprite.new(x:120, y:400, image:Image.new(400, 20, C_BLACK).box_fill(1, 1, 398, 18, C_WHITE), static:true)
space.add(floor)
# 床は中心を軸に回るが落ちないようにStaticSpriteとつなげておく
#space.add_constraint(CPPivotJoint.new(space.static_sprite.body, floor.body, CP::Vec2.new(320, 410), CP::Vec2::ZERO))
# 床とStaticSpriteをモーターでつなぐ
#space.add_constraint(CP::Constraint::SimpleMotor.new(space.static_sprite.body, floor.body, -0.0))
# □
100.times do
spr = CPSprite.new(x:rand()*200+180, y:rand()*100, image:image_box)
space.add(spr)
end
# ○
100.times do
spr = CPSprite.new(x:rand()*200+180, y:rand()*100, image:image_circle, collision:[10,10,10])
space.add(spr)
end
# △
100.times do
spr = CPSprite.new(x:rand()*200+180, y:rand()*100, image:image_triangle, collision:[10, 0, 19, 19, 0, 19])
space.add(spr)
end
# 接触点を表示するためのデフォルトハンドラ
contact_image = Image.new(3, 3, C_RED)
space.space.set_default_collision_handler do |a, b, arb|
arb.points.each do |c|
Window.draw(c.point.x - 1, c.point.y - 1, contact_image, 100)
end
true
end
spr = nil
constraint = nil
Window.loop do
break if Input.key_push?(K_ESCAPE)
# マウスでオブジェクトを掴むための処理
pos = CP::Vec2.new(Input.mouse_pos_x, Input.mouse_pos_y)
if Input.mouse_push?(M_LBUTTON)
shape = space.space.point_query_first(pos)
if shape and !shape.object.param[:static]
spr = CPSprite.new(x:pos.x, y:pos.y)
space.add_static_sprite(spr)
tmp = shape.body.world2local(pos)
constraint = CPPivotJoint.new(spr.body, shape.body, CP::Vec2::ZERO, tmp)
constraint.max_force = 50000.0
space.add_constraint(constraint)
end
end
if Input.mouse_down?(M_LBUTTON) and spr
tmp = pos.lerp(spr.body.p, 0.25)
spr.body.v = (tmp - pos) * 60
spr.body.p = tmp
elsif spr
space.remove_sprite(spr)
space.remove_constraint(constraint)
spr = nil
constraint = nil
end
# 全体の動作と描画
space.step(1.0/60.0)
space.draw
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment