-
-
Save mirichi/3672a136c62d0faab4da to your computer and use it in GitHub Desktop.
Chipmunkらくらくラッパ
This file contains 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
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