OBAQで「ニュートンのゆりかご」

調整が良くないのか長く続きません。

調整が良くないのか長く続きません。

;
;	OBAQ 「ニュートンのゆりかご」
;
;	スペースキーで動かし始める。
;	調整がうまく行っていないのか途中でバラバラになってしまいます。
;
#include "obaq.as"

;内積
#define global ctype DotProduct2D(%1,%2,%3,%4) (double(%1)*(%3) + double(%2)*(%4))


#module
;	振り子	pendulum
;	num      : オブジェクトID
;	x,y      : アンカー座標
;	distance : 距離
;	const_k  : バネ定数
;	damping  : 減衰
#deffunc qAttach int p_num, double p_x, double p_y, double p_distance, double p_const_k, double p_damping
	qgetreq@ rpr, REQ_PHYSICS_RATE	; 1フレームあたりの物理計算回数

	;	オブジェクトの状態を取得
	qgetpos@    p_num, hx1, hy1, hr1
	qgetspeed@  p_num, vx, vy, vr
	qgetweight@ p_num, weiht, mt

	;	オブジェクトからアンカーまでの距離ベクトル
	dx = p_x - hx1
	dy = p_y - hy1
	;cos	-(dx,dy)と(vx,vy)とがなす角のcos値
	dd = sqrt(dx*dx + dy*dy)
	vv = sqrt(vx*vx + vy*vy)
	if (dd=0.0) | (vv=0.0) {
		c = 1.0
	} else {
		c = DotProduct2D( vx, vy, -dx, -dy ) / vv / dd
	}
	;梁正規化
	ix = dx / dd
	iy = dy / dd


	;	減衰
	v = vv * c
	bvx = ix * -v
	bvy = iy * -v
	cvx = 0.0
	cvy = 0.0
	if bvx>0 {
		cvx = -p_damping
		if (bvx - p_damping)<0 : cvx = -bvx
	} else {
		if bvx<0 {
			cvx = p_damping
			if (bvx + p_damping)>0 : cvx = -bvx
		}
	}
	if bvy>0 {
		cvy = -p_damping
		if (bvy - p_damping)<0 : cvy = -bvy
	} else {
		if bvy<0 {
			cvy = p_damping
			if (bvy + p_damping)>0 : cvy = -bvy
		}
	}


	;	バネ
	;バネの伸び
	dl = sqrt(dx*dx + dy*dy) - p_distance
	; a = x * k / m
	vx = ix * dl * p_const_k / weiht
	vy = iy * dl * p_const_k / weiht
	vx *= rpr	;加速度を速度に置き換え
	vy *= rpr
	qspeed@ p_num, vx + cvx, vy + cvy, 0.0


	return

#global

	qreset			; OBAQの初期化

	;	オブジェクト配置
	dim myball, 5
	repeat 5
		qaddpoly myball(cnt), 100, 60.0+10.0*cnt, 60.0, 0, 5.0,5.0, 0
		qweight  myball(cnt), 6.0
		qdamper  myball(cnt), 0.0, 0.0
		qinertia myball(cnt), 1.0
		qtype    myball(cnt), 0x100
	loop


	
	;----------
	;	梁
	;----------
	; 硬いバネと大きな減衰で梁を表現します。
	
	; 梁長さ
	lg = 30.0

	; バネ定数
	; 値が小さいほどバネが柔らかく、よく伸びるようになります。
	;k = 0.01
	k = 0.4
	
	; 減衰
	; 値が大きいほど振動が速く収まります。
	;cv = 0.0001
	cv = 0.2


	;----------
	;	環境
	;----------
	qgravity 0, 0.005
	
	
;	メインループ
qgetpos mybox, px,py,pr
*main
	redraw 0		; 画面の更新を開始
	color 0,0,0:boxf	; 画面をクリア
	qexec			; OBAQによるオブジェクトの更新

	;	最初に動かす
	stick key
	if key&16 : qspeed myball(0), -0.5
	color 255,255,255
	pos 50,50
	mes "スペースキーを押してください。"
	

	;----------
	;	振り子
	;----------
	repeat 5
		qAttach myball(cnt), 60.0+10.0*cnt, 30.0, lg, k, cv
	loop

	;	紐を描画
	color 255,255,255
	repeat 5
		qgetpos myball(cnt), px,py,pa
		qcnvaxis lpx, lpy, px, py, 0
		x = 60.0+10.0*cnt
		y = 30.0
		qcnvaxis lx, ly, x, y, 0
		line lx, ly, lpx, lpy
	loop


	qdraw			; オブジェクトの描画
	redraw 1		; 画面の更新を終了
	await 12		; 一定時間待つ
	goto *main