Created
February 4, 2014 17:28
-
-
Save gunungloli666/8808407 to your computer and use it in GitHub Desktop.
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
<html><head> | |
<meta charset="utf-8"> | |
<script src="jquery.js"></script> | |
<script src="js/jquery-ui-1.8.19.custom.min.js"></script> | |
<link rel="stylesheet" href="css/jquery-ui-1.8.19.custom.css"> | |
<script src="ivank.js"></script> | |
<style> | |
#c:active { cursor: pointer; } | |
audio { display: none; } | |
</style> | |
<script> | |
Array.prototype.append = function(arr) { | |
if (!arr) return; | |
for (var i=0; i < arr.length; i++) | |
this.push( arr[i] ); | |
} | |
Array.prototype.last = function() { | |
return this[ this.length-1 ]; | |
} | |
String.prototype.n = function(times) { | |
return (new Array(times + 1)).join(this); | |
} | |
String.prototype.normalizeLength = function(a) { | |
if (this.length > a) return this.substr(0, a); | |
if (this.length < a) return this + " ".n(a-this.length); | |
return this; | |
} | |
function isOk_(f) | |
{ | |
return (!isNaN(f) && isFinite(f)); | |
} | |
function isOk() | |
{ | |
for (var i=0; i < arguments.length; i++) | |
{ | |
var a = arguments[i]; | |
if (typeof a.x != 'undefined') // vector | |
{ | |
if (!isOk(a.x, a.y)) | |
return false; | |
} | |
else | |
{ | |
if (!isOk_(a)) | |
return false; | |
} | |
} | |
return true; | |
} | |
var applyingFns = []; | |
function applyGlobalParamsLocally(fn) | |
{ | |
if (fn) | |
{ | |
applyingFns.push(fn); | |
return; | |
} | |
for (var i=0; i < applyingFns.length; i++) | |
{ | |
var fn = applyingFns[i]; | |
fn(); | |
} | |
} | |
//////////////////////////////////////////////////////////// | |
/* | |
addItems('water', 10) | |
$.each(circles, function(i, e) { if (e.m.name=='dirt') e.setDensity(0) }); | |
*/ | |
var g_nonsphPress = 80000; | |
var g_nonsphPressNear = 80000; | |
var g_sphQ2 = 1; | |
var g_sphQ3 = 3; | |
var g_sphQmult = 1; | |
var g_cellsActive = 0; | |
var DEBUG = true; // makes it much slower | |
var g_lastUsedObj; | |
var g_maxVelLimit = 140000; | |
var g_skipJointCollision = 0; | |
var g_useRK = 1; | |
var g_useRkVel = 1; | |
var g_useRkPos = 1; | |
var g_meldOnlySameMaterial = 0; | |
var g_bMelding = 0; | |
var g_maxLinks = 6; | |
var g_sprK = 10000;//25260; | |
var g_sprDamp = 0; | |
var g_sprMax = 4.4; | |
var g_sprLenRatio = 1.0; | |
var g_b1 = 1; | |
var g_f1 = 1; | |
var g_f2 = 1; | |
var g_f3 = 1; | |
var g_f4 = 1; | |
var g_radius = 14; | |
var g_sphRadius = g_radius*2; | |
var g_sphStiff = 6000; | |
var g_sphStiffNear = 10000; | |
var g_sphRestDensity = 0; | |
var g_spriteScale = 1.0;//g_sphRadius/8; | |
/* encapsulate grid functionality: | |
grid: | |
step | |
stepBig | |
grid | |
gridDyn | |
gridBig | |
gridMin, gridMax | |
drawGrid | |
init(step, stepBig) | |
setInfoObj | |
regridObj | |
arrNeedUpdate <- objects should call needsGridUpdate(), which will put them here, | |
so the array only goes over those | |
findNearby | |
getInAABB | |
update(circles, 'checkall') | |
*/ | |
// could later implement one more grid, which would be coarser | |
var g_gridStep = max(g_radius, g_sphRadius)*1;//3; // min *1 | |
var g_grid; | |
var g_gridDyn; | |
var g_gridMin; | |
var g_gridMax; | |
applyGlobalParamsLocally(function() | |
{ | |
return; | |
var w = g_materials['water']; | |
var o = g_materials['oil']; | |
var h = g_materials['honey']; | |
w.sphStiff = g_sphStiff; | |
w.sphStiffNear = g_sphStiffNear; | |
w.sphRestDensity = g_sphRestDensity; | |
o.sphRestDensity = g_sphRestDensity; | |
h.sphRestDensity = g_sphRestDensity; | |
w.spriteScale = g_spriteScale; | |
o.spriteScale = g_spriteScale; | |
h.spriteScale = g_spriteScale; | |
/* | |
*/ | |
}) | |
var g_HeatMax = 3; | |
var g_sequential = 1; | |
/////////////////////////////////////////////// | |
// SIMULATION | |
var badSprite = 64; | |
var g_gravity = 9; | |
var g_nGravity = v2(0, 1); | |
var g_useGrid = 1; | |
var numCircles = 10; // <- NUMBER OF CIRCLES | |
var g_drawGrid = 0; | |
var g_drawHeat = 0; | |
var g_drawContacts = 0; | |
var g_jointWidth = 0; | |
var g_timeMult = 0.99;//502; // <-- TIME + STEPS | |
// debug | |
var fKeys = 30;//8; | |
var fShift = 2; | |
// globals | |
var stage, dbgs, dbg; | |
var bgImage, bgClr; | |
var sprites = []; | |
var materials = []; | |
var g_freeCircleId = 1; | |
var circles = []; | |
var joints = []; | |
var grid = []; | |
var dt = 0.001; | |
var g_fps = 100; | |
var dtFrame = 0.001; | |
var c0; // test circle | |
var kd = []; // keys down | |
var kc = []; // keys changed | |
var kx = []; // keys changed really | |
var g_currMaxVel2 = 0; | |
/* | |
ked je velky damp (30) a steps (200), tak spring zacina byt pruzne pevny pri 4000 | |
a pri 10000 je takmer kovovo pevny | |
- pri damp/spring 20/10k je to trochu roztrasene cele | |
- pri damp/spring 30/4k je to dost roztrasene | |
- pri damp/spring 30/1k sa to zacina prehybat | |
- pri steps 50 je roztrasene aj 30/10k | |
sprng/damp maxR | |
kov 9000/20 r*1.2 | |
sklo ako kov r*1.01 | |
drevo 2000/100 r*1.2 | |
zele 200/100 r*1.5 ale slabo sa to kyve este (neskusal som vahu menit) | |
voda 10/1 r*1.2 | |
SPH: | |
*/ | |
var g_materials = | |
{ | |
'default': // any unset properties will be taken from here | |
{ | |
density: 1, velocityDamp: 1, | |
sprite: 'circle', spriteScale: 1, | |
isSph: false, // sph parameters are irrelevant here, but are default values | |
// btw, these are params for water | |
sphStiff: 3000, sphStiffNear: 10000, sphRestDensity: 3, | |
}, | |
'water': | |
{ | |
sprite: 'water', spriteScale: 1, density: 1, | |
isSph: true, | |
}, | |
'honey': | |
{ | |
sprite: 'honey', density: 1.5, spriteScale: 1, | |
isSph: true, sphStiff: 20000, sphStiffNear: 5000, | |
}, | |
'oil': | |
{ | |
sprite: 'oil', density: 0.8, spriteScale: 1, | |
isSph: true, sphStiff: 20000, sphStiffNear: 5000, | |
}, | |
'air': | |
{ | |
sprite: 'air', spriteScale: 0.5, | |
density: 0.002, velocityDamp: 0, | |
isSph: true, sphStiff: 10000, sphStiffNear: 1000, | |
}, | |
'player': { sprite: 'player', density: 0.8, | |
//spriteScale: 2.5, isSph:1,}, | |
spriteScale: 1.0, isSph:0,}, | |
'iron': { sprite: 'iron', density: 8, }, | |
'metal': { sprite: 'metal', density: 5 }, | |
'glass': { sprite: 'glass', density: 4 }, | |
'ice': { sprite: 'ice', }, | |
'snow': { sprite: 'snow', density: 0.1, velocityDamp: 39, spriteScale: 0.5 }, | |
'lava': { sprite: 'lava', density: 10, isSph: true, }, | |
'grass': { sprite: 'grass', density: 0.1, }, | |
'leafs': { sprite: 'leafs', density: 0.1, }, | |
'apple': { sprite: 'apple', }, | |
'orange': { sprite: 'orange', }, | |
'kiwi': { sprite: 'kiwi', }, | |
'strawb': { sprite: 'strawb', }, | |
'banana': { sprite: 'banana', }, | |
'sand': { sprite: 'sand', density: 1.2, }, | |
'dirt': { sprite: 'dirt', density: 2 }, | |
'rocks': { sprite: 'rocks', density: 5}, | |
'plank': { sprite: 'plank', density: 0.5, }, | |
'wood': { sprite: 'wood', density: 0.5, }, | |
'tree': { sprite: 'tree', density: 0.5, }, | |
'skin': { sprite: 'skin', }, | |
'bone': { sprite: 'bone', density: 2 }, | |
'flesh': { sprite: 'flesh', }, | |
'blood': { sprite: 'blood', }, | |
'brains': { sprite: 'brains', }, | |
'piss': { sprite: 'piss', isSph: true, }, | |
'shit': { sprite: 'shit', }, | |
'goo': { sprite: 'goo', }, | |
'jelly': { sprite: 'jelly', }, | |
'flour': { sprite: 'flour', }, | |
}; | |
// iterasi untuk mengeset material yang belum diset... | |
$.each(g_materials, function(matName, material) | |
{ | |
var defM = g_materials['default']; | |
$.each(defM, function(key, defValue) | |
{ | |
if (typeof material[key] == 'undefined') | |
material[key] = defValue; | |
material.name = matName; | |
}); | |
}); | |
function delCircles() | |
{ | |
$.each(circles, function(i, c) | |
{ | |
c.remove(); | |
}); | |
circles = []; | |
fillGrid(); | |
} | |
function delJoints() | |
{ | |
$.each(joints, function(i, j) | |
{ | |
j.remove(); | |
}); | |
joints = []; | |
} | |
function getLoadId(id) | |
{ | |
for (var i=0; i < circles.length; i++) | |
{ | |
var c = circles[i]; | |
if (c.load_id == id) | |
return c; | |
} | |
} | |
// posisi Material ketika mula-mula running | |
function introlevel() | |
{ | |
return '[{"material":"dirt","p":{"x":-144.59520404879004,"y":-10.672370411065913},"v":{"x":0,"y":0},"static":true,"id":11},{"material":"dirt","p":{"x":-96.79530965164304,"y":-8.584861576167441},"v":{"x":0,"y":0},"static":true,"id":12},{"material":"dirt","p":{"x":-143.83654792513698,"y":19.492772138135933},"v":{"x":0,"y":0},"static":true,"id":13},{"material":"dirt","p":{"x":-114.51415546517819,"y":30.73790362795671},"v":{"x":0,"y":0},"static":true,"id":14},{"material":"dirt","p":{"x":-116.61999903433025,"y":-27.894122989458538},"v":{"x":0,"y":0},"static":true,"id":15},{"material":"dirt","p":{"x":-44.418449708260596,"y":-19.020309668183813},"v":{"x":0,"y":0},"static":true,"id":16},{"material":"dirt","p":{"x":-52.41472538653761,"y":-51.73058594498832},"v":{"x":0,"y":0},"static":true,"id":17},{"material":"dirt","p":{"x":-9.232782362960279,"y":-19.746931296922753},"v":{"x":0,"y":0},"static":true,"id":18},{"material":"dirt","p":{"x":-19.3677819063887,"y":-47.34105581618894},"v":{"x":0,"y":0},"static":true,"id":19},{"material":"dirt","p":{"x":-18.16024565882981,"y":-74.46534291110981},"v":{"x":0,"y":0},"static":true,"id":20},{"material":"dirt","p":{"x":8.851370259188116,"y":-53.273998347260545},"v":{"x":0,"y":0},"static":true,"id":21},{"material":"dirt","p":{"x":80.30341436434537,"y":-45.64942848996361},"v":{"x":0,"y":0},"static":true,"id":22},{"material":"dirt","p":{"x":120.16953287087381,"y":-21.231347203600308},"v":{"x":0,"y":0},"static":true,"id":23},{"material":"dirt","p":{"x":68.69239793345332,"y":4.811569885005156},"v":{"x":0,"y":0},"static":true,"id":24},{"material":"dirt","p":{"x":102.66704758163542,"y":3.7243895089522994},"v":{"x":0,"y":0},"static":true,"id":25},{"material":"dirt","p":{"x":109.30349871888757,"y":-44.56559037358602},"v":{"x":0,"y":0},"static":true,"id":26},{"material":"dirt","p":{"x":51.38728418480605,"y":-15.954759281474253},"v":{"x":0,"y":0},"static":true,"id":27},{"material":"dirt","p":{"x":85.35836314130574,"y":-17.586619646634063},"v":{"x":0,"y":0},"static":true,"id":28},{"material":"dirt","p":{"x":160.16807128861547,"y":-28.83329741280113},"v":{"x":0,"y":0},"static":true,"id":29},{"material":"dirt","p":{"x":193.18237041588873,"y":-38.837174410890384},"v":{"x":0,"y":0},"static":true,"id":30},{"material":"dirt","p":{"x":217.7220726571977,"y":-0.7758099464285806},"v":{"x":0,"y":0},"static":true,"id":31},{"material":"dirt","p":{"x":197.70948319882154,"y":20.651948384982006},"v":{"x":0,"y":0},"static":true,"id":32},{"material":"dirt","p":{"x":163.52853292785585,"y":1.4249735475000307},"v":{"x":0,"y":0},"static":true,"id":33},{"material":"dirt","p":{"x":191.8698093816638,"y":-7.583169278647347},"v":{"x":0,"y":0},"static":true,"id":34},{"material":"dirt","p":{"x":258.7371795633808,"y":-8.720283811326226},"v":{"x":0,"y":0},"static":true,"id":35},{"material":"dirt","p":{"x":272.49258855730295,"y":-36.261695479388436},"v":{"x":0,"y":0},"static":true,"id":36},{"material":"dirt","p":{"x":323.95722578372806,"y":-28.889683589684864},"v":{"x":0,"y":0},"static":true,"id":37},{"material":"dirt","p":{"x":306.5520149040967,"y":-5.793485582220455},"v":{"x":0,"y":0},"static":true,"id":38},{"material":"dirt","p":{"x":278.48893032129854,"y":11.781228000883857},"v":{"x":0,"y":0},"static":true,"id":39},{"material":"dirt","p":{"x":295.5928962379694,"y":-54.833315418447455},"v":{"x":0,"y":0},"static":true,"id":40},{"material":"dirt","p":{"x":222.3492145743221,"y":-49.43158605030703},"v":{"x":0,"y":0},"static":true,"id":41},{"material":"dirt","p":{"x":252.97353934682906,"y":-57.83799602079171},"v":{"x":0,"y":0},"static":true,"id":42},{"material":"dirt","p":{"x":22.182849862612784,"y":-15.92156982999495},"v":{"x":0,"y":0},"static":true,"id":43},{"material":"dirt","p":{"x":34.78950885217637,"y":-44.08245540522239},"v":{"x":0,"y":0},"static":true,"id":44},{"material":"dirt","p":{"x":-7.182465181685984,"y":-118.20541776684195},"v":{"x":0,"y":0},"static":true,"id":45},{"material":"dirt","p":{"x":4.3728942312300205,"y":-142.84651825358242},"v":{"x":0,"y":0},"static":true,"id":46},{"material":"dirt","p":{"x":-32.034737568348646,"y":-145.72048597750336},"v":{"x":0,"y":0},"static":true,"id":47},{"material":"dirt","p":{"x":-36.451575335115194,"y":-95.99166066632688},"v":{"x":0,"y":0},"static":true,"id":48},{"material":"dirt","p":{"x":-49.015684170648456,"y":-124.6018002765727},"v":{"x":0,"y":0},"static":true,"id":49},{"material":"dirt","p":{"x":-92.47663851454854,"y":-191.73075426216656},"v":{"x":0,"y":0},"static":true,"id":50},{"material":"dirt","p":{"x":-75.67950525507331,"y":-158.1762534355321},"v":{"x":0,"y":0},"static":true,"id":51},{"material":"dirt","p":{"x":-112.98394699208438,"y":-166.5315594713711},"v":{"x":0,"y":0},"static":true,"id":52},{"material":"dirt","p":{"x":-64.47313283476979,"y":-196.04506262704217},"v":{"x":0,"y":0},"static":true,"id":53},{"material":"dirt","p":{"x":-101.36212995741516,"y":-138.8101208837279},"v":{"x":0,"y":0},"static":true,"id":54},{"material":"dirt","p":{"x":-47.59487931616604,"y":-172.43322349745267},"v":{"x":0,"y":0},"static":true,"id":55},{"material":"dirt","p":{"x":-84.19142765924335,"y":-98.31009087485313},"v":{"x":0,"y":0},"static":true,"id":56},{"material":"dirt","p":{"x":-113.39252855721861,"y":-75.67834949267149},"v":{"x":0,"y":0},"static":true,"id":57},{"material":"dirt","p":{"x":-78.42762796860188,"y":-69.07818204776436},"v":{"x":0,"y":0},"static":true,"id":58},{"material":"dirt","p":{"x":-129.09209490660578,"y":-100.84980467666924},"v":{"x":0,"y":0},"static":true,"id":59},{"material":"dirt","p":{"x":-76.59402647707611,"y":-124.7453177436912},"v":{"x":0,"y":0},"static":true,"id":60},{"material":"dirt","p":{"x":-156.90628589782864,"y":-77.51901704739316},"v":{"x":0,"y":0},"static":true,"id":61},{"material":"dirt","p":{"x":-178.60504616983235,"y":-59.6263034456922},"v":{"x":0,"y":0},"static":true,"id":62},{"material":"dirt","p":{"x":-183.0918392315507,"y":-102.1563104979275},"v":{"x":0,"y":0},"static":true,"id":63},{"material":"dirt","p":{"x":-155.77379240933806,"y":-121.5230364046572},"v":{"x":0,"y":0},"static":true,"id":64},{"material":"dirt","p":{"x":-198.70927310548723,"y":-80.14651286240053},"v":{"x":0,"y":0},"static":true,"id":65},{"material":"dirt","p":{"x":-206.1641043331474,"y":-6.087916434814588},"v":{"x":0,"y":0},"static":true,"id":66},{"material":"dirt","p":{"x":-223.38876654673368,"y":-36.43339789479728},"v":{"x":0,"y":0},"static":true,"id":67},{"material":"dirt","p":{"x":-175.86269970517606,"y":-8.5160974236926},"v":{"x":0,"y":0},"static":true,"id":68},{"material":"dirt","p":{"x":-193.88340264558792,"y":-33.04948560155685},"v":{"x":0,"y":0},"static":true,"id":69},{"material":"dirt","p":{"x":-163.3959765145555,"y":-33.28155238002296},"v":{"x":0,"y":0},"static":true,"id":70},{"material":"dirt","p":{"x":-137.5336029175669,"y":-144.47229786720277},"v":{"x":0,"y":0},"static":true,"id":71},{"material":"dirt","p":{"x":-256.07733468990773,"y":-48.805049886341294},"v":{"x":0,"y":0},"static":true,"id":72},{"material":"dirt","p":{"x":-286.88575614616275,"y":-30.424332100312313},"v":{"x":0,"y":0},"static":true,"id":73},{"material":"dirt","p":{"x":-257.35859125945717,"y":-17.165284449580213},"v":{"x":0,"y":0},"static":true,"id":74},{"material":"dirt","p":{"x":-237.70307700429112,"y":8.465581623491744},"v":{"x":0,"y":0},"static":true,"id":75},{"material":"dirt","p":{"x":-269.04977033659816,"y":11.574990242374042},"v":{"x":0,"y":0},"static":true,"id":76},{"material":"dirt","p":{"x":389.048889413476,"y":-51.85998874095219},"v":{"x":0,"y":0},"static":true,"id":77},{"material":"dirt","p":{"x":404.4107142146677,"y":-8.757594948010023},"v":{"x":0,"y":0},"static":true,"id":78},{"material":"dirt","p":{"x":359.5782151594758,"y":-51.63421027579295},"v":{"x":0,"y":0},"static":true,"id":79},{"material":"dirt","p":{"x":376.1524036489427,"y":-18.32103037678587},"v":{"x":0,"y":0},"static":true,"id":80},{"material":"dirt","p":{"x":345.5380026474595,"y":0.11040941408884919},"v":{"x":0,"y":0},"static":true,"id":81},{"material":"dirt","p":{"x":374.95463914982975,"y":9.506508133067314},"v":{"x":0,"y":0},"static":true,"id":82},{"material":"dirt","p":{"x":402.77595574222505,"y":-101.40019801479343},"v":{"x":0,"y":0},"static":true,"id":83},{"material":"dirt","p":{"x":428.69312564097345,"y":-46.28205360692505},"v":{"x":0,"y":0},"static":true,"id":84},{"material":"dirt","p":{"x":423.046991661191,"y":-82.24877209436659},"v":{"x":0,"y":0},"static":true,"id":85},{"material":"dirt","p":{"x":452.2287735398859,"y":-83.33486019854013},"v":{"x":0,"y":0},"static":true,"id":86},{"material":"dirt","p":{"x":436.96501636877656,"y":-107.57535680246701},"v":{"x":0,"y":0},"static":true,"id":87},{"material":"dirt","p":{"x":456.0918662380427,"y":-51.474067798379565},"v":{"x":0,"y":0},"static":true,"id":88},{"material":"dirt","p":{"x":503.3323030555621,"y":-105.81426081040456},"v":{"x":0,"y":0},"static":true,"id":89},{"material":"dirt","p":{"x":491.2568056732416,"y":-148.52848590889528},"v":{"x":0,"y":0},"static":true,"id":90},{"material":"dirt","p":{"x":457.7880915971473,"y":-132.15434291192844},"v":{"x":0,"y":0},"static":true,"id":91},{"material":"dirt","p":{"x":516.1613789303228,"y":-131.70091526003137},"v":{"x":0,"y":0},"static":true,"id":92},{"material":"dirt","p":{"x":477.9094619397074,"y":-98.90472716817214},"v":{"x":0,"y":0},"static":true,"id":93},{"material":"dirt","p":{"x":511.11839026305825,"y":-169.0719148239424},"v":{"x":0,"y":0},"static":true,"id":94},{"material":"dirt","p":{"x":554.3906759805977,"y":-213.89827466660643},"v":{"x":0,"y":0},"static":true,"id":95},{"material":"dirt","p":{"x":563.334210745059,"y":-187.96088320759588},"v":{"x":0,"y":0},"static":true,"id":96},{"material":"dirt","p":{"x":539.8659093007445,"y":-235.80417391841763},"v":{"x":0,"y":0},"static":true,"id":97},{"material":"dirt","p":{"x":529.6594617944211,"y":-202.12959005960727},"v":{"x":0,"y":0},"static":true,"id":98},{"material":"dirt","p":{"x":581.7163873994723,"y":-209.85629867759997},"v":{"x":0,"y":0},"static":true,"id":99},{"material":"dirt","p":{"x":567.358026378788,"y":-239.9040830909271},"v":{"x":0,"y":0},"static":true,"id":100},{"material":"dirt","p":{"x":611.4745649080724,"y":-170.67330607529107},"v":{"x":0,"y":0},"static":true,"id":101},{"material":"dirt","p":{"x":609.1910159802064,"y":-203.39115781466785},"v":{"x":0,"y":0},"static":true,"id":102},{"material":"dirt","p":{"x":578.3217026200145,"y":-163.78929951823625},"v":{"x":0,"y":0},"static":true,"id":103},{"material":"dirt","p":{"x":602.7093817722052,"y":-143.53341844761246},"v":{"x":0,"y":0},"static":true,"id":104},{"material":"dirt","p":{"x":639.1875074002892,"y":-166.00810048141227},"v":{"x":0,"y":0},"static":true,"id":105},{"material":"dirt","p":{"x":673.8219359470531,"y":-54.29707453231936},"v":{"x":0,"y":0},"static":true,"id":106},{"material":"dirt","p":{"x":695.0720843980089,"y":-83.52393139358287},"v":{"x":0,"y":0},"static":true,"id":107},{"material":"dirt","p":{"x":694.5200102366507,"y":-119.43741082418387},"v":{"x":0,"y":0},"static":true,"id":108},{"material":"dirt","p":{"x":659.4109494462609,"y":-93.61224230304038},"v":{"x":0,"y":0},"static":true,"id":109},{"material":"dirt","p":{"x":662.1581359971315,"y":-121.62820638175731},"v":{"x":0,"y":0},"static":true,"id":110},{"material":"dirt","p":{"x":649.3296615583822,"y":-67.43320512595903},"v":{"x":0,"y":0},"static":true,"id":111},{"material":"dirt","p":{"x":663.7810251852497,"y":-203.72736536472553},"v":{"x":0,"y":0},"static":true,"id":112},{"material":"dirt","p":{"x":641.6044352017343,"y":-227.65223353303486},"v":{"x":0,"y":0},"static":true,"id":113},{"material":"dirt","p":{"x":679.4983097538352,"y":-179.49361246305966},"v":{"x":0,"y":0},"static":true,"id":114},{"material":"dirt","p":{"x":636.4392625885084,"y":-199.15574055112415},"v":{"x":0,"y":0},"static":true,"id":115},{"material":"dirt","p":{"x":682.2832025634125,"y":-279.6387831296028},"v":{"x":0,"y":0},"static":true,"id":116},{"material":"dirt","p":{"x":674.5944783668965,"y":-229.02666039086893},"v":{"x":0,"y":0},"static":true,"id":117},{"material":"dirt","p":{"x":648.1242512753233,"y":-259.5047987277807},"v":{"x":0,"y":0},"static":true,"id":118},{"material":"dirt","p":{"x":700.57931352593,"y":-254.8583079965428},"v":{"x":0,"y":0},"static":true,"id":119},{"material":"dirt","p":{"x":734.9706686325371,"y":-271.2767655298118},"v":{"x":0,"y":0},"static":true,"id":120},{"material":"dirt","p":{"x":762.8975257473066,"y":-250.3793920975183},"v":{"x":0,"y":0},"static":true,"id":121},{"material":"dirt","p":{"x":741.0382871581241,"y":-297.609318746068},"v":{"x":0,"y":0},"static":true,"id":122},{"material":"dirt","p":{"x":736.9391249399632,"y":-239.15195883698806},"v":{"x":0,"y":0},"static":true,"id":123},{"material":"dirt","p":{"x":772.6050461670384,"y":-293.89579816144004},"v":{"x":0,"y":0},"static":true,"id":124},{"material":"dirt","p":{"x":786.437825509347,"y":-267.5320855549915},"v":{"x":0,"y":0},"static":true,"id":125},{"material":"dirt","p":{"x":764.9038785416633,"y":-320.91924982181024},"v":{"x":0,"y":0},"static":true,"id":126},{"material":"dirt","p":{"x":797.102331998758,"y":-225.74374557089908},"v":{"x":0,"y":0},"static":true,"id":127},{"material":"dirt","p":{"x":811.6860542520881,"y":-253.60935644608838},"v":{"x":0,"y":0},"static":true,"id":128},{"material":"dirt","p":{"x":824.5959579749033,"y":-201.24594295480205},"v":{"x":0,"y":0},"static":true,"id":129},{"material":"dirt","p":{"x":838.6883512036875,"y":-230.15229150549425},"v":{"x":0,"y":0},"static":true,"id":130},{"material":"dirt","p":{"x":792.702255657874,"y":-197.82730874502016},"v":{"x":0,"y":0},"static":true,"id":131},{"material":"dirt","p":{"x":826.3928095586598,"y":-171.19594859224776},"v":{"x":0,"y":0},"static":true,"id":132},{"material":"dirt","p":{"x":801.705375677906,"y":-158.10643525178853},"v":{"x":0,"y":0},"static":true,"id":133},{"material":"dirt","p":{"x":794.4250677125528,"y":-130.77116214680552},"v":{"x":0,"y":0},"static":true,"id":134},{"material":"dirt","p":{"x":793.0279175080359,"y":-94.96058719149858},"v":{"x":0,"y":0},"static":true,"id":135},{"material":"dirt","p":{"x":821.7368215695024,"y":-110.11343046846866},"v":{"x":0,"y":0},"static":true,"id":136},{"material":"dirt","p":{"x":769.2549058049917,"y":-119.3469218351978},"v":{"x":0,"y":0},"static":true,"id":137},{"material":"dirt","p":{"x":766.6380947725847,"y":-90.02295677723487},"v":{"x":0,"y":0},"static":true,"id":138},{"material":"dirt","p":{"x":819.376850573346,"y":-79.73973956225564},"v":{"x":0,"y":0},"static":true,"id":139},{"material":"dirt","p":{"x":795.4835541797802,"y":-60.978835127692946},"v":{"x":0,"y":0},"static":true,"id":140},{"material":"dirt","p":{"x":858.0862845750526,"y":-50.74755154596244},"v":{"x":0,"y":0},"static":true,"id":141},{"material":"dirt","p":{"x":830.7224233429879,"y":3.6649555540683423},"v":{"x":0,"y":0},"static":true,"id":142},{"material":"dirt","p":{"x":874.0017421627417,"y":-10.13577080377911},"v":{"x":0,"y":0},"static":true,"id":143},{"material":"dirt","p":{"x":848.0991946598515,"y":-19.389742989554748},"v":{"x":0,"y":0},"static":true,"id":144},{"material":"dirt","p":{"x":817.8853291124105,"y":-36.3847608282191},"v":{"x":0,"y":0},"static":true,"id":145},{"material":"dirt","p":{"x":865.4318950809538,"y":16.87751217446771},"v":{"x":0,"y":0},"static":true,"id":146},{"material":"dirt","p":{"x":883.5572884147987,"y":-35.6724955057698},"v":{"x":0,"y":0},"static":true,"id":147},{"material":"dirt","p":{"x":906.8952651778236,"y":-8.583949566583897},"v":{"x":0,"y":0},"static":true,"id":148},{"material":"dirt","p":{"x":892.9264710154384,"y":16.401415623959338},"v":{"x":0,"y":0},"static":true,"id":149},{"material":"dirt","p":{"x":732.3758051143959,"y":-206.26825049722822},"v":{"x":0,"y":0},"static":true,"id":150},{"material":"dirt","p":{"x":769.8482316564769,"y":-218.00027606280776},"v":{"x":0,"y":0},"static":true,"id":151},{"material":"dirt","p":{"x":768.4577581835911,"y":-179.6934810915801},"v":{"x":0,"y":0},"static":true,"id":152},{"material":"dirt","p":{"x":666.2562406966463,"y":-153.96703434690892},"v":{"x":0,"y":0},"static":true,"id":153},{"material":"dirt","p":{"x":704.0658791074529,"y":-159.1764368317282},"v":{"x":0,"y":0},"static":true,"id":154},{"material":"dirt","p":{"x":710.2024210998788,"y":-186.98247243233084},"v":{"x":0,"y":0},"static":true,"id":155},{"material":"rocks","p":{"x":622.9841716205701,"y":-90.81143680799983},"v":{"x":0,"y":0},"static":true,"id":156},{"material":"rocks","p":{"x":632.7067280514166,"y":-37.248021008709884},"v":{"x":0,"y":0},"static":true,"id":157},{"material":"rocks","p":{"x":633.758736752905,"y":-119.59106908834576},"v":{"x":0,"y":0},"static":true,"id":158},{"material":"rocks","p":{"x":599.5204796884209,"y":-101.72948882607295},"v":{"x":0,"y":0},"static":true,"id":159},{"material":"rocks","p":{"x":561.1274250978604,"y":-74.05917436698144},"v":{"x":0,"y":0},"static":true,"id":160},{"material":"rocks","p":{"x":549.5196793014184,"y":-102.41835912665044},"v":{"x":0,"y":0},"static":true,"id":161},{"material":"rocks","p":{"x":573.659584030509,"y":-121.54542146039819},"v":{"x":0,"y":0},"static":true,"id":162},{"material":"rocks","p":{"x":544.8183972006664,"y":-128.99008846630966},"v":{"x":0,"y":0},"static":true,"id":163},{"material":"rocks","p":{"x":532.5353543385863,"y":-76.03947262697613},"v":{"x":0,"y":0},"static":true,"id":164},{"material":"rocks","p":{"x":545.4436719790101,"y":-50.555521911814935},"v":{"x":0,"y":0},"static":true,"id":165},{"material":"rocks","p":{"x":516.7241542302072,"y":-53.80047138651355},"v":{"x":0,"y":0},"static":true,"id":166},{"material":"rocks","p":{"x":500.28378844819963,"y":-12.789341662850347},"v":{"x":0,"y":0},"static":true,"id":167},{"material":"rocks","p":{"x":548.1427804678679,"y":-19.476397073667613},"v":{"x":0,"y":0},"static":true,"id":168},{"material":"rocks","p":{"x":482.30062408652157,"y":-34.72255318782118},"v":{"x":0,"y":0},"static":true,"id":169},{"material":"rocks","p":{"x":536.5445474367589,"y":6.438379984896073},"v":{"x":0,"y":0},"static":true,"id":170},{"material":"rocks","p":{"x":485.5959669984877,"y":16.387926067109674},"v":{"x":0,"y":0},"static":true,"id":171},{"material":"rocks","p":{"x":429.23568229936063,"y":4.249983110349149},"v":{"x":0,"y":0},"static":true,"id":172},{"material":"rocks","p":{"x":456.7636717921123,"y":-22.118633336503535},"v":{"x":0,"y":0},"static":true,"id":173},{"material":"rocks","p":{"x":461.5131309097633,"y":35.632801154512435},"v":{"x":0,"y":0},"static":true,"id":174},{"material":"rocks","p":{"x":459.99234092701226,"y":9.129874448952478},"v":{"x":0,"y":0},"static":true,"id":175},{"material":"rocks","p":{"x":588.3558828411624,"y":-24.923138937910153},"v":{"x":0,"y":0},"static":true,"id":176},{"material":"rocks","p":{"x":572.2020553862676,"y":14.35072209406917},"v":{"x":0,"y":0},"static":true,"id":177},{"material":"rocks","p":{"x":627.53838729579,"y":-6.906359615732981},"v":{"x":0,"y":0},"static":true,"id":178},{"material":"rocks","p":{"x":612.7210348220542,"y":17.10160502977942},"v":{"x":0,"y":0},"static":true,"id":179},{"material":"rocks","p":{"x":649.0008204150945,"y":12.980169060681419},"v":{"x":0,"y":0},"static":true,"id":180},{"material":"rocks","p":{"x":656.2192262271419,"y":-12.998150661546333},"v":{"x":0,"y":0},"static":true,"id":181},{"material":"rocks","p":{"x":688.9700072258711,"y":-5.7270718223086305},"v":{"x":0,"y":0},"static":true,"id":182},{"material":"rocks","p":{"x":675.5925250183791,"y":27.92253700861272},"v":{"x":0,"y":0},"static":true,"id":183},{"material":"rocks","p":{"x":722.0312319751829,"y":-21.01528102578459},"v":{"x":0,"y":0},"static":true,"id":184},{"material":"rocks","p":{"x":707.1468374775723,"y":25.593840165530764},"v":{"x":0,"y":0},"static":true,"id":185},{"material":"rocks","p":{"x":736.7432211684063,"y":8.337642172818505},"v":{"x":0,"y":0},"static":true,"id":186},{"material":"rocks","p":{"x":758.5149075519294,"y":-9.990293635403532},"v":{"x":0,"y":0},"static":true,"id":187},{"material":"rocks","p":{"x":728.06718913652,"y":-72.4349332270508},"v":{"x":0,"y":0},"static":true,"id":188},{"material":"rocks","p":{"x":762.884892004542,"y":-61.73742582977911},"v":{"x":0,"y":0},"static":true,"id":189},{"material":"rocks","p":{"x":742.1423953212798,"y":-43.51774698545387},"v":{"x":0,"y":0},"static":true,"id":190},{"material":"rocks","p":{"x":740.7190140020102,"y":-104.91414556888094},"v":{"x":0,"y":0},"static":true,"id":191},{"material":"rocks","p":{"x":714.6797949345782,"y":-49.118620347726846},"v":{"x":0,"y":0},"static":true,"id":192},{"material":"rocks","p":{"x":725.7129402188584,"y":-131.88099544544605},"v":{"x":0,"y":0},"static":true,"id":193},{"material":"rocks","p":{"x":759.6313686445355,"y":-146.1549481483578},"v":{"x":0,"y":0},"static":true,"id":194},{"material":"rocks","p":{"x":736.9245917033404,"y":-166.99576186592788},"v":{"x":0,"y":0},"static":true,"id":195},{"material":"rocks","p":{"x":771.809547864832,"y":-34.94223798364601},"v":{"x":0,"y":0},"static":true,"id":196},{"material":"rocks","p":{"x":589.9490822292864,"y":-55.866379058292864},"v":{"x":0,"y":0},"static":true,"id":197},{"material":"rocks","p":{"x":805.4652477996424,"y":18.486957596034586},"v":{"x":0,"y":0},"static":true,"id":198},{"material":"rocks","p":{"x":779.9775017509237,"y":13.81197047361809},"v":{"x":0,"y":0},"static":true,"id":199},{"material":"rocks","p":{"x":803.0890496475622,"y":-9.461818412526668},"v":{"x":0,"y":0},"static":true,"id":200},{"material":"rocks","p":{"x":840.4955794131383,"y":30.58012434991656},"v":{"x":0,"y":0},"static":true,"id":201},{"material":"sand","p":{"x":877,"y":-100.15373961218836},"v":{"x":0,"y":0},"static":true,"id":202},{"material":"sand","p":{"x":900,"y":-68.1094182825484},"v":{"x":0,"y":0},"static":true,"id":203},{"material":"sand","p":{"x":922,"y":-47.08033240997224},"v":{"x":0,"y":0},"static":true,"id":204},{"material":"sand","p":{"x":975,"y":-20.044321329639843},"v":{"x":0,"y":0},"static":true,"id":205},{"material":"sand","p":{"x":1008,"y":-13.034626038781084},"v":{"x":0,"y":0},"static":true,"id":206},{"material":"sand","p":{"x":826,"y":-141.21191135734068},"v":{"x":0,"y":0},"static":true,"id":207},{"material":"sand","p":{"x":861,"y":-127.19252077562317},"v":{"x":0,"y":0},"static":true,"id":208},{"material":"sand","p":{"x":913,"y":-98.15235457063704},"v":{"x":0,"y":0},"static":true,"id":209},{"material":"sand","p":{"x":867.3523139208555,"y":-171.46513517113738},"v":{"x":0,"y":0},"static":true,"id":210},{"material":"sand","p":{"x":883.6417940706015,"y":-144.2040016132553},"v":{"x":0,"y":0},"static":true,"id":211},{"material":"sand","p":{"x":910.9176457170397,"y":-127.71750865727813},"v":{"x":0,"y":0},"static":true,"id":212},{"material":"sand","p":{"x":849.2632860997692,"y":-98.42872896175982},"v":{"x":0,"y":0},"static":true,"id":213},{"material":"sand","p":{"x":949.916012333706,"y":-87.2383848252058},"v":{"x":0,"y":0},"static":true,"id":214},{"material":"sand","p":{"x":955.7930163387209,"y":-50.327313926450074},"v":{"x":0,"y":0},"static":true,"id":215},{"material":"sand","p":{"x":976.549031435512,"y":-74.763334656903},"v":{"x":0,"y":0},"static":true,"id":216},{"material":"sand","p":{"x":938.0069152805954,"y":-20.817343039043294},"v":{"x":0,"y":0},"static":true,"id":217},{"material":"sand","p":{"x":989.5491797588766,"y":-46.0243005688867},"v":{"x":0,"y":0},"static":true,"id":218},{"material":"sand","p":{"x":987.2472640480846,"y":5.36895493639588},"v":{"x":0,"y":0},"static":true,"id":219},{"material":"sand","p":{"x":1017.8496695067734,"y":-45.009927936476174},"v":{"x":0,"y":0},"static":true,"id":220},{"material":"sand","p":{"x":1038.675354797393,"y":-19.166628310841247},"v":{"x":0,"y":0},"static":true,"id":221},{"material":"sand","p":{"x":1056.5875082956627,"y":-39.918661797726145},"v":{"x":0,"y":0},"static":true,"id":222},{"material":"sand","p":{"x":1033.368304132484,"y":14.321896569496403},"v":{"x":0,"y":0},"static":true,"id":223},{"material":"sand","p":{"x":1072.4865146800876,"y":-17.535807578200092},"v":{"x":0,"y":0},"static":true,"id":224},{"material":"sand","p":{"x":1061.8267267551273,"y":16.567825302252118},"v":{"x":0,"y":0},"static":true,"id":225},{"material":"sand","p":{"x":1099.464100357145,"y":-29.056516420248272},"v":{"x":0,"y":0},"static":true,"id":226},{"material":"sand","p":{"x":1097.1903503267094,"y":-0.7094473514364381},"v":{"x":0,"y":0},"static":true,"id":227},{"material":"sand","p":{"x":1122.6936676604673,"y":-12.342825316821404},"v":{"x":0,"y":0},"static":true,"id":228},{"material":"sand","p":{"x":1114.309364314191,"y":21.886072902088927},"v":{"x":0,"y":0},"static":true,"id":229},{"material":"sand","p":{"x":1126.1689772754908,"y":-40.59347131180664},"v":{"x":0,"y":0},"static":true,"id":230},{"material":"sand","p":{"x":1150.6996508138254,"y":-9.243669399795522},"v":{"x":0,"y":0},"static":true,"id":231},{"material":"sand","p":{"x":1145.6757950410247,"y":22.101388906324814},"v":{"x":0,"y":0},"static":true,"id":232},{"material":"sand","p":{"x":1158.8021706882864,"y":-34.3298723891279},"v":{"x":0,"y":0},"static":true,"id":233},{"material":"sand","p":{"x":1172.473381338641,"y":11.015485700454747},"v":{"x":0,"y":0},"static":true,"id":234},{"material":"sand","p":{"x":1185.68398981262,"y":-14.372964291598464},"v":{"x":0,"y":0},"static":true,"id":235},{"material":"sand","p":{"x":1209.264890378341,"y":0.538417636690383},"v":{"x":0,"y":0},"static":true,"id":236},{"material":"sand","p":{"x":1190.6374092120677,"y":-40.2717276660627},"v":{"x":0,"y":0},"static":true,"id":237},{"material":"sand","p":{"x":1215.3677939865738,"y":-25.160296379431088},"v":{"x":0,"y":0},"static":true,"id":238},{"material":"sand","p":{"x":1243.5726271290332,"y":-28.0610500508119},"v":{"x":0,"y":0},"static":true,"id":239},{"material":"sand","p":{"x":1236.1169979516417,"y":15.236432311205135},"v":{"x":0,"y":0},"static":true,"id":240},{"material":"sand","p":{"x":1264.2551273582503,"y":-1.1504853682494058},"v":{"x":0,"y":0},"static":true,"id":241},{"material":"sand","p":{"x":1272.3842510962859,"y":-29.65700617312109},"v":{"x":0,"y":0},"static":true,"id":242},{"material":"sand","p":{"x":1262.2846676148474,"y":27.704480657627528},"v":{"x":0,"y":0},"static":true,"id":243},{"material":"sand","p":{"x":1301.1535900309682,"y":-7.320199698867555},"v":{"x":0,"y":0},"static":true,"id":244},{"material":"sand","p":{"x":1297.5819082725793,"y":22.32063891672874},"v":{"x":0,"y":0},"static":true,"id":245},{"material":"sand","p":{"x":1302.6147450944409,"y":-33.4008931691817},"v":{"x":0,"y":0},"static":true,"id":246},{"material":"sand","p":{"x":1327.6234129043296,"y":-15.974354837708916},"v":{"x":0,"y":0},"static":true,"id":247},{"material":"sand","p":{"x":1325.998420290649,"y":16.55361960397738},"v":{"x":0,"y":0},"static":true,"id":248},{"material":"sand","p":{"x":1352.4464548090473,"y":4.060674257034748},"v":{"x":0,"y":0},"static":true,"id":249},{"material":"sand","p":{"x":1350.3200136870146,"y":-31.266066377592892},"v":{"x":0,"y":0},"static":true,"id":250},{"material":"sand","p":{"x":1350.9090655744076,"y":31.607885597740733},"v":{"x":0,"y":0},"static":true,"id":251},{"material":"sand","p":{"x":1380.761766731739,"y":-4.29362479364363},"v":{"x":0,"y":0},"static":true,"id":252},{"material":"sand","p":{"x":1390.887936681509,"y":26.49040911397242},"v":{"x":0,"y":0},"static":true,"id":253},{"material":"sand","p":{"x":1380.8099695518613,"y":-33.220750589349336},"v":{"x":0,"y":0},"static":true,"id":254},{"material":"sand","p":{"x":1410.7738582156599,"y":0.08650125151928023},"v":{"x":0,"y":0},"static":true,"id":255},{"material":"sand","p":{"x":1438.5053531769663,"y":17.287699089037346},"v":{"x":0,"y":0},"static":true,"id":256},{"material":"sand","p":{"x":1414.0782640939578,"y":-26.71400715631796},"v":{"x":0,"y":0},"static":true,"id":257},{"material":"sand","p":{"x":1439.649057969451,"y":-14.895506192346943},"v":{"x":0,"y":0},"static":true,"id":258},{"material":"sand","p":{"x":1417.4380193306133,"y":37.07682980841594},"v":{"x":0,"y":0},"static":true,"id":259},{"material":"sand","p":{"x":1466.8353902362287,"y":9.386002309272158},"v":{"x":0,"y":0},"static":true,"id":260},{"material":"sand","p":{"x":1464.2770121442154,"y":37.93892477623547},"v":{"x":0,"y":0},"static":true,"id":261},{"material":"sand","p":{"x":1488.9052075101063,"y":-7.906317831171805},"v":{"x":0,"y":0},"static":true,"id":262},{"material":"sand","p":{"x":1493.9038852639496,"y":34.49440785392687},"v":{"x":0,"y":0},"static":true,"id":263},{"material":"sand","p":{"x":1515.3215932082385,"y":5.36514677933917},"v":{"x":0,"y":0},"static":true,"id":264},{"material":"sand","p":{"x":1516.349387289025,"y":-23.24265855469241},"v":{"x":0,"y":0},"static":true,"id":265},{"material":"sand","p":{"x":1541.2063508499414,"y":21.45852809760288},"v":{"x":0,"y":0},"static":true,"id":266},{"material":"sand","p":{"x":1542.2930148141459,"y":-11.100302501697684},"v":{"x":0,"y":0},"static":true,"id":267},{"material":"sand","p":{"x":1566.9779214579612,"y":6.936976649682379},"v":{"x":0,"y":0},"static":true,"id":268},{"material":"sand","p":{"x":1565.0794302308932,"y":41.06120470527128},"v":{"x":0,"y":0},"static":true,"id":269},{"material":"sand","p":{"x":1592.8574098823592,"y":20.183986571540117},"v":{"x":0,"y":0},"static":true,"id":270},{"material":"sand","p":{"x":1586.6116733429953,"y":-10.761940316335767},"v":{"x":0,"y":0},"static":true,"id":271},{"material":"sand","p":{"x":1617,"y":-21.044321329639843},"v":{"x":0,"y":0},"static":true,"id":272},{"material":"rocks","p":{"x":1926.559049911797,"y":-8.502218081729325},"v":{"x":0,"y":0},"static":true,"id":273},{"material":"rocks","p":{"x":1894.990714081563,"y":-47.17836753383449},"v":{"x":0,"y":0},"static":true,"id":274},{"material":"rocks","p":{"x":1871.137743816711,"y":-32.29947714612058},"v":{"x":0,"y":0},"static":true,"id":275},{"material":"rocks","p":{"x":1893.21808530204,"y":-9.41096181061289},"v":{"x":0,"y":0},"static":true,"id":276},{"material":"rocks","p":{"x":1866.0166868017986,"y":1.7389651796577255},"v":{"x":0,"y":0},"static":true,"id":277},{"material":"rocks","p":{"x":1897.38183242362,"y":19.953992873316793},"v":{"x":0,"y":0},"static":true,"id":278},{"material":"rocks","p":{"x":1936.836599810049,"y":-34.67215204048489},"v":{"x":0,"y":0},"static":true,"id":279},{"material":"rocks","p":{"x":1930.7124742940068,"y":20.14830890022631},"v":{"x":0,"y":0},"static":true,"id":280},{"material":"rocks","p":{"x":1965.575336090289,"y":-15.246211366725333},"v":{"x":0,"y":0},"static":true,"id":281},{"material":"rocks","p":{"x":1839.7327254805714,"y":-28.33058441379501},"v":{"x":0,"y":0},"static":true,"id":282},{"material":"rocks","p":{"x":1798.482820091769,"y":-9.210248169953502},"v":{"x":0,"y":0},"static":true,"id":283},{"material":"rocks","p":{"x":1758.7870813626796,"y":24.806686025579893},"v":{"x":0,"y":0},"static":true,"id":284},{"material":"rocks","p":{"x":1754.263061576523,"y":-14.3202681387761},"v":{"x":0,"y":0},"static":true,"id":285},{"material":"rocks","p":{"x":1786.3119987854734,"y":18.695557215718054},"v":{"x":0,"y":0},"static":true,"id":286},{"material":"rocks","p":{"x":1733.487753749825,"y":4.169401932974779},"v":{"x":0,"y":0},"static":true,"id":287},{"material":"rocks","p":{"x":1778.9653720622882,"y":-30.531806764657176},"v":{"x":0,"y":0},"static":true,"id":288},{"material":"rocks","p":{"x":1822.3949220459908,"y":16.000330384356403},"v":{"x":0,"y":0},"static":true,"id":289},{"material":"rocks","p":{"x":1806.3652340071276,"y":-35.24408856274715},"v":{"x":0,"y":0},"static":true,"id":290},{"material":"rocks","p":{"x":1849.3813649201766,"y":25.734245945895623},"v":{"x":0,"y":0},"static":true,"id":291},{"material":"rocks","p":{"x":1970.6776387309656,"y":25.769119171737884},"v":{"x":0,"y":0},"static":true,"id":292},{"material":"rocks","p":{"x":1992.6591491457075,"y":-1.697462334916736},"v":{"x":0,"y":0},"static":true,"id":293},{"material":"rocks","p":{"x":1993.1934669893235,"y":-32.55465096227272},"v":{"x":0,"y":0},"static":true,"id":294},{"material":"rocks","p":{"x":1957.7624491332099,"y":-53.170634652678814},"v":{"x":0,"y":0},"static":true,"id":295},{"material":"rocks","p":{"x":1930.0875214738771,"y":-69.9078942518629},"v":{"x":0,"y":0},"static":true,"id":296},{"material":"rocks","p":{"x":1866.1693059140816,"y":-75.23258572296231},"v":{"x":0,"y":0},"static":true,"id":297},{"material":"rocks","p":{"x":1894.6808382254094,"y":-79.8302307961601},"v":{"x":0,"y":0},"static":true,"id":298},{"material":"rocks","p":{"x":1837.8908278560266,"y":-82.33307477047299},"v":{"x":0,"y":0},"static":true,"id":299},{"material":"rocks","p":{"x":1821.4877082100138,"y":-57.58030013331927},"v":{"x":0,"y":0},"static":true,"id":300},{"material":"rocks","p":{"x":1796.5324356518686,"y":-69.06472576373972},"v":{"x":0,"y":0},"static":true,"id":301},{"material":"dirt","p":{"x":1665.6655962951481,"y":-40.11755653873979},"v":{"x":0,"y":0},"static":true,"id":302},{"material":"dirt","p":{"x":1676.0871265968308,"y":5.8352034051627015},"v":{"x":0,"y":0},"static":true,"id":303},{"material":"dirt","p":{"x":1701.74836826697,"y":-51.35093976029157},"v":{"x":0,"y":0},"static":true,"id":304},{"material":"dirt","p":{"x":1702.0127899702638,"y":-11.578833678112915},"v":{"x":0,"y":0},"static":true,"id":305},{"material":"dirt","p":{"x":1650.5395609419793,"y":-6.843949171982672},"v":{"x":0,"y":0},"static":true,"id":306},{"material":"dirt","p":{"x":1704.6083223950118,"y":16.885408262608735},"v":{"x":0,"y":0},"static":true,"id":307},{"material":"dirt","p":{"x":1721.6865637339652,"y":-32.490383038333334},"v":{"x":0,"y":0},"static":true,"id":308},{"material":"dirt","p":{"x":1735.62183387205,"y":-57.78204152057424},"v":{"x":0,"y":0},"static":true,"id":309},{"material":"dirt","p":{"x":1764.5226794127375,"y":-60.51840452888041},"v":{"x":0,"y":0},"static":true,"id":310},{"material":"dirt","p":{"x":1747.7806108845398,"y":-86.0901905983851},"v":{"x":0,"y":0},"static":true,"id":311},{"material":"dirt","p":{"x":1793.2898252243176,"y":-99.76834721334649},"v":{"x":0,"y":0},"static":true,"id":312},{"material":"dirt","p":{"x":1821.7556468769908,"y":-111.69088622173831},"v":{"x":0,"y":0},"static":true,"id":313},{"material":"dirt","p":{"x":1851.7637223722413,"y":-107.27917367979421},"v":{"x":0,"y":0},"static":true,"id":314},{"material":"dirt","p":{"x":1878.7434199610725,"y":-101.71737944807103},"v":{"x":0,"y":0},"static":true,"id":315},{"material":"dirt","p":{"x":1910.8873105347157,"y":-101.51233051242843},"v":{"x":0,"y":0},"static":true,"id":316},{"material":"dirt","p":{"x":1948.3397796573117,"y":-92.98786480417289},"v":{"x":0,"y":0},"static":true,"id":317},{"material":"dirt","p":{"x":1972.985897014849,"y":-76.05632016659445},"v":{"x":0,"y":0},"static":true,"id":318},{"material":"dirt","p":{"x":2002.273735113442,"y":-62.87998676295399},"v":{"x":0,"y":0},"static":true,"id":319},{"material":"dirt","p":{"x":2022.4420212144032,"y":-23.817354837659423},"v":{"x":0,"y":0},"static":true,"id":320},{"material":"dirt","p":{"x":2038.136483383365,"y":-45.34668328406906},"v":{"x":0,"y":0},"static":true,"id":321},{"material":"dirt","p":{"x":2030.8491661082953,"y":6.156801456977746},"v":{"x":0,"y":0},"static":true,"id":322},{"material":"dirt","p":{"x":2052.1591465249658,"y":-10.743026435759589},"v":{"x":0,"y":0},"static":true,"id":323},{"material":"dirt","p":{"x":2067.0904469098896,"y":-32.27947987809796},"v":{"x":0,"y":0},"static":true,"id":324},{"material":"dirt","p":{"x":2077.2825164003298,"y":1.6607817459175749},"v":{"x":0,"y":0},"static":true,"id":325},{"material":"dirt","p":{"x":2058.1742308465764,"y":22.725019149794434},"v":{"x":0,"y":0},"static":true,"id":326},{"material":"dirt","p":{"x":2103.03660065867,"y":22.366710735214156},"v":{"x":0,"y":0},"static":true,"id":327},{"material":"dirt","p":{"x":2102.4503308720887,"y":-9.709903308461207},"v":{"x":0,"y":0},"static":true,"id":328},{"material":"dirt","p":{"x":2085.2112548667938,"y":42.942953794185996},"v":{"x":0,"y":0},"static":true,"id":329},{"material":"dirt","p":{"x":2028.9465504698455,"y":-75.34168743267855},"v":{"x":0,"y":0},"static":true,"id":330},{"material":"dirt","p":{"x":1996.8634280022234,"y":-90.80399860700948},"v":{"x":0,"y":0},"static":true,"id":331},{"material":"dirt","p":{"x":1887.274368791841,"y":-129.60509998295868},"v":{"x":0,"y":0},"static":true,"id":332},{"material":"dirt","p":{"x":1846.8324780296534,"y":-133.54678976037883},"v":{"x":0,"y":0},"static":true,"id":333},{"material":"dirt","p":{"x":1768.395758238621,"y":-114.16155145657592},"v":{"x":0,"y":0},"static":true,"id":334},{"material":"dirt","p":{"x":1790.5850874576718,"y":-131.4103148445987},"v":{"x":0,"y":0},"static":true,"id":335},{"material":"dirt","p":{"x":1731.812960062176,"y":-108.54649180688807},"v":{"x":0,"y":0},"static":true,"id":336},{"material":"dirt","p":{"x":1719.1828238721937,"y":-84.28963051940934},"v":{"x":0,"y":0},"static":true,"id":337},{"material":"sand","p":{"x":1567.2937449403107,"y":-32.453708332258884},"v":{"x":0,"y":0},"static":true,"id":338},{"material":"sand","p":{"x":1600.3462958885357,"y":-49.49081433866513},"v":{"x":0,"y":0},"static":true,"id":339},{"material":"sand","p":{"x":1575.2780050346628,"y":-71.19454466108573},"v":{"x":0,"y":0},"static":true,"id":340},{"material":"sand","p":{"x":1547.619893167168,"y":-54.43272942979229},"v":{"x":0,"y":0},"static":true,"id":341},{"material":"sand","p":{"x":1604.2012209398672,"y":-76.92614368581496},"v":{"x":0,"y":0},"static":true,"id":342},{"material":"sand","p":{"x":1626.072313615121,"y":-59.61210359500353},"v":{"x":0,"y":0},"static":true,"id":343},{"material":"sand","p":{"x":1643.5447426727042,"y":-81.1344027861802},"v":{"x":0,"y":0},"static":true,"id":344},{"material":"sand","p":{"x":1627.1525619896129,"y":-106.08803488914737},"v":{"x":0,"y":0},"static":true,"id":345},{"material":"sand","p":{"x":1661.2679947987199,"y":-100.70656498307176},"v":{"x":0,"y":0},"static":true,"id":346},{"material":"sand","p":{"x":1673.8492783810943,"y":-67.11406023120321},"v":{"x":0,"y":0},"static":true,"id":347},{"material":"sand","p":{"x":1689.8897696556523,"y":-98.8585343054234},"v":{"x":0,"y":0},"static":true,"id":348},{"material":"sand","p":{"x":1683.4968018084764,"y":-124.99331271957726},"v":{"x":0,"y":0},"static":true,"id":349},{"material":"sand","p":{"x":1718.252552605234,"y":-133.06859173317923},"v":{"x":0,"y":0},"static":true,"id":350},{"material":"sand","p":{"x":1746.5854627918452,"y":-131.95877602788255},"v":{"x":0,"y":0},"static":true,"id":351},{"material":"rocks","p":{"x":1867.2433949159458,"y":-158.80852708005318},"v":{"x":0,"y":0},"static":true,"id":352},{"material":"rocks","p":{"x":1838.032982133329,"y":-171.12902224593768},"v":{"x":0,"y":0},"static":true,"id":353},{"material":"rocks","p":{"x":1808.3370279707015,"y":-160.67003203713307},"v":{"x":0,"y":0},"static":true,"id":354},{"material":"rocks","p":{"x":1899.5741114988923,"y":-162.4588462202255},"v":{"x":0,"y":0},"static":true,"id":355},{"material":"rocks","p":{"x":1914.8893790589646,"y":-134.91922178335085},"v":{"x":0,"y":0},"static":true,"id":356},{"material":"rocks","p":{"x":1950.1828124020249,"y":-140.1915193277557},"v":{"x":0,"y":0},"static":true,"id":357},{"material":"rocks","p":{"x":1934.0899093542248,"y":-170.93510021857514},"v":{"x":0,"y":0},"static":true,"id":358},{"material":"rocks","p":{"x":1977.1976170158014,"y":-147.94596798079976},"v":{"x":0,"y":0},"static":true,"id":359},{"material":"rocks","p":{"x":1971.102038868703,"y":-109.81071743375287},"v":{"x":0,"y":0},"static":true,"id":360},{"material":"rocks","p":{"x":2000.3869900489226,"y":-118.0389400448422},"v":{"x":0,"y":0},"static":true,"id":361},{"material":"rocks","p":{"x":2028.7070872019976,"y":-121.04360523228877},"v":{"x":0,"y":0},"static":true,"id":362},{"material":"rocks","p":{"x":1899.669439884834,"y":-194.17295082388932},"v":{"x":0,"y":0},"static":true,"id":363},{"material":"rocks","p":{"x":1874.0322168739513,"y":-189.7391077944585},"v":{"x":0,"y":0},"static":true,"id":364},{"material":"rocks","p":{"x":1872.291384066455,"y":-220.7322265424474},"v":{"x":0,"y":0},"static":true,"id":365},{"material":"rocks","p":{"x":1847.4703122833744,"y":-205.61546335860032},"v":{"x":0,"y":0},"static":true,"id":366},{"material":"rocks","p":{"x":1828.5102518312633,"y":-223.85368494287525},"v":{"x":0,"y":0},"static":true,"id":367},{"material":"rocks","p":{"x":1818.2572950972244,"y":-194.05585438076798},"v":{"x":0,"y":0},"static":true,"id":368},{"material":"rocks","p":{"x":1851.6578052509576,"y":-237.8223066720879},"v":{"x":0,"y":0},"static":true,"id":369},{"material":"rocks","p":{"x":1809.2066576415673,"y":-244.7036997775374},"v":{"x":0,"y":0},"static":true,"id":370},{"material":"rocks","p":{"x":1833.0933755431324,"y":-259.14016688701764},"v":{"x":0,"y":0},"static":true,"id":371},{"material":"rocks","p":{"x":1856.9126287559047,"y":-274.6682347866894},"v":{"x":0,"y":0},"static":true,"id":372},{"material":"rocks","p":{"x":1832.461165114306,"y":-286.27023097582753},"v":{"x":0,"y":0},"static":true,"id":373},{"material":"rocks","p":{"x":1808.564659637399,"y":-272.5755770158827},"v":{"x":0,"y":0},"static":true,"id":374},{"material":"rocks","p":{"x":1916.2286423053592,"y":-218.18534457778236},"v":{"x":0,"y":0},"static":true,"id":375},{"material":"rocks","p":{"x":1936.8721382888034,"y":-198.1812090160263},"v":{"x":0,"y":0},"static":true,"id":376},{"material":"rocks","p":{"x":1781.5589079139754,"y":-165.1432549986663},"v":{"x":0,"y":0},"static":true,"id":377},{"material":"rocks","p":{"x":1800.1332386229187,"y":-216.52590145715288},"v":{"x":0,"y":0},"static":true,"id":378},{"material":"rocks","p":{"x":1782.596771715209,"y":-194.24938761161434},"v":{"x":0,"y":0},"static":true,"id":379},{"material":"rocks","p":{"x":1777.1578127350658,"y":-235.57356079083212},"v":{"x":0,"y":0},"static":true,"id":380},{"material":"rocks","p":{"x":1757.2946046311408,"y":-177.28406477701992},"v":{"x":0,"y":0},"static":true,"id":381},{"material":"water","p":{"x":39,"y":-201.29501385041544},"v":{"x":0,"y":0},"static":false,"id":382},{"material":"water","p":{"x":72,"y":-183.270083102493},"v":{"x":0,"y":0},"static":false,"id":383},{"material":"water","p":{"x":110,"y":-167.24792243767308},"v":{"x":0,"y":0},"static":false,"id":384},{"material":"water","p":{"x":202,"y":-148.22022160664812},"v":{"x":0,"y":0},"static":false,"id":385},{"material":"water","p":{"x":240,"y":-148.22160664819944},"v":{"x":0,"y":0},"static":false,"id":386},{"material":"water","p":{"x":330,"y":-205.30055401662042},"v":{"x":0,"y":0},"static":false,"id":387},{"material":"water","p":{"x":360,"y":-213.31163434903044},"v":{"x":0,"y":0},"static":false,"id":388},{"material":"water","p":{"x":420,"y":-231.33656509695288},"v":{"x":0,"y":0},"static":false,"id":389},{"material":"water","p":{"x":457,"y":-247.3587257617728},"v":{"x":0,"y":0},"static":false,"id":390},{"material":"water","p":{"x":498,"y":-291.41828254847644},"v":{"x":0,"y":0},"static":false,"id":391},{"material":"water","p":{"x":549,"y":-331.4750692520775},"v":{"x":0,"y":0},"static":false,"id":392},{"material":"water","p":{"x":573,"y":-345.4930747922437},"v":{"x":0,"y":0},"static":false,"id":393},{"material":"water","p":{"x":600,"y":-354.5069252077562},"v":{"x":0,"y":0},"static":false,"id":394},{"material":"water","p":{"x":898,"y":-221.3227146814404},"v":{"x":0,"y":0},"static":false,"id":395},{"material":"water","p":{"x":929,"y":-191.28116343490296},"v":{"x":0,"y":0},"static":false,"id":396},{"material":"water","p":{"x":961,"y":-171.2520775623268},"v":{"x":0,"y":0},"static":false,"id":397},{"material":"water","p":{"x":1006,"y":-154.22991689750688},"v":{"x":0,"y":0},"static":false,"id":398},{"material":"water","p":{"x":1052,"y":-145.2160664819944},"v":{"x":0,"y":0},"static":false,"id":399},{"material":"water","p":{"x":1083,"y":-143.21329639889188},"v":{"x":0,"y":0},"static":false,"id":400},{"material":"water","p":{"x":1113,"y":-142.21191135734068},"v":{"x":0,"y":0},"static":false,"id":401},{"material":"water","p":{"x":1143,"y":-142.21191135734068},"v":{"x":0,"y":0},"static":false,"id":402},{"material":"water","p":{"x":1174,"y":-142.21191135734068},"v":{"x":0,"y":0},"static":false,"id":403},{"material":"water","p":{"x":1206,"y":-141.21052631578937},"v":{"x":0,"y":0},"static":false,"id":404},{"material":"water","p":{"x":1236,"y":-138.20775623268696},"v":{"x":0,"y":0},"static":false,"id":405},{"material":"water","p":{"x":1275,"y":-138.20637119113564},"v":{"x":0,"y":0},"static":false,"id":406},{"material":"water","p":{"x":1317,"y":-143.21329639889188},"v":{"x":0,"y":0},"static":false,"id":407},{"material":"water","p":{"x":1353,"y":-150.22437673130185},"v":{"x":0,"y":0},"static":false,"id":408},{"material":"water","p":{"x":1390,"y":-155.23130193905808},"v":{"x":0,"y":0},"static":false,"id":409},{"material":"water","p":{"x":1424,"y":-160.23684210526312},"v":{"x":0,"y":0},"static":false,"id":410},{"material":"water","p":{"x":1474,"y":-167.24653739612188},"v":{"x":0,"y":0},"static":false,"id":411},{"material":"water","p":{"x":1502,"y":-167.24792243767308},"v":{"x":0,"y":0},"static":false,"id":412},{"material":"water","p":{"x":1538,"y":-168.24792243767308},"v":{"x":0,"y":0},"static":false,"id":413},{"material":"water","p":{"x":1581,"y":-165.24515235457056},"v":{"x":0,"y":0},"static":false,"id":414},{"material":"water","p":{"x":1647,"y":-171.2520775623268},"v":{"x":0,"y":0},"static":false,"id":415},{"material":"water","p":{"x":1679,"y":-177.26038781163425},"v":{"x":0,"y":0},"static":false,"id":416},{"material":"water","p":{"x":1722,"y":-179.26454293628808},"v":{"x":0,"y":0},"static":false,"id":417},{"material":"water","p":{"x":1657,"y":-196.2880886426592},"v":{"x":0,"y":0},"static":false,"id":418},{"material":"water","p":{"x":1514,"y":-200.29224376731298},"v":{"x":0,"y":0},"static":false,"id":419},{"material":"water","p":{"x":1446,"y":-205.29916897506922},"v":{"x":0,"y":0},"static":false,"id":420},{"material":"water","p":{"x":1382,"y":-210.30609418282546},"v":{"x":0,"y":0},"static":false,"id":421},{"material":"water","p":{"x":1332,"y":-213.31024930747918},"v":{"x":0,"y":0},"static":false,"id":422},{"material":"water","p":{"x":1279,"y":-215.31301939058164},"v":{"x":0,"y":0},"static":false,"id":423},{"material":"water","p":{"x":1236,"y":-221.32132963988914},"v":{"x":0,"y":0},"static":false,"id":424},{"material":"water","p":{"x":1189,"y":-221.32132963988914},"v":{"x":0,"y":0},"static":false,"id":425},{"material":"water","p":{"x":1137,"y":-216.3144044321329},"v":{"x":0,"y":0},"static":false,"id":426},{"material":"water","p":{"x":1091,"y":-210.30609418282546},"v":{"x":0,"y":0},"static":false,"id":427},{"material":"water","p":{"x":1044,"y":-205.30055401662042},"v":{"x":0,"y":0},"static":false,"id":428},{"material":"water","p":{"x":1002,"y":-208.3047091412742},"v":{"x":0,"y":0},"static":false,"id":429},{"material":"water","p":{"x":975,"y":-211.30886426592792},"v":{"x":0,"y":0},"static":false,"id":430},{"material":"water","p":{"x":1408,"y":-221.32132963988914},"v":{"x":0,"y":0},"static":false,"id":431},{"material":"water","p":{"x":1495,"y":-232.33795013850408},"v":{"x":0,"y":0},"static":false,"id":432},{"material":"water","p":{"x":1528,"y":-240.34764542936284},"v":{"x":0,"y":0},"static":false,"id":433},{"material":"water","p":{"x":1564,"y":-242.35180055401656},"v":{"x":0,"y":0},"static":false,"id":434},{"material":"water","p":{"x":1614,"y":-243.35180055401656},"v":{"x":0,"y":0},"static":false,"id":435},{"material":"water","p":{"x":1641,"y":-243.35318559556782},"v":{"x":0,"y":0},"static":false,"id":436},{"material":"water","p":{"x":1669,"y":-248.36011080332406},"v":{"x":0,"y":0},"static":false,"id":437},{"material":"water","p":{"x":1617,"y":-274.3947368421052},"v":{"x":0,"y":0},"static":false,"id":438},{"material":"water","p":{"x":1580,"y":-282.4058171745152},"v":{"x":0,"y":0},"static":false,"id":439},{"material":"water","p":{"x":1503,"y":-291.41966759002764},"v":{"x":0,"y":0},"static":false,"id":440},{"material":"water","p":{"x":1440,"y":-292.4210526315789},"v":{"x":0,"y":0},"static":false,"id":441},{"material":"water","p":{"x":1379,"y":-288.4155124653739},"v":{"x":0,"y":0},"static":false,"id":442},{"material":"water","p":{"x":1318,"y":-284.40997229916894},"v":{"x":0,"y":0},"static":false,"id":443},{"material":"water","p":{"x":1252,"y":-278.40166204986144},"v":{"x":0,"y":0},"static":false,"id":444},{"material":"water","p":{"x":1162,"y":-262.37811634349026},"v":{"x":0,"y":0},"static":false,"id":445},{"material":"water","p":{"x":1102,"y":-256.371191135734},"v":{"x":0,"y":0},"static":false,"id":446},{"material":"water","p":{"x":1042,"y":-251.36426592797778},"v":{"x":0,"y":0},"static":false,"id":447},{"material":"water","p":{"x":995,"y":-249.36149584487532},"v":{"x":0,"y":0},"static":false,"id":448},{"material":"water","p":{"x":959,"y":-246.35595567867034},"v":{"x":0,"y":0},"static":false,"id":449},{"material":"water","p":{"x":926,"y":-240.3490304709141},"v":{"x":0,"y":0},"static":false,"id":450},{"material":"snow","p":{"x":798,"y":-420.59695290858724},"v":{"x":0,"y":0},"static":false,"id":451},{"material":"snow","p":{"x":761,"y":-433.61495844875344},"v":{"x":0,"y":0},"static":false,"id":452},{"material":"snow","p":{"x":718,"y":-440.6260387811634},"v":{"x":0,"y":0},"static":false,"id":453},{"material":"snow","p":{"x":690,"y":-437.6218836565097},"v":{"x":0,"y":0},"static":false,"id":454},{"material":"snow","p":{"x":639,"y":-431.6121883656509},"v":{"x":0,"y":0},"static":false,"id":455},{"material":"snow","p":{"x":600,"y":-427.6080332409972},"v":{"x":0,"y":0},"static":false,"id":456},{"material":"snow","p":{"x":567,"y":-427.60664819944594},"v":{"x":0,"y":0},"static":false,"id":457},{"material":"snow","p":{"x":850,"y":-449.6385041551246},"v":{"x":0,"y":0},"static":false,"id":458},{"material":"snow","p":{"x":831,"y":-481.68144044321326},"v":{"x":0,"y":0},"static":false,"id":459},{"material":"snow","p":{"x":803,"y":-486.68975069252076},"v":{"x":0,"y":0},"static":false,"id":460},{"material":"snow","p":{"x":771,"y":-494.6994459833795},"v":{"x":0,"y":0},"static":false,"id":461},{"material":"snow","p":{"x":721,"y":-501.7105263157895},"v":{"x":0,"y":0},"static":false,"id":462},{"material":"snow","p":{"x":691,"y":-508.7202216066482},"v":{"x":0,"y":0},"static":false,"id":463},{"material":"snow","p":{"x":662,"y":-511.72437673130196},"v":{"x":0,"y":0},"static":false,"id":464},{"material":"snow","p":{"x":625,"y":-507.7188365650969},"v":{"x":0,"y":0},"static":false,"id":465},{"material":"snow","p":{"x":597,"y":-479.6786703601108},"v":{"x":0,"y":0},"static":false,"id":466},{"material":"snow","p":{"x":581,"y":-452.64127423822714},"v":{"x":0,"y":0},"static":false,"id":467},{"material":"snow","p":{"x":765,"y":-467.6620498614958},"v":{"x":0,"y":0},"static":false,"id":468},{"material":"snow","p":{"x":698,"y":-409.58310249307476},"v":{"x":0,"y":0},"static":false,"id":469},{"material":"snow","p":{"x":812,"y":-456.6468144044321},"v":{"x":0,"y":0},"static":false,"id":470},{"material":"snow","p":{"x":797,"y":-529.7493074792244},"v":{"x":0,"y":0},"static":false,"id":471},{"material":"snow","p":{"x":760,"y":-553.7825484764543},"v":{"x":0,"y":0},"static":false,"id":472},{"material":"snow","p":{"x":722,"y":-567.8019390581717},"v":{"x":0,"y":0},"static":false,"id":473},{"material":"snow","p":{"x":691,"y":-571.8074792243767},"v":{"x":0,"y":0},"static":false,"id":474},{"material":"snow","p":{"x":655,"y":-562.7950138504154},"v":{"x":0,"y":0},"static":false,"id":475},{"material":"snow","p":{"x":613,"y":-532.7520775623268},"v":{"x":0,"y":0},"static":false,"id":476},{"material":"snow","p":{"x":614,"y":-456.6481994459833},"v":{"x":0,"y":0},"static":false,"id":477},{"material":"snow","p":{"x":695,"y":-470.66759002770084},"v":{"x":0,"y":0},"static":false,"id":478}]'; | |
} | |
/* | |
menambahkan material. Jika materialnya sudah disimpan tambahkan... | |
jika belum... load dari introlevel (mula-mula on enter frame ) | |
Untuk material yang keras (kayu, besi, tanah ) sifatnyas static jadi | |
densitas dibuat nol.... sementara Untuk Material lainnya semisal air, oli, | |
dan lain-lain.... nilai kecepatannya diload... | |
*/ | |
function loadLvl(name) | |
{ | |
delJoints(); | |
delCircles(); | |
name = name || 'lvl'; | |
var lvl = localStorage[name]; | |
if (name=='introlevel') | |
lvl = introlevel(); | |
if (!lvl) lvl = '[]'; | |
lvl = JSON.parse(lvl); | |
$.each(lvl, function(i, o) | |
{ | |
// not in old saves | |
//if (!o.isCircle) return; | |
if (o.isJoint) return; | |
var c = new Circle(o.material, o.p.x, o.p.y); | |
if (o.static) | |
c.setDensity(0); | |
else | |
c.v = v2copy(o.v); | |
c.load_id = o.id; | |
circles.push(c); | |
}); | |
$.each(lvl, function(i, o) | |
{ | |
if (!o.isJoint) return; | |
var a = getLoadId(o.a_id); | |
var b = getLoadId(o.b_id); | |
if (hasJoint(a, b)) | |
return console.log('wtf, bad lvl, has duplicate joint'); | |
a.connect(b); | |
}); | |
nicelog('loaded '+name); | |
resetCam(); | |
} | |
function saveLvl(bConfirm, name) | |
{ | |
nullShiftCtrlAlt(); | |
if (bConfirm) | |
{ | |
if (!confirm('really save?')) return; | |
} | |
name = name || 'lvl'; | |
var lvl=[]; | |
$.each(circles, function(i, c) | |
{ | |
lvl.push({ | |
material: c.m.name, | |
p: c.p, | |
v: c.v, | |
static: !c.mass, | |
id: c.id, | |
}); | |
}) | |
$.each(joints, function(i, j) | |
{ | |
lvl.push({ | |
isJoint: true, | |
a_id: j.A.id, | |
b_id: j.B.id, | |
}); | |
}) | |
localStorage[name] = JSON.stringify(lvl); | |
nicelog('saved'); | |
} | |
function doByArgs(fn, first, orOther) | |
{ | |
// is material name? | |
if (typeof first == 'string') | |
{ | |
var mName = first; | |
$.each(circles, function(i, c) | |
{ | |
if (c.m.name == mName) | |
fn(c); | |
}); | |
return true; | |
} | |
var arr = []; | |
if (first instanceof Array) | |
arr = first; | |
if (!arr.length && orOther instanceof Array) | |
arr = orOther; | |
$.each(arr, function(i, c) | |
{ | |
fn(c); | |
}); | |
//nicelog('processed ',arr.length,' items - so it shouldnt check "pressed twice"'); | |
if (arr.length) return true; | |
} | |
// 1 object: solidify(circle0) | |
// by material: solidify('dirt') | |
// array: solidify(getGrasping()) | |
// solidify(circles) | |
// array or other: solidify(getGrasping(), circles) | |
var lastPressTimes = {}; | |
function pressedTwiceInSecond(sName) | |
{ | |
var now = time(); | |
var t = lastPressTimes[sName]; | |
if (!t || (now - t) > 1000) | |
{ | |
lastPressTimes = {}; | |
lastPressTimes[sName] = now; | |
return false; | |
} | |
lastPressTimes = {}; | |
return true; | |
} | |
function currentlyInLastSec() | |
{ | |
if (!lastPressTimes) return ''; | |
var name = ''; | |
$.each(lastPressTimes, function(k, o) | |
{ | |
var elapsed = time() - o; | |
if (elapsed < 1000) name = k; | |
}); | |
return name; | |
} | |
function solidify(c, arr) | |
{ | |
if (c instanceof Circle) | |
return c.setDensity(0); | |
if (!doByArgs(solidify, c, arr) && pressedTwiceInSecond('solidify')) | |
doByArgs(solidify, circles); | |
} | |
function dynamify(c, arr) | |
{ | |
if (c instanceof Circle) | |
return c.setDensity(c.m.density); | |
if (!doByArgs(dynamify, c, arr) && pressedTwiceInSecond('dynamify')) | |
doByArgs(dynamify, circles); | |
} | |
function meld(c, arr) | |
{ | |
if (c instanceof Circle) | |
return c.checkNewJoints(); | |
if (!doByArgs(meld, c, arr) && pressedTwiceInSecond('meld')) | |
doByArgs(meld, circles); | |
} | |
function unmeld(c, arr) | |
{ | |
if (c instanceof Circle) | |
return c.unmeld(); | |
if (!doByArgs(unmeld, c, arr) && pressedTwiceInSecond('unmeld')) | |
doByArgs(unmeld, circles); | |
} | |
function remove(c, arr) | |
{ | |
if (c instanceof Circle) | |
return c.remove(); | |
if (!doByArgs(remove, c, arr) && pressedTwiceInSecond('remove')) | |
doByArgs(remove, circles); | |
} | |
/* | |
*/ | |
function getSprite(name, size, frames) | |
{ | |
if (sprites[name]) | |
return sprites[name]; | |
frames = frames || 1; | |
size = size || badSprite; | |
var spr = { | |
name: name, | |
fname: 'i/'+name+'.png', | |
size: size, | |
}; | |
var bd = new BitmapData(spr.fname, frames); | |
spr.bmpData = bd | |
spr.newBitmap = function() | |
{ | |
if (bd.frames > 1) return new MBitmap(bd); | |
else return new Bitmap(bd); | |
} | |
sprites[name] = spr; | |
return spr; | |
} | |
function isFixed(a) | |
{ | |
return (a.toFixed() == a); | |
} | |
function nullShiftCtrlAlt() | |
{ | |
kd['SHIFT'] = 0; | |
kd['CTRL'] = 0; | |
kd['ALT'] = 0; | |
} | |
function extractDelta(e) | |
{ | |
if (e.wheelDelta) return e.wheelDelta; | |
if (e.detail) return e.detail * -40; | |
if (e.originalEvent && e.originalEvent.wheelDelta) | |
return e.originalEvent.wheelDelta; | |
} | |
$(document).bind('mousewheel DOMMouseScroll', function (e) { | |
var d = extractDelta(e); | |
if (onMouseWheel) | |
onMouseWheel(d); | |
}); | |
// ready | |
$(function() | |
{ | |
start(); | |
//setTimeout(onRESIZE, 100); | |
//setTimeout(onRESIZE, 200); // otherwise it somehow doesnt work :/ | |
onRESIZE(); | |
resetCam(); | |
nullShiftCtrlAlt(); | |
$('#sliders').hover( | |
function() { $(this).css('opacity', 1) }, | |
function() { $(this).css('opacity', 0) } | |
); | |
if (0) | |
{ | |
addSlider('g_f1', 0, 2, 0.01); | |
addSlider('g_f2', 0, 2, 0.01); | |
addSlider('g_f3', 0, 2, 0.01); | |
addSlider('g_f4', 0, 2, 0.01); | |
addSlider(); | |
} | |
/* | |
addSlider('g_maxLinks', 0, 9, 1); | |
addSlider('g_sphRestDensity', 0.1, 5, 0.1, 'log'); | |
addSlider('g_timeMult', 0.0, 5.0, 0.005); | |
addSlider('g_sprK', 0, 255000, 20); | |
addSlider('g_sprDamp', 0, 200); | |
addSlider('g_drawGrid', 0, 1); | |
addSlider('g_useGrid', 0, 1); | |
addSlider('g_skipJointCollision', 0, 1); | |
*/ | |
addSlider('g_gravity', 0, 9, 1); | |
addSlider('g_drawHeat', 0, 1); | |
addSlider('g_HeatMax', 0.1, 1000, 0.1, 'log'); | |
addSlider('g_jointWidth', 0, 4, 1); | |
addSlider(); | |
addSlider('g_nonsphPress', 100, 999999); | |
addSlider('g_nonsphPressNear', 100, 999999); | |
addSlider('g_sphQ2', 0.5, 5, 0.1); | |
addSlider('g_sphQ3', 0.5, 5, 0.1); | |
addSlider('g_sphQmult', 0.5, 5, 0.1); | |
//$('.slider_g_timeMult > a').focus(); | |
function addSlider(evalName, mn, mx, step, logarithmic) | |
{ | |
var sliders = $('#sliders'); | |
if (!evalName) | |
return sliders.append('<br>'); | |
if (mn>=1 && mx/mn >= 50000) | |
logarithmic = 1; | |
if (logarithmic) | |
{ | |
mn = loge(mn); | |
mx = loge(mx); | |
step = 0.001; | |
} | |
step = step || 1; | |
if (!isFixed(mn) || !isFixed(mx)) | |
step = minmax(mn, 0.001, (mx-mn)/100+0.01); | |
$('<span></span>').appendTo(sliders); | |
var slider = $('<div>').appendTo(sliders); | |
slider.width(200); | |
slider.addClass('slider_'+evalName); | |
function fnSlide(ev, ui) | |
{ | |
var v = ui.value; | |
if (logarithmic) | |
{ | |
v = powe(v); | |
if (v < 5) v = v.toFixed(2); | |
else v = v.toFixed(0); | |
} | |
eval(evalName+' = v'); | |
$(this).prev().text(evalName+': '+v); | |
} | |
var val = eval(evalName); | |
mn = min(mn, val); | |
mx = max(mx, val); | |
slider.slider({ | |
min:mn, | |
max:mx, | |
step: step, | |
change: fnSlide, | |
slide: fnSlide, | |
}); | |
var currVal = eval(evalName); | |
if (logarithmic) | |
currVal = loge(currVal); | |
slider.slider( {value: currVal} ); | |
} | |
}); | |
//$(window).resize(onRESIZE); | |
function onRESIZE() | |
{ | |
bgScaleOnResize(); | |
updateStageTransform(); | |
} | |
function bgScaleOnResize() | |
{ | |
var doItLater = 0; | |
var w = stage.stageWidth; | |
var h = stage.stageHeight; | |
if (bgImage) | |
{ | |
var bg = bgImage; | |
var d = bg.bitmapData; | |
if (d.width) | |
{ | |
bg.scaleX = stage.stageWidth / d.width; | |
bg.scaleY = stage.stageHeight / d.height; | |
var mx = max(bg.scaleX, bg.scaleY); | |
bg.scaleX = mx; | |
bg.scaleY = mx; | |
} | |
else | |
doItLater = 1; | |
} | |
if (bgClr) | |
{ | |
var sz = 50000; | |
// sky | |
var cSky = 0x99bbee; | |
var cDirt = 0x64533e; | |
var cc = 0 ? cDirt : cSky; | |
bgClr.graphics.beginFill(cc); | |
bgClr.graphics.drawRect(-sz/2, 0, sz, -sz/2); | |
// bottom with rock-color | |
bgClr.graphics.beginFill(0x777777); // rocks | |
bgClr.graphics.drawRect(-sz/2, 0, sz, sz/4); | |
if (!'show start rect') { | |
bgClr.graphics.beginFill(0xff0000, 0.1); // beginning screen | |
bgClr.graphics.drawRect(0, 0, w, -h); | |
} | |
} | |
if (doItLater) | |
setTimeout(bgScaleOnResize, 10); | |
} | |
function processSound(type, A, B) | |
{ | |
return; | |
if (A == c0 || B == c0) | |
{ | |
if (v2len(c0.v) > 500) | |
$('.'+type)[rndi(4)].play(); | |
} | |
} | |
var pairs = []; | |
function addPair(a, b) | |
{ | |
pairs.push( {A:a, B:b} ); | |
} | |
function Circle(material, x, y) | |
{ | |
if (typeof material == 'string') | |
material = g_materials[material]; | |
if (!material) material = g_materials['default']; | |
x = x || 0; | |
y = y || 0; | |
var A = this; | |
g_lastUsedObj = this; | |
A.p = v2(x, y); | |
A.v = v2(0, 0); | |
A.m = material; | |
A.sph = A.m.isSph; | |
A.r = rnd(g_radius) + g_radius; | |
A.links = []; | |
A.sprite = getSprite(A.m.sprite); | |
A.spriteHeat = null; // used if !null, use drawHeat(true/false) | |
A.o = A.sprite.newBitmap(); | |
stage.addChild(A.o); | |
A.setDensity = function(fDens) // 0=static | |
{ | |
var r = A.sph ? 1 : g_radius; | |
r = g_radius; | |
A.mass = fDens * (r*r * 3.14159); // untuk besi, kayu, batu... nilai massa = nol... karena density = 0 | |
A.invM = A.mass > 0 ? 1/A.mass : 0; | |
A.v = v2(0, 0); | |
} | |
A.rigidRadius = function() | |
{ | |
if (A.sph) return g_sphRadius; // SPHM | |
return g_radius; | |
} | |
A.setDensity(A.m.density); // A.mass + A.invM | |
A.id = g_freeCircleId++; | |
A.order = A.id; // will be changed frequently, see sortFromDynamics | |
A.setStatic = function() | |
{ | |
A.setDensity(0); | |
} | |
A.unsetHeat = function() | |
{ | |
A.drawHeat(false); | |
} | |
A.setHeat = function(f) | |
{ | |
A.drawHeat(true); | |
if (!isOk(f)) f = 0; | |
f = abs(f); | |
f = minmax(f, 0, 1); | |
A.o.currentFrame = to_i(f*31); | |
} | |
A.drawHeat = function(enable) | |
{ | |
if (enable && A.spriteHeat || | |
!enable && !A.spriteHeat) | |
return; | |
if (A.o) stage.removeChild(A.o); | |
if (!enable) | |
{ | |
A.spriteHeat = null; | |
A.o = A.sprite.newBitmap(); | |
} | |
else | |
{ | |
A.spriteHeat = getSprite('heat'); | |
A.o = A.spriteHeat.newBitmap(); | |
} | |
A.updateEngineScale(); | |
stage.addChild(A.o); | |
}; | |
A.updateEngineScale = function() | |
{ | |
var spr = A.spriteHeat ? A.spriteHeat : A.sprite; | |
var sprMult = g_radius / spr.size * A.m.spriteScale; | |
A.offsetRadius = A.o.bitmapData.width * sprMult; | |
A.o.scaleX = 2 * sprMult; | |
A.o.scaleY = 2 * sprMult; | |
} | |
A.unmeld = function() | |
{ | |
$.each(joints, function(i, j) | |
{ | |
if (j.has(A)) | |
j.remove(); | |
}); | |
} | |
A.remove = function() | |
{ | |
if (g_lastUsedObj === A) | |
g_lastUsedObj = null; | |
if (A.removed) return; | |
A.unmeld(); | |
stage.removeChild(A.o); | |
A.removed = true; | |
} | |
A.prepareRK = function() | |
{ | |
A.a = v2(0, 0); | |
A.a1 = v2(0, 0); | |
A.a2 = v2(0, 0); | |
A.a3 = v2(0, 0); | |
A.a4 = v2(0, 0); | |
} | |
A.updateEngineData = function() | |
{ | |
// toto by stacilo zavolat raz po nacitani textur, len neviem kam to dat | |
// a inak by to nemalo moc zrat.. | |
A.updateEngineScale(); | |
A.o.x = A.p.x - A.offsetRadius; | |
A.o.y = A.p.y - A.offsetRadius; | |
} | |
A.gravity = function() | |
{ | |
if (!A.mass) return; | |
var g = v2mult(g_nGravity, g_gravity*dt*1000); | |
v2addMe(A.v, g); | |
} | |
A.fixBrokenVelocityPosition = function() | |
{ | |
if (!A.mass) return; | |
if (!isOk(A.p.x)) A.p.x = 100; | |
if (!isOk(A.p.y)) A.p.y = 100; | |
if (!isOk(A.v.x)) A.v.x = 0; | |
if (!isOk(A.v.y)) A.v.y = 0; | |
} | |
A.moveByVelocity = function() | |
{ | |
if (!A.mass) | |
{ | |
if (A.v.x || A.v.y) console.error('static object has velocity!'); | |
return; | |
} | |
if (A.m.velocityDamp) | |
{ | |
var dmp = A.m.velocityDamp * dt; | |
if (dmp > 1) dmp = 0.99; | |
v2subMe(A.v, v2mult(A.v, dmp)); | |
} | |
if (A.impulses && (A.impulses.x || A.impulses.y)) | |
{ | |
v2addMe(A.v, v2mult(A.impulses, 1) ); // or *dtFrame ? | |
A.impulses = v2(0, 0); | |
} | |
A.v.x = absmin(A.v.x, g_maxVelLimit); | |
A.v.y = absmin(A.v.y, g_maxVelLimit); | |
g_currMaxVel2 = max(v2len2(A.v), g_currMaxVel2); | |
if (A.movedByRk) | |
{ | |
A.movedByRk = 0; | |
return; | |
} | |
A.p.x += A.v.x * dt; | |
A.p.y += A.v.y * dt; | |
} | |
A.calcVelocityFromDisplacement = function() | |
{ | |
if (!A.mass || !dt || !A.sph) | |
return; | |
if (!A.pOld) | |
A.pOld = v2copy(A.p); | |
if (A.sph) | |
{ | |
A.v = v2div(v2sub(A.p, A.pOld), dt); | |
A.pOld = v2copy(A.p); | |
} | |
} | |
A.frameStart = function() | |
{ | |
A.sphDens = 0; | |
A.sphDensNear = 0; | |
A.v_ = v2(0, 0); | |
/* | |
if (!A.vOld) A.vOld = v2(0, 0); | |
A.vOld = v2c(A.v); | |
if (dt) | |
A.acc = v2sub(A.vOld, A.v)/dt; | |
*/ | |
// dbg | |
A._seqI=0; | |
A._seqIabs=0; | |
} | |
A.findPairs = function() | |
{ | |
// cant use rigid radius here, cos some pairs are from smooth particles | |
var dynOnly = !A.mass; | |
var r = A.sph ? g_sphRadius : g_radius; | |
var chk = getNearby(A.p, r, A.order, dynOnly); | |
for (var i=0; i < chk.length; i++) | |
{ | |
var B = chk[i]; | |
if (A == B) continue; | |
frame_collision_checks++; | |
// show what pairs does getNearby return | |
//drawLine(A.p, B.p, 'f00'); | |
if (!A.mass && !B.mass) continue; | |
if (g_skipJointCollision) | |
if (A.isLinked(B)) continue; | |
var maxDist; | |
if (!A.sph && !B.sph) maxDist = g_radius*2; | |
else maxDist = g_sphRadius*2; | |
if ( v2isCloserThan(A.p, B.p, maxDist) ) | |
addPair(A, B); | |
else | |
;//nullContact(A, B); | |
} | |
} | |
A.sphCalculateDensity = function(B, p) | |
{ | |
//if (!A.sph && !B.sph) return; | |
var maxRange = g_sphRadius*2; | |
var d = v2dist(A.p, B.p); // hitung jarak partikel saat ini dengan | |
// partikel B | |
p.q = 1 - d / maxRange; | |
if (p.q < 0) p.q = 0; | |
p.q *= g_sphQmult; | |
p.q = min(p.q, 1); | |
p.q2 = pow(p.q, g_sphQ2); | |
p.q3 = pow(p.q, g_sphQ3); | |
A.sphDens += p.q2; | |
B.sphDens += p.q2; | |
A.sphDensNear += p.q3; | |
B.sphDensNear += p.q3; | |
p.a2b = d; | |
} | |
// A.m.sphStiff * (A.sphDens - A.m.sphRestDensity); | |
A.pressure_ = function() { return A.m.sphStiff * A.sphDens; } | |
A.pressureNear_ = function() { return A.m.sphStiffNear * A.sphDensNear; } | |
A.sphCalculatePressure = function() | |
{ | |
if (A.sph) | |
{ | |
A.pressure = A.pressure_(); | |
A.pressureNear = A.pressureNear_(); | |
} | |
else | |
{ | |
A.pressure = g_nonsphPress; | |
A.pressureNear = g_nonsphPressNear; | |
} | |
if (0 &&A.sph) { | |
drawCircleO(A.p, A.pressure/100, 'f00'); | |
drawCircleO(A.p, A.pressureNear/100, '00f'); | |
} | |
g_avgSphDensity += A.sphDens; | |
g_numSph++; | |
} | |
A.sphSolve = function(B, p) | |
{ | |
//processSound('splash', A, B); | |
if (g_maxPressure < A.pressure) | |
g_maxPressure = A.pressure; | |
if (g_maxPressureNear < A.pressureNear) | |
g_maxPressureNear = A.pressureNear; | |
if (!A.pressure) A.pressure = 9999; | |
if (!B.pressure) B.pressure = 9999; | |
if (!A.pressureNear) A.pressureNear = 33333; | |
if (!B.pressureNear) B.pressureNear = 33333; | |
var press = A.pressure + B.pressure; | |
var pressN = A.pressureNear + B.pressureNear; | |
var fDisp = (press*p.q2 + pressN*p.q3); | |
fDisp *= dt * dt; | |
if (g_drawContacts) | |
{ | |
var clr = heatclr(pressN/130000); | |
if (!A.sph || !B.sph) | |
drawLine(A.p, B.p, clr); | |
} | |
if (!p.a2b) p.a2b = 1; | |
var a2bN = v2div(v2sub(B.p, A.p), p.a2b); | |
var vDisp = v2mult(a2bN, -fDisp); | |
v2divMe( vDisp, (A.invM+B.invM) ); | |
return vDisp; | |
} | |
A.rigidSolve = function(B, p) | |
{ | |
processSound('puk', A, B); | |
var vF = collideForce(A, B); | |
if (1) | |
{ | |
v2addMe(A.v, v2mult(vF, A.invM) ); | |
v2subMe(B.v, v2mult(vF, B.invM) ); | |
return v2(0, 0); | |
} | |
return v2mult(vF, dt); | |
} | |
A.solveCollision = function(B, p) | |
{ | |
frame_collisions++; | |
var vDisp; | |
if (A.sph || B.sph) | |
vDisp = A.sphSolve(B, p); | |
else | |
vDisp = A.rigidSolve(B, p); | |
if (!dt) return; | |
if (A.active) { | |
if (A.sph) v2addMe( A.p, v2mult(vDisp, A.invM) ); | |
else v2addMe( A.v, v2mult(vDisp, A.invM/dt) ); | |
} | |
if (B.active) { | |
if (B.sph) v2subMe( B.p, v2mult(vDisp, B.invM) ); | |
else v2subMe( B.v, v2mult(vDisp, B.invM/dt) ); | |
} | |
} | |
A.odrazOdStran = function() | |
{ | |
if (!A.mass) return; | |
if (!dt) return; | |
var r = A.rigidRadius(); | |
var w = stage.stageWidth - r; | |
var h = stage.stageHeight - r; | |
var fRestitution = 1; | |
var fMoveBackRatio = 0.5; | |
if (A.p.y > -r) | |
{ | |
var d = -A.p.y - r; | |
A.p.y += d * fMoveBackRatio; | |
A.v.y = -abs(A.v.y * fRestitution); | |
} | |
} | |
A.linksMaxed = function() | |
{ | |
return (g_maxLinks && A.links.length >= g_maxLinks); | |
} | |
A.checkNewJoints = function(bOnlyCheckLaterOrder) | |
{ | |
var order = -1; | |
if (bOnlyCheckLaterOrder) order = A.order; | |
//if (!A.mass) return; | |
if (A.m.name == 'water') return; | |
if (A.linksMaxed()) return; | |
var chk = getNearby(A.p, g_radius*1.5, order); | |
for (var i=0; i < chk.length; i++) | |
{ | |
var B = chk[i]; | |
if (A == B) continue; | |
frame_spring_checks++; | |
if (!A.mass && !B.mass) continue; | |
//if (!B.mass) continue; | |
if (A.isLinked(B)) continue; | |
if (B.linksMaxed()) continue; | |
if (g_meldOnlySameMaterial) | |
if (B.m != A.m) continue; | |
var lenMeld = A.sprMeld(B); | |
if ( !v2isFurtherThan(A.p, B.p, lenMeld) ) | |
A.connect(B); | |
} | |
} | |
// 'b' is other object | |
A.sprLen = function(B) { | |
return (A.rigidRadius() + B.rigidRadius())*g_sprLenRatio; | |
} | |
A.sprMax = function(B) { | |
return A.sprLen(B)*9999;//g_sprMax; | |
} | |
A.sprMeld = function(B) { | |
return A.sprLen(B)*min(g_sprMax, 1.5); | |
} | |
A.isLinked = function(B) | |
{ | |
for (var i=0; i < A.links.length; i++) | |
{ | |
if (A.links[i] == B) | |
return true; | |
} | |
} | |
A.connect = function(B) | |
{ | |
console.assert( !A.isLinked(B) ); | |
A.links.push(B); | |
B.links.push(A); | |
joints.push( new Joint(A, B) ); | |
} | |
// this is called by joints | |
A.remove_connection_to = function(B) | |
{ | |
for (var i=0; i < A.links.length; i++) | |
{ | |
if (A.links[i] == B) | |
return removeAt(A.links, i); | |
} | |
} | |
A.unmeld = function() | |
{ | |
$.each(joints, function(i, j) | |
{ | |
if (j.has(A)) | |
j.remove(); | |
}); | |
} | |
A.impulse = function(vI) | |
{ | |
if (!A.mass) return; | |
if (!A.impulses) A.impulses = v2(0, 0); | |
v2addMe(A.impulses, v2mult(vI, dtFrame*1000) ); | |
} | |
} | |
function hasJoint(a, b) | |
{ | |
var has = 0; | |
$.each(joints, function(i, j) { | |
if (!j.has(a, b)) return; | |
has = true; | |
return false; | |
}); | |
return has; | |
} | |
function Joint(A, B) | |
{ | |
if (DEBUG) | |
{ | |
if (A === B) | |
console.log('a == b - wtf joint'); | |
if (hasJoint(A, B)) | |
console.log('has(a, b) already exists - wtf joint'); | |
} | |
var j = this; | |
j.A = A; | |
j.B = B; | |
j.dbg_drawJoints = function() | |
{ | |
var sprLen = A.rigidRadius() + B.rigidRadius(); | |
var dist = v2dist(A.p, B.p); | |
var f = (dist - sprLen) / (sprLen*g_sprMax - sprLen); | |
f = minmax(f, -1, 1); | |
f = abs(f); | |
f = 1-f; | |
f = f*f*f*f; | |
f = 1-f; | |
f = parseInt(f*255); | |
var green = 255-f; | |
var red = f; | |
var clr = red*256*256 + green*256; | |
var ax = A.p.x, ay=A.p.y; | |
var bx = B.p.x, by=B.p.y; | |
drawLine(ax, ay, bx, by, clr, g_jointWidth); | |
} | |
// i = 1,2,3,4 | |
j.updateRK = function(i) | |
{ | |
if (!A.mass && !B.mass) return; | |
if (!dt) return; | |
var t = dt; | |
switch (i) { | |
case 1: t *= 0; | |
break; | |
case 2: | |
case 3: t *= 0.5; | |
break; | |
case 4: t *= 1; | |
break; | |
} | |
var q = i-1; // previous index | |
var vq = 'v'+q; | |
var aq = 'a'+q; | |
var pi = 'p'+i; | |
var vi = 'v'+i; | |
var ai = 'a'+i; | |
A[pi] = v2c(A.p); | |
B[pi] = v2c(B.p); | |
A[vi] = v2c(A.v); | |
B[vi] = v2c(B.v); | |
if (q) | |
{ | |
v2addMe(A[pi], v2mult(A[vq], t)); | |
v2addMe(B[pi], v2mult(B[vq], t)); | |
v2addMe(A[vi], v2mult(A[aq], t)); | |
v2addMe(B[vi], v2mult(B[aq], t)); | |
} | |
var a = dampspringForce_pv(A[pi], A[vi], B[pi], B[vi], A.sprLen(B), g_sprK, g_sprDamp); | |
v2divMe(a, A.invM+B.invM) | |
v2addMe(A[ai], v2mult(a, A.invM)); | |
v2subMe(B[ai], v2mult(a, B.invM)); | |
//j.dbgRK(i, a); | |
} | |
j.dbgRK = function(i, a) | |
{ | |
var w = 1; | |
var fa = 0.0005; | |
var fv = 0.05; | |
var off = (i+1)*20; | |
if (!i) i = ''; | |
var aa = v2mult(A['a'+i], fa); | |
var ba = v2mult(B['a'+i], fa); | |
var av = v2mult(A['v'+i], fv); | |
var bv = v2mult(B['v'+i], fv); | |
var ap = v2c(A['p'+i]); | |
var bp = v2c(B['p'+i]); | |
var pp = v2center(ap, bp); | |
v2addMexy(ap, off, 0); | |
v2addMexy(bp, off+10, 0); | |
//if (a) drawLineN(pp, v2perp(a, fa*-0.001), 'f00', 1); | |
//drawLineN(ap, aa, 'f00', w); | |
//drawLineN(bp, ba, '0f0', w); | |
v2addMex(ap, 5); | |
v2addMex(bp, 5); | |
//drawLineN(ap, av, 'f0f', w); | |
//drawLineN(bp, bv, '00f', w); | |
} | |
j.updateRK4 = function() | |
{ | |
if (!A.mass && !B.mass) return; | |
if (!dt) return; | |
finishRK4(A); | |
finishRK4(B); | |
//j.dbgRK(0); | |
} | |
function finishRK4(c, q) | |
{ | |
if (!c.active) return; | |
var pq = v2avg(c.p1, c.p2, c.p2, c.p3, c.p3, c.p4); | |
if (g_useRkPos) | |
{ | |
c.p = v2c(pq); | |
c.movedByRk = 1; | |
} | |
var vq = v2avg(c.v1, c.v2, c.v2, c.v3, c.v3, c.v4); | |
if (g_useRkVel) | |
c.v = v2c(vq); | |
var aq = v2avg(c.a1, c.a2, c.a2, c.a3, c.a3, c.a4); | |
v2multMe(aq, dt); | |
v2addMe(c.a, aq); | |
} | |
j.update = function() | |
{ | |
if (g_useRK) j.updateRK4(); | |
else j.updateEuler(); | |
} | |
j.updateEuler = function() | |
{ | |
if (!A.mass && !B.mass) return; | |
if (!dt) return; | |
var vF = dampspringForce(A, B, A.sprLen(B), g_sprK, g_sprDamp); | |
v2multMe( vF, dt/(A.invM+B.invM) ); | |
v2addMe( A.a, v2mult(vF, A.invM) ); | |
v2subMe( B.a, v2mult(vF, B.invM) ); | |
} | |
function dampspringForce_pv(Ap, Av, Bp, Bv, sprLen, sprK, sprDamp) | |
{ | |
var a2b = v2dist(Bp, Ap); | |
var a2bN = v2dirTo(Ap, Bp); | |
var sI = (a2b - sprLen) * sprK; | |
var dI = v2dot( v2sub(Bv, Av), a2bN ) * sprDamp; | |
return v2mult(a2bN, sI+dI); | |
} | |
j.isBroken = function() | |
{ | |
var sprLen = A.rigidRadius() + B.rigidRadius(); | |
return v2isFurtherThan(A.p, B.p, A.sprMax(B)); | |
} | |
j.remove = function() | |
{ | |
A.remove_connection_to(B); | |
B.remove_connection_to(A); | |
j.removed = true; | |
return true; | |
} | |
j.has = function(c, q) | |
{ | |
if (!q) | |
return (j.A==c || j.B==c); | |
return (j.A==c && j.B==q || j.A==q && j.B==c); | |
} | |
function dampspringForceRK4(sprK, sprLen, sprDamp, A, B) | |
{ | |
/* | |
P, V, dt, A? | |
V1 = V + 0*dt*A | |
A1 = A // [0, P, V1] = current acceleration (when P and V) | |
V2 = V + 0.5*dt*A1 | |
A2 = [0.5*dt, P+0.5*dt*V1, V2] | |
V3 = V + 0.5*dt*A2 | |
A3 = [0.5*dt, P+0.5*dt*V2, V3] | |
V4 = V + 0.5*dt*A3 | |
A4 = [dt, P+dt*V3, V4] | |
V_ = (V1 + 2*V2 + 2*V3 + V4)/6 | |
A_ = (A1 + 2*A2 + 2*A3 + A4)/6 | |
*/ | |
// create virtual objects | |
var A = {v: v2c(a.v), p: v2c(a.p), invM: a.invM}; | |
var B = {v: v2c(b.v), p: v2c(b.p), invM: b.invM}; | |
var sprLen = a.sprLen(b); | |
A.f1 = a.f1; | |
A.vOrig = v2c(A.v); | |
B.vOrig = v2c(B.v); | |
fRK4(A, B, 0.00001*dt, 1, sprLen); // will use A.f1 | |
fRK4(A, B, 0.5*dt, 2, sprLen); | |
fRK4(A, B, 0.5*dt, 3, sprLen); | |
fRK4(A, B, 1.0*dt, 4, sprLen); | |
var fx = A.f1.x + 2*(A.f2.x + A.f3.x) + A.f4.x; | |
var fy = A.f1.y + 2*(A.f2.y + A.f3.y) + A.f4.y; | |
var vF = v2(fx, fy); | |
return vF; | |
} | |
function dampspringForceRK4_pv(sprK, sprLen, sprDamp, A, B) | |
{ | |
/* | |
// mam P a V | |
P1 = P | |
V1 = V | |
// posuniem sa o polku dt, a zistim aka by bola teraz potrebna rychlost | |
P2 = P + 0.5*dt*V1 | |
V2 = newV(0.5*dt) | |
// posuniem sa o polku dt s vypocitanou rychlostou, a presnejsie(?) zistim aku treba rychlost | |
P3 = P + 0.5*dt*V2 | |
V3 = newV(0.5*dt) | |
// skusim sa opat posunut, aby som zistil rychlost, tentoraz tam kde chcem ist | |
P4 = P + 1.0*dt*V3 | |
V4 = newV(1.0*dt) | |
// vysledna rychlost je z kombinacie hodnot (asi) | |
P_ = (P1 + 2*P2 + 2*P3 + P4)/6 | |
V_ = (V1 + 2*V2 + 2*V3 + V4)/6 | |
*/ | |
// create virtual objects | |
var A = {v: v2c(a.v), p: v2c(a.p), invM: a.invM}; | |
var B = {v: v2c(b.v), p: v2c(b.p), invM: b.invM}; | |
var sprLen = a.sprLen(b); | |
A.f1 = a.f1; | |
A.vOrig = v2c(A.v); | |
B.vOrig = v2c(B.v); | |
fRK4(A, B, 0.00001*dt, 1, sprLen); // will use A.f1 | |
fRK4(A, B, 0.5*dt, 2, sprLen); | |
fRK4(A, B, 0.5*dt, 3, sprLen); | |
fRK4(A, B, 1.0*dt, 4, sprLen); | |
var fx = A.f1.x + 2*(A.f2.x + A.f3.x) + A.f4.x; | |
var fy = A.f1.y + 2*(A.f2.y + A.f3.y) + A.f4.y; | |
var vF = v2(fx, fy); | |
return vF; | |
} | |
function fRK4(A, B, timestep, k, sprLen) | |
{ | |
var vF; | |
if (timestep) | |
vF = dampspringForce(g_sprK, sprLen, g_sprDamp, A, B); | |
else | |
vF = v2c(A.f1); | |
A['f'+k] = v2c(vF); | |
v2multMe( vF, timestep/(A.invM+B.invM) ); | |
var a1 = A['f'+(k-1)]; | |
if (k>=2) { | |
A.v = v2add(A.vOrig, v2mult(a1, timestep)); | |
B.v = v2add(B.vOrig, v2mult(a1, timestep)); | |
} | |
v2addMe( A.v, v2mult(vF, A.invM) ); | |
v2subMe( B.v, v2mult(vF, B.invM) ); | |
} | |
function dampspringForce(A, B, sprLen, sprK, sprDamp) | |
{ | |
var a2b = v2dist(B.p, A.p); | |
if (a2b == 0) { a2b = 1; A.p.y+=1; } | |
var a2bN = v2mult( v2sub(B.p, A.p), 1/a2b ); | |
var d = a2b - sprLen; | |
var sI = sprK * d; | |
var difVel = v2sub(B.v, A.v); | |
var dI = v2dot( difVel, a2bN ); | |
dI *= sprDamp; | |
var f = dI + sI; | |
return v2mult( v2dirTo(A.p, B.p), f ); | |
} | |
} | |
var contacts = {}; | |
function getContact(a, b) | |
{ | |
var id = a.id+'-'+b.id; | |
if (!contacts[id]) | |
contacts[id] = {impulse:0}; | |
return contacts[id]; | |
} | |
function nullContact(a, b) | |
{ | |
var id = a.id+'-'+b.id; | |
if (contacts[id]) | |
contacts[id].impulse = 0; | |
} | |
// cf2 | |
function collideForce(A, B) | |
{ | |
var lenCol = g_radius*2; | |
var Av = v2add(A.v, A.v_); | |
var Bv = v2add(B.v, B.v_); | |
var a2b = v2dist(B.p, A.p); | |
if (!g_sequential) | |
if (a2b > lenCol) return v2(0, 0); | |
if (a2b == 0) { a2b = 1; A.p.y+=1; } | |
var a2bN = v2mult( v2sub(B.p, A.p), 1/a2b ); | |
var difVel = v2sub(Bv, Av); | |
var dot = v2dot( difVel, a2bN ); | |
if (g_drawContacts) | |
{ | |
var c = v2center(A.p, B.p); | |
drawLine(A.p, B.p, 'fff'); | |
} | |
if (g_sequential) | |
{ | |
var con = getContact(A, B); | |
var relNv = dot; | |
var remove = 0; | |
if (dt) | |
remove = relNv + (a2b-lenCol)/dt; | |
var imp = remove / (A.invM + B.invM); | |
//imp *= g_f1; | |
// 0.5 je stabilnejsie, maksie, a viac sa prepada | |
// 1.3 drzi dost pokope, ale pri 1.4 uz sa rozbija | |
var newImp = min(0, imp + con.impulse); | |
//newImp *= g_f2; | |
// 1.01 vybuchuje | |
// 0.99 sa scvrkuje | |
var change = (newImp - con.impulse); | |
//change *= g_f3; | |
// to iste co f1 | |
con.impulse = newImp; | |
return v2mult(a2bN, change); | |
} | |
else | |
{ | |
var toTouch = 0; | |
if (dt) | |
toTouch = (a2b-lenCol)/dt; | |
var pwr = dot + toTouch; | |
if (pwr > 0) | |
return v2(0, 0); | |
pwr /= (A.invM + B.invM); | |
return v2mult(a2bN, pwr); | |
} | |
} | |
var framecount = 0; | |
function start() | |
{ | |
stage = new Stage('c'); | |
stage.mouseChildren = stage.eventChildren = false; | |
getSprite('player', 128, 4); | |
getSprite('heat', 64, 32); | |
var h = stage.stageHeight; | |
if ('bg') | |
{ | |
bgClr = new Sprite(); | |
stage.addChild(bgClr); | |
var f; | |
switch(3) | |
{ | |
case 0: f = 'i/bg_black.png'; break; | |
case 1: f = 'i/bg_white.png'; break; | |
case 2: f = 'i/bg.jpg'; break; | |
case 3: f = 'i/bg2.jpg'; break; | |
} | |
//bgImage = new Bitmap(new BitmapData(f, 1)); | |
if (bgImage) stage.addChild(bgImage); | |
bgScaleOnResize(); | |
} | |
addCircles(); | |
// dbg stuff | |
dbgs = new Sprite(); | |
dbg = dbgs.graphics; | |
stage.addChild(dbgs); | |
stage.addEventListener(Event.ENTER_FRAME, onEF); | |
stage.addEventListener(Event.RESIZE, onRESIZE); | |
stage.addEventListener(KeyboardEvent.KEY_DOWN, onKD); | |
stage.addEventListener(KeyboardEvent.KEY_UP , onKU); | |
stage.addEventListener(MouseEvent.MOUSE_MOVE, onMM); | |
stage.addEventListener(MouseEvent.MOUSE_DOWN, onMD); | |
stage.addEventListener(MouseEvent.MOUSE_UP, onMU); | |
addInfoTexts(); | |
loadLvl('introlevel'); // ini yang menentukan material di awal running | |
} | |
function addInfoTexts() | |
{ | |
var startX = 100; | |
var startY = -400; | |
var text = function(s, setX, setY) | |
{ | |
if (setX) startX = setX; | |
if (setY) startY = setY; | |
drawText(startX, startY, s, 0, 0, stage); | |
startY += 30; | |
}; | |
text('Fluid + rigid bodies dynamics', 0, -370); | |
text(''); | |
text(' [D]irt, [W]ater'); | |
text(' [SPACE+MOUSE] move camera'); | |
text(''); | |
text('(1 of 4) >>'); | |
text('How about other elements?', 1000, -370); | |
text(''); | |
text(' add [R]ocks, [S]and'); | |
text(' add [Q]Snow, [A]ir'); | |
text(''); | |
text('(2 of 4) >>'); | |
text('When hovering balls, you can:', 2000, -370); | |
text(''); | |
text(' [N] make them solid (+SHIFT revert)'); | |
text(' [X] delete them'); | |
text(''); | |
text('(3 of 4) >>'); | |
text('Delete world? Make world solid?', 3000, -370); | |
text(''); | |
text(' press 2x [N] to make everything solid'); | |
text(' press 2x [X] to delete everything'); | |
text(''); | |
text('(4 of 4)'); | |
text('More?', 4000, -370); | |
text(''); | |
text(' [NUM 0] to pause time'); | |
text(' [NUM 5] to unpause'); | |
text(' [SHIFT+1] to save world (up to 9 worlds)'); | |
text(' [1] to load world'); | |
text(''); | |
text('made by psycho'); | |
text('using IvanK Lib (lib.ivank.net)'); | |
} | |
function rangeUnit(f, mn, mx) | |
{ | |
return (f-mn) / (mx-mn); | |
} | |
function forRangeStepsLog(mn, mx, steps, fn) | |
{ | |
forRangeSteps(mn, mx, steps, fn, 'log'); | |
} | |
function forRangeSteps(mn, mx, steps, fn, log) | |
{ | |
if (log) { | |
mn = loge(mn); | |
mx = loge(mx); | |
} | |
var step = 0; | |
if (steps > 1) | |
step = (mx-mn) / (steps-1); | |
for (var i=mn; i <= mx; i+=step) | |
{ | |
var val = i; | |
if (log) | |
val = powe(val); | |
var ru = rangeUnit(i, mn, mx).toFixed(4); | |
var b = fn(val, ru); | |
if (b == false || !step) | |
break; | |
} | |
} | |
var mousePos = v2null(); | |
var mouseLast = v2null(); | |
var mouseScr = v2null(); | |
var mouseScrLast = v2null(); | |
var graspingRange = 50; | |
function getGrasping() | |
{ | |
if (!grasped)return | |
if (grasped instanceof Array) return grasped; | |
return [grasped]; | |
} | |
var arrHovered = []; | |
var grasped = []; | |
function processMouse() | |
{ | |
if (kd['mouse']) | |
processGrasping(); | |
else | |
grasped = []; | |
arrHovered = []; | |
var g = getCircleAtMouse(); | |
if (g) | |
{ | |
arrHovered = [g]; | |
} | |
else | |
if (!grasped || !grasped.length) | |
{ | |
var maxR = graspingRange / g_camZoom; | |
arrHovered = getAllColliding(mousePos, maxR); | |
if (arrHovered.length) | |
drawCircleO(mousePos, maxR, 'aaa'); | |
} | |
$.each(arrHovered, function(i, c) | |
{ | |
var r = g_radius; | |
r *= c.mass ? 1.3 : 0.3; | |
drawCrossBW(c.p, r, 'a0a'); | |
}); | |
} | |
function processGrasping() | |
{ | |
var m = mousePos; | |
var maxN = 3000; | |
var range = graspingRange / g_camZoom; | |
var spr = 100; | |
var dmp = 20; | |
var isArr = grasped instanceof Array; | |
if (isArr) | |
{ | |
$.each(circles, function(i, c) | |
{ | |
if (grasped.length > maxN) | |
return false; | |
if (!c.mass) return; | |
if (v2isCloserThan(c.p, m, range)) | |
{ | |
if (grasped.indexOf(c) == -1) | |
{ | |
grasped.push(c) | |
g_lastUsedObj = c; | |
} | |
} | |
}); | |
$.each(grasped, function(i, g) | |
{ | |
grasp(g); | |
drawLine(m, g.p, 'aaa'); | |
}); | |
} | |
if (grasped && !isArr) | |
{ | |
grasp(grasped); | |
drawLine(m, grasped.p, 'aaa'); | |
} | |
function grasp(c) | |
{ | |
var mass = c.mass+0; | |
if (c.sph) mass = 0; // just for now.. | |
grasp_(c.p, c.v, mass, spr, dmp); | |
} | |
function grasp_(p, v, mass, spr, dmp) | |
{ | |
var m = mousePos; | |
var d = v2sub(m, p); | |
if (!mass || !dtFrame) | |
{ | |
v.x=0; | |
v.y=0; | |
return v2addMe( p, v2mult(d, 0.05) ); | |
} | |
if (v2len(d) < 50) | |
return; | |
var sp = spr * dtFrame * (mass?logn(mass, 4):1); | |
var dm = dmp * dtFrame; | |
dm = minmax(dm, 0, 0.99); | |
v2multMe(d, sp); // spring | |
v2addMe( v, d ); | |
v2subMe( v, v2mult(v, dm) ); // damp | |
} | |
} | |
function onMouseWheel(d) | |
{ | |
var fZoom = 1.15; | |
if (d > 0) | |
camZoomIn(fZoom); | |
else | |
camZoomOut(fZoom); | |
} | |
function onMM(e) | |
{ | |
var of = $('#c').offset(); | |
var c = $('#c'); | |
var w = $(window); | |
of = v2( of.left, of.top ); | |
c = v2( c.width(), c.height() ); | |
w = v2( w.width(), w.height() ); | |
var m = v2( e.target.mouseX, e.target.mouseY ); | |
// mousePos = (m-of) * (w/c); | |
mouseScrLast = mouseScr; | |
mouseScr = v2multV( | |
v2sub(m, of), | |
v2divV(w, c) | |
); | |
mouseLast = mousePos; | |
mousePos = screenToWorld(mouseScr); | |
if (kd['SPACE']) | |
{ | |
var diff = v2sub(mouseScr, mouseScrLast); | |
lockCam = false; | |
var z = g_camZoom; | |
addCamPosition(-diff.x/z, -diff.y/z); | |
} | |
} | |
/* | |
jika posisi material yang ditambahkan tidak | |
berdempetan dengan material yang sudah ada | |
*/ | |
function getFirstColliding(v, r) | |
{ | |
r = r || 0; | |
var maxR = g_radius + r; | |
for (var i=0; i < circles.length; i++) | |
{ | |
var c = circles[i]; | |
if (v2isCloserThan(c.p, v, maxR)) | |
return c; | |
} | |
} | |
function getAllColliding(v, r) | |
{ | |
r = r || 0; | |
var arr = []; | |
var near = getNearby(v, r); | |
for (var i=0; i < near.length; i++) | |
{ | |
var c = near[i]; | |
if (v2isCloserThan(c.p, v, g_radius + r)) | |
arr.push(c); | |
} | |
return arr; | |
} | |
function getCircleAtMouse() | |
{ | |
var arr = getAllColliding(mousePos); | |
if (arr && arr.length) return arr[0]; | |
} | |
function onMD(e) | |
{ | |
if (!kd['mouse']) kx['mouse'] = true; | |
kd['mouse'] = true; | |
kc['mouse'] = true; | |
// grasping | |
grasped = []; | |
var bAllowGraspingOne = 1; | |
var g = 0; | |
if (bAllowGraspingOne) | |
g = getCircleAtMouse(); | |
if (g) | |
{ | |
grasped = g; | |
g_lastUsedObj = g; | |
} | |
if (grasped) | |
$('#sliders').hide(); | |
} | |
function onMU(e) | |
{ | |
if (kd['mouse']) kx['mouse'] = true; | |
kd['mouse'] = false; | |
kc['mouse'] = true; | |
$('#sliders').show(); | |
} | |
function getAlternativeCode(c) | |
{ | |
var ch = String.fromCharCode(c); | |
if (ch >= 'A' && ch <= 'Z' || | |
ch >= '0' && ch <= '9') | |
return ch; | |
if (c==106) return 'NUM*'; | |
if (c==107) return 'NUM+'; | |
if (c==109) return 'NUM-'; | |
if (c==96) return 'NUM0'; | |
if (c==97) return 'NUM1'; | |
if (c==98) return 'NUM2'; | |
if (c==99) return 'NUM3'; | |
if (c==100) return 'NUM4'; | |
if (c==101) return 'NUM5'; | |
if (c==102) return 'NUM6'; | |
if (c==103) return 'NUM7'; | |
if (c==104) return 'NUM8'; | |
if (c==105) return 'NUM9'; | |
// must be CAPS cos native 'shift' value | |
if (c==16) return 'SHIFT'; | |
if (c==17) return 'CTRL'; | |
if (c==18) return 'ALT'; | |
if (c==13) return 'ENTER'; | |
if (c==27) return 'ESC'; | |
if (c==32) return 'SPACE'; | |
if (c==37) return 'LT'; | |
if (c==38) return 'UP'; | |
if (c==39) return 'RT'; | |
if (c==40) return 'DN'; | |
} | |
var g_keylog = 0;//true; | |
function logKey(c, bDown) | |
{ | |
if (!g_keylog) return; | |
var ch = getAlternativeCode(c); | |
var s = bDown ? 'DOWN:' : 'UP: '; | |
s += (' '+c).normalizeLength(4); | |
if (ch) s += (' '+ch); | |
s = s.normalizeLength(15); | |
if (kd['CTRL']) s += ' +CTRL ' | |
if (kd['SHIFT']) s += ' +SHIFT' | |
if (kd['ALT']) s += ' +ALT ' | |
console.log(s); | |
} | |
function onKD(e) | |
{ | |
var c = e.keyCode; | |
if (!kd[c]) kx[c] = true; | |
kd[c] = true; | |
kc[c] = true; | |
var ch = getAlternativeCode(c); | |
if (ch) | |
{ | |
kd[ch] = true; | |
kc[ch] = true; | |
} | |
logKey(c, 'down'); | |
} | |
function onKU(e) | |
{ | |
var c = e.keyCode; | |
if (kd[c]) kx[c] = true; | |
kd[c] = false; | |
kc[c] = true; | |
var ch = getAlternativeCode(c); | |
if (ch) | |
{ | |
kd[ch] = false; | |
kc[ch] = true; | |
} | |
logKey(c); | |
} | |
function addCircles() | |
{ | |
var w = stage.stageWidth; | |
var h = stage.stageHeight; | |
//addItems('water', 2); | |
//addItems('dirt', 2); | |
if (numCircles) | |
{ | |
var mats = []; | |
switch (4) | |
{ | |
case 0: mats = ['skin', 'bone', 'flesh']; break; | |
case 1: mats = ['dirt', 'sand', 'rocks']; break; | |
case 2: mats = ['dirt', 'dirt', 'rocks']; break; | |
case 3: mats = ['water', 'water', 'dirt', 'rocks']; break; | |
case 4: mats = ['dirt']; break; | |
case 5: mats = ['water']; break; | |
case 6: mats = ['apple', 'orange', 'kiwi', 'strawb', 'banana']; break; | |
case 7: mats = ['oil', 'water', 'honey']; break; | |
} | |
var countPerM = to_i(numCircles / mats.length); | |
if (!countPerM) countPerM = 1; | |
for (var i=0; i < mats.length; i++) | |
{ | |
var m = mats[i]; | |
addItems(m, countPerM); | |
numCircles -= countPerM; | |
if (numCircles<=0) break; | |
} | |
} | |
if (0) | |
{ | |
//c0 = addItems('player', 1, 0, w/2, 0)[0]; | |
addItems('player', 1, 0, w/2, 0)[0]; | |
} | |
// bottom | |
if (0) | |
{ | |
var r = g_radius; | |
var x = -r*2; | |
var y = h-r*4; | |
var statics = addItems('iron', w/r*0.8, -0.5, x, y); | |
$.each(statics, function(i, e) { | |
e.setStatic(); | |
}); | |
} | |
g_lastAddedY = -1; | |
} | |
var g_lastAddedY=0; | |
/* | |
tambahkan sebanyak count material.... | |
jika count tidak ada.... maka tambahkan satu biji material | |
*/ | |
function addItems(materialName, count, spacingRatioOfR, startX, startY) | |
{ | |
// (RR)rr(RR)... | |
spacingRatioOfR = spacingRatioOfR || 1; | |
if (typeof count == 'undefined') count = 1; | |
var m = g_materials[materialName]; | |
if (!m) { | |
console.error('no material defined'); | |
return; | |
} | |
var r = m.isSph ? | |
min(g_sphRadius/2, 8) : | |
g_radius; | |
var w = stage.stageWidth; | |
var h = stage.stageHeight; | |
var space = r*2 + r*spacingRatioOfR; | |
var step = to_i( space )+1; | |
var side = to_i( w/step - 0.5 ); // -2 for spacing on sides | |
var customPosition = (startX || startY); | |
if (!customPosition) | |
{ | |
startY = g_lastAddedY + space/2; | |
startX = space; | |
} | |
else | |
side = 9999; | |
var add = []; | |
for (var i=0; i < count; i++) | |
{ | |
var xi = to_i(i%side); | |
var yi = to_i(i/side); | |
var x = xi*step + startX + rndi(); // rand to avoid aligning | |
var y = yi*step + startY + rndi(); | |
if (!customPosition && y > h-space*4) | |
break; | |
add.push( new Circle(m, x, y) ) | |
if (!customPosition && g_lastAddedY!=-1) | |
g_lastAddedY = y + space/2; | |
} | |
circles.append(add); | |
return add; | |
} | |
// z nejakeho divneho dovodu nieco zadefinuje 'add' a potom to oddefinuje, ale ked to tu takto nastavim, | |
// tak tu zostane asi volanie starej funkcie, a tym padom sa to vola, kedze 'add_' nikto neoddefinuje.. asi tak.. | |
/* | |
*/ | |
function add_(materialName, count) | |
{ | |
lockCam = 0; | |
var mat = materialName; | |
var m = mousePos; | |
if (kd['SHIFT']) | |
{ | |
var r = (graspingRange-g_radius)/g_camZoom; | |
var i = 0; | |
while (i++ < 100) | |
{ | |
var vRnd = v2rnd(0, r); | |
if (v2len2(vRnd) > r*r) continue; | |
var p = v2add(m, vRnd); // tambahkan material tidak jauh dari posisi mouse saat ini | |
// yakni dengan melakukan koreksi tertentu dari posisi mouse | |
addIfSpace(mat, 1, 0, p.x, p.y); | |
} | |
return; | |
} | |
if (!count || count == 1) // ini masuk karena tidak ada argument untuk count | |
{ | |
grasped = addIfSpace(mat, count, 0, m.x, m.y); | |
return grasped; | |
} | |
else | |
return add(mat, count); | |
} | |
// relatively (con?)temporary | |
function add(materialName, count, space, x, y) | |
{ | |
return addItems(materialName, count, space, x, y) | |
} | |
/* | |
tambahkan material jika tidak berdempetan dengan material yang sudah | |
ada | |
*/ | |
function addIfSpace(materialName, count, space, x, y) | |
{ | |
if (getFirstColliding(v2(x, y), g_radius-1)) return; | |
return addItems(materialName, count, space, x, y) | |
} | |
function kkd(c) { return kd[c]; } | |
function kkc(c) { return kc[c]; } | |
function kkx(c) { return kx[c]; } | |
function pressed(c) | |
{ | |
return kd[c] && kc[c]; | |
} | |
function pressedAny() | |
{ | |
for (var i=0; i < arguments.length; i++) | |
{ | |
var c = arguments[i]; | |
if (kd[c] && kc[c]) | |
return c; | |
} | |
} | |
function doWithGrasped(fn) | |
{ | |
var arr = getGrasping(); | |
if (!arr) return; | |
$.each(grasped, function(i, g) | |
{ | |
fn(g); | |
}); | |
} | |
var g_camX = 0; | |
var g_camY = 0; | |
var g_camZoom = 1; | |
function addCamPosition(x, y) | |
{ | |
g_camX += x; | |
g_camY += y; | |
updateStageTransform(); | |
} | |
function setCamPosition(x, y) | |
{ | |
g_camX = x; | |
g_camY = y; | |
updateStageTransform(); | |
} | |
function camZoomIn(f) { setCamZoom(g_camZoom*f); } | |
function camZoomOut(f) { setCamZoom(g_camZoom/f); } | |
function setCamZoom(z) | |
{ | |
if (g_camY == currentMaxY()) | |
g_camY = 9999; // snap to bottom | |
g_camZoom = z; | |
updateStageTransform(); | |
} | |
function resetCam() | |
{ | |
var w2 = stage.stageWidth/2; | |
var h2 = -stage.stageHeight/2; | |
g_camX = w2; | |
g_camY = h2; | |
g_camZoom = 1; | |
updateStageTransform(); | |
} | |
function screenToWorld(x, y) | |
{ | |
if (x.x) { | |
y = x.y; | |
x = x.x; | |
} | |
var w2 = stage.stageWidth/2; | |
var h2 = stage.stageHeight/2; | |
var z = g_camZoom; | |
x = (x-w2)/z + g_camX; | |
y = (y-h2)/z + g_camY; | |
return v2(x, y); | |
} | |
function worldToScreen(x, y) | |
{ | |
if (x.x) { | |
y = x.y; | |
x = x.x; | |
} | |
var w = stage.stageWidth; | |
var h = stage.stageHeight; | |
x = (x - g_camX)*z + w2; | |
y = (y - g_camY)*z + h2; | |
return v2(x, y); | |
} | |
function currentMaxY() { return -(stage.stageHeight/2-10)/g_camZoom; } | |
function updateStageTransform() | |
{ | |
var w = stage.stageWidth; | |
var h = stage.stageHeight; | |
var z = g_camZoom; | |
stage.scaleX = z; | |
stage.scaleY = z; | |
g_camY = min(g_camY, currentMaxY()); | |
var x, y; | |
x = w/2 - g_camX * z; | |
y = h/2 - g_camY * z; | |
stage.x = x; | |
stage.y = y; | |
} | |
var lockCam = 0; | |
function processInput() | |
{ | |
var w = stage.stageWidth; | |
var h = stage.stageHeight; | |
var fZoom = 1.05; | |
if (kd['NUM*']) resetCam(); | |
if (kd['NUM+']) camZoomIn(fZoom); | |
if (kd['NUM-']) camZoomOut(fZoom); | |
if (pressed('C')) lockCam = !lockCam; | |
if (lockCam && g_lastUsedObj) | |
{ | |
var p = g_lastUsedObj.p; | |
setCamPosition(p.x, p.y); | |
} | |
if (pressed('P')) add_('player'); | |
if (kkd('W')) add_('water'); | |
if (kkd('O')) add_('oil'); | |
if (kkd('H')) add_('honey'); | |
if (kkd('Q')) add_('snow'); | |
if (kkd('A')) add_('air'); | |
if (kkd('T')) add_('tree'); | |
if (kkd('G')) add_('grass'); | |
if (kkd('L')) add_('leafs'); | |
if (kkd('V')) add_('lava'); | |
if (kkd('D')) add_('dirt'); | |
if (kkd('R')) add_('rocks'); | |
if (kkd('S')) add_('sand'); | |
if (kkd('I')) add_('iron'); | |
var num = pressedAny('1', '2', '3', '4', '5', '6', '7', '8', '9'); // null may not work coz '0'==false | |
if (num) | |
{ | |
var lvl = 'lvl'+num; | |
if (kd['SHIFT']) saveLvl('confirm', lvl); | |
else loadLvl(lvl); | |
} | |
if (pressed('N')) | |
{ | |
if (kd['SHIFT']) dynamify(getGrasping(), arrHovered); | |
else solidify(getGrasping(), arrHovered); | |
} | |
if (pressed('M')) | |
{ | |
if (kd['SHIFT']) unmeld(getGrasping(), arrHovered); | |
else meld(getGrasping(), arrHovered); | |
} | |
if (pressed('X')) | |
remove(getGrasping(), arrHovered); | |
if (kd['Z']) | |
{ | |
var c = v2(w/2, h/2); | |
g_nGravity = v2dirTo(c, mousePos); | |
drawLine(mousePos, c, 'fff'); | |
} | |
if (kd['NUM0']) g_timeMult = 0; | |
if (kd['NUM1']) g_timeMult = 0.005; | |
if (kd['NUM2']) g_timeMult = 0.02; | |
if (kd['NUM3']) g_timeMult = 0.05; | |
if (kd['NUM4']) g_timeMult = 0.2; | |
if (kd['NUM5']) g_timeMult = 0.5; | |
if (kd['NUM6']) g_timeMult = 1.0; | |
var add = v2(0, 0); | |
var f = fKeys; | |
var cf = 0; | |
if (kd['SHIFT']) | |
{ | |
f *= fShift; | |
} | |
if (kd['UP']) { add.y = -f; cf = 1; } | |
if (kd['DN']) { add.y = +f; cf = 1; } | |
if (kd['LT']) { add.x = -f; cf = 2; } | |
if (kd['RT']) { add.x = +f; cf = 3; } | |
// normalize diagonal speed | |
if (v2len(add)) add = v2mult(v2norm(add), f); | |
c0 = null; | |
if (g_lastUsedObj) | |
c0 = g_lastUsedObj; | |
else | |
$.each(circles, function(i, c) | |
{ | |
if (c.m.name == 'player') | |
{ | |
c0 = c; | |
return false; | |
} | |
}); | |
// follow player | |
if (g_lastUsedObj && g_lastUsedObj.m.name=='player') | |
$.each(circles, function(i, c) | |
{ | |
if (c.m.name != 'player' || c==g_lastUsedObj) return; | |
var a = v2dirTo(c.p, g_lastUsedObj.p); | |
v2multMe(a, 900*dt); | |
c.impulse(a); | |
usePlayerFrames(c); | |
}); | |
usePlayerFrames(c0); | |
if (kd['E']) | |
{ | |
var earthquake = v2rnd(50, 100); | |
$.each(circles, function(i,c) | |
{ | |
if (c.mass) | |
c.impulse( earthquake ); | |
}); | |
} | |
if (c0) | |
c0.impulse(add); | |
kc = []; | |
kx = []; | |
} | |
function usePlayerFrames(c) | |
{ | |
if (!c || !c.o || !c.o instanceof MBitmap) | |
return; | |
var up = -c.v.y; | |
var dn = c.v.y; | |
var lt = -c.v.x; | |
var rt = c.v.x; | |
var cf = 0; | |
var mx = maxn(up, dn, lt, rt); | |
if (mx==up || mx==dn) cf = 1; | |
if (mx==lt) cf = 2; | |
if (mx==rt) cf = 3; | |
if (mx==0) cf = 0; | |
c.o.currentFrame = cf; | |
} | |
//////////////////////////////////////////////////////// | |
// GRID | |
function drawGrid(on) | |
{ | |
if (!on) return; | |
if (!g_grid) return; | |
var w = stage.stageWidth; | |
var h = stage.stageHeight; | |
var mn = p2gpos( v2min(g_gridMin, screenToWorld(0, 0)) ); | |
var mx = p2gpos( v2max(g_gridMax, screenToWorld(w, h)) ); | |
v2addMexy(mx, 1, 1); | |
var s = g_gridStep; | |
var h = s/2; // half step | |
for (var x=mn.x; x <= mx.x; x++) | |
drawLine(x*s, mn.y*s, x*s, mx.y*s, 'aaa'); | |
for (var y=mn.y; y <= mx.y; y++) | |
drawLine(mn.x*s, y*s, mx.x*s, y*s, 'aaa'); | |
var arr = [];//getNearby(mousePos, 0); | |
for (var i=0; i < arr.length; i++) | |
{ | |
var A = arr[i]; | |
drawCircle(A.p, g_radius, '5f5'); | |
drawLine(mousePos, A.p, 'aaa'); | |
} | |
$.each(g_gridDyn, function(i, cell) | |
{ | |
if (!cell || !cell.length) return err('huh?'); | |
var c = cell[0]; | |
var gp = p2gpos(c.p); | |
drawRect(v2mult(gp, s), v2(s, s), 'fff', 0.2); | |
}); | |
} | |
function fillGrid() | |
{ | |
if (!g_useGrid) | |
{ | |
g_grid = null; | |
g_gridDyn = null; | |
return; | |
} | |
var w = stage.stageWidth; | |
var h = stage.stageHeight; | |
var s = g_gridStep; | |
// NOTE: if i wanted to optimize this, i could only recheck objects that moved in the last frame | |
// therefore i would avoid rehashing 1000s of static circles (if it shows up as performance issue) | |
g_grid = {}; | |
g_gridDyn = {}; | |
var mn = v2null(); | |
var mx = v2null(); | |
for (var i=0; i<circles.length; i++) | |
{ | |
var c = circles[i]; | |
if (c.removed) continue; // all (not removed) | |
var x = Math.floor(c.p.x/s); // calc index | |
var y = Math.floor(c.p.y/s); | |
if (mn.x > x) mn.x = x; // keep min/max | |
if (mn.y > y) mn.y = y; | |
if (mx.x < x) mx.x = x; | |
if (mx.y < y) mx.y = y; | |
var k = x+'-'+y; // key = "X-Y" | |
if (!g_grid[k]) g_grid[k] = []; | |
g_grid[k].push(c); | |
if (!c.mass) continue; | |
if (!g_gridDyn[k]) g_gridDyn[k] = []; | |
g_gridDyn[k].push(c); | |
} | |
// mult by step | |
g_gridMin = v2multxy(mn, s, s); | |
g_gridMax = v2multxy(mx, s, s); | |
} | |
var errLast; | |
function err(s, ret) | |
{ | |
var now = time(); | |
if (errLast && now-errLast>100) | |
console.log(s); | |
errLast = now; | |
return ret; | |
} | |
// position is usual world XY | |
// radius is radius in which we want to check collision | |
// iSelf is ORDER of self, so it only returns higher ORDERs (or leave empty if u want all) | |
// dynamicOnly is what it says | |
function getNearby(pos, radius, iSelf, dynamicOnly) | |
{ | |
if (abs(pos.x)+abs(pos.y) > 999999) return err('getNearby wtf', []); | |
if (typeof iSelf!='number') iSelf = -1; | |
// calc min/max indices of grid | |
var r = radius; | |
var s = g_gridStep; | |
var mn = v2subxy(pos, r, r); | |
var mx = v2addxy(pos, r, r); | |
return getInAABB(mn, mx, dynamicOnly, iSelf); | |
} | |
var g_aabbArea; | |
function getInAABB(mn, mx, dynamicOnly, iSelf) | |
{ | |
// if no grid - this may become very slow with big levels | |
if (!g_grid || !g_gridDyn) | |
{ | |
g_aabbArea = -1; | |
return getInAABB_noGrid(mn, mx, dynamicOnly, iSelf); | |
} | |
if (typeof iSelf!='number') iSelf = -1; | |
mn = p2gpos(mn); | |
mx = p2gpos(mx, 'up'); | |
// grid step has to be as big as maximum radius | |
// that way, we wont miss circles, when we add +1 step to each side of area we are checking | |
v2addMexy(mn, -1, -1); | |
v2addMexy(mx, 1, 1); | |
var arr = []; | |
var s = g_gridStep; | |
var df = v2sub(mx, mn); | |
g_aabbArea = df.x * df.y; | |
for (var y=mn.y; y<mx.y; y++) | |
{ | |
for (var x=mn.x; x<mx.x; x++) | |
{ | |
var g = dynamicOnly ? g_gridDyn : g_grid; | |
var k = Math.floor(x)+'-'+Math.floor(y); | |
var gArr = g[k]; | |
if (!gArr) continue; | |
for (var i=0; i<gArr.length; i++) | |
{ | |
var c = gArr[i]; | |
if (!c) { err('wtf'); continue; } | |
if (c.order <= iSelf) continue; | |
if (c.removed) continue; | |
arr.push(c); | |
} | |
} | |
} | |
return arr; | |
} | |
function p2gpos(p, up) { up=up?1:0; return v2(up+Math.floor(p.x/g_gridStep), up+Math.floor(p.y/g_gridStep)); } | |
function p2gkey(p) { return Math.floor(p.x/g_gridStep)+'-'+Math.floor(p.y/g_gridStep); } | |
function xy2gkey(x, y) { return Math.floor(x/g_gridStep)+'-'+Math.floor(y/g_gridStep); } | |
function getInAABB_noGrid(mn, mx, dynamicOnly, iSelf) | |
{ | |
if (typeof iSelf!='number') iSelf = -1; | |
var arr = []; | |
for (var i=0; i < circles.length; i++) | |
{ | |
var c = circles[i]; | |
if (!c) { err('wtf'); continue; } | |
if (c.removed) continue; | |
if (c.order <= iSelf) continue; | |
if (dynamicOnly && !c.mass) continue; | |
var bOut = (c.p.x < mn.x || c.p.x > mx.x || c.p.y < mn.y || c.p.y > mx.y); | |
if (!bOut) | |
arr.push(c); | |
} | |
return arr; | |
} | |
// GRID | |
///////////////////////////////////////////////////////////// | |
function f2rgb(r, g, b) | |
{ | |
return to_i255(r)*256*256 + | |
to_i255(g)*256 + | |
to_i255(b); | |
} | |
function heatclr(f01, add) | |
{ | |
add = add || 0; | |
// input is f=<0,1> | |
var f = minmax(f01, 0, 1); | |
f *= 2; | |
var r=0,g=0,b=0; | |
if (f<1) | |
{ | |
g = f*2; | |
b = 2-f*2; | |
} | |
else | |
{ | |
f -= 1; | |
r = f*2; | |
g = 2-f*2; | |
} | |
var clr = f2rgb(r+add, g+add, b+add); | |
return clr; | |
} | |
// in best case (when nothing is removed), it just returns original array | |
function onlyUnremoved(arr) | |
{ | |
var i; | |
for (i=0; i < arr.length; i++) | |
if (arr[i].removed) break; | |
// nothing changed, return original array | |
if (i==arr.length) return arr; | |
nicelog('onlyUnremoved - something has changed'); | |
var arrUnr = []; | |
for (i=0; i < arr.length; i++) | |
{ | |
var a = arr[i]; | |
if (!a.removed) arrUnr.push(a); | |
} | |
return arrUnr; | |
} | |
function getScreenAABB(reserveRatio) | |
{ | |
var w = stage.stageWidth; | |
var h = stage.stageHeight; | |
var mn = screenToWorld(0, 0); | |
var mx = screenToWorld(w, h); | |
var vR = v2sub(mx, mn); | |
v2multMe(vR, reserveRatio); | |
v2subMe(mn, vR); | |
//if (vR.y < 0) vR.y = 0; // if testing with smaller rect, i want it to touch the bottom | |
v2addMe(mx, vR); | |
return {mn:mn, mx:mx}; | |
} | |
var frame_count = 0; | |
var frame_collisions; | |
var frame_collision_checks; | |
var frame_spring_checks; | |
var activeScreenRatio = -0.0; | |
var visibleScreenRatio = 0.01; | |
var circlesActive = []; | |
var runFrames = -1; | |
function onEF() | |
{ | |
frame_count++; | |
applyGlobalParamsLocally(); | |
//if (! (frame_count%10) ) | |
{ | |
if (dbg) dbg.clear(); // lines, circles | |
while (dbgs.children.length) // texts | |
dbgs.removeChildAt(0); | |
} | |
stage.removeChild(dbgs); // on top | |
stage.addChild(dbgs); | |
framecount++; | |
dtFrame = get_dt(); | |
dtFrame = 1/60 * 0.5; | |
dtFrame *= g_timeMult; | |
processMouse(); | |
processInput(); | |
frame_collisions = 0; | |
frame_collision_checks = 0; | |
frame_spring_checks = 0; | |
////////////////////////////////////////// | |
// remove removed | |
circles = onlyUnremoved(circles); | |
fillGrid(); | |
var aabb = getScreenAABB(activeScreenRatio); | |
//drawRectO(aabb.mn, aabb.mx, 'f00'); | |
circlesActive = getInAABB(aabb.mn, aabb.mx); // mencari circle aktif dalam grid | |
g_cellsActive = g_aabbArea; | |
circlesActive = sortDynamicsFirst(circlesActive); | |
for (var i=0; i < circles.length; i++) circles[i].active = false; | |
for (var i=0; i < circlesActive.length; i++) circlesActive[i].active = true; | |
var run = true; | |
if (runFrames > -1) | |
{ | |
if (runFrames==0) run = false; | |
else runFrames--; | |
} | |
if (run) | |
simulatePhysics( dtFrame ); | |
drawHeatVelocity( g_drawHeat ); | |
debugTexts(); | |
//test_drawPoly(); | |
/* toto uz je inde, a asi to sem treba presunut | |
// update positions in engine | |
var cc = circlesActive; | |
cc = circles; // tmp | |
for (var i=0; i < cc.length; i++) | |
{ | |
var c = cc[i]; | |
c.updateEngineData(); | |
} | |
*/ | |
drawGrid(g_drawGrid); | |
if (g_jointWidth) | |
{ | |
$.each(joints, function(i, j) | |
{ | |
j.dbg_drawJoints(); | |
}); | |
} | |
} | |
/* | |
na masu pasivnych guliciek pouzit algoritmus, ktory ich sceli do polygonu | |
moct nakreslit polygon, ktory nebude mat realne data o gulickach v sebe, ale bude sa dat z neho odlupovat (or kopat donho dole) | |
podla nakresleneho polygonu by sa mali zobrazit gulicky po krajoch (default v zoome 1), a vnutro vyfarbit | |
neskor by sa malo dat odlupat z neho, a tak sa bude upravovat polygon podla odobratej gulicky | |
*/ | |
function test_drawPoly() | |
{ | |
var first; | |
var last; | |
$.each(circles, function(i, c) | |
{ | |
if (!i) first=c; | |
line(last, c); | |
last = c; | |
}); | |
line(first, last); | |
function line(a, b) | |
{ | |
if (!a || !b) return; | |
drawLine(a.p, b.p, '000', 2); | |
} | |
} | |
function debugTexts() | |
{ | |
// removing/melding/solidifying/dynamifying/etc EVERYTHING requires DOUBLE-PRESS | |
var confirmAction = currentlyInLastSec(); | |
if (confirmAction) | |
confirmAction = '<b style="color: red;">'+confirmAction.toUpperCase()+' ALL?</b>'; | |
$('#sph').html('<b>fluid</b>'+ | |
confirmAction + | |
'g: <b>'+g_gravity+'</b>'+ | |
'maxVel: <b>'+nice(sqrt(g_currMaxVel2))+'</b>'+ | |
'#cellsActive: <b>'+g_cellsActive+'</b>'+ | |
'maxPress: <b>'+nice(g_maxPressure)+'</b>'+ | |
'maxPressNear: <b>'+nice(g_maxPressureNear)+'</b>'+ | |
/*'smoothR: <b>'+g_sphRadius+'</b>'+ | |
'stiff: <b>'+g_sphStiff+'</b>'+ | |
'stiffNear: <b>'+g_sphStiffNear+'</b>'+ | |
'restDensity: <b>'+g_sphRestDensity+' ('+nice(g_avgSphDensity)+')'+'</b>'+ | |
*/ | |
'<span class="fright">'+circles.length+'xO '+g_fps+'</span>'+ | |
''); | |
$('#fps').html('fps: '+g_fps); | |
$('#tests').html('collisions: '+frame_collisions+ | |
'<br>checks coll: '+frame_collision_checks+ | |
'<br>checks spring: '+frame_spring_checks+ | |
''); | |
} | |
function drawHeatVelocity(enabled) | |
{ | |
var cc = circles[0]; | |
if (!cc) return; | |
if (enabled) | |
{ | |
$.each(circles, function(i, c) | |
{ | |
//if (!c.mass) return; | |
var f = 0; | |
switch(0) { | |
case 0: f = v2len( c.v ); break; | |
case 1: f = c._seqI/1000; break; | |
case 2: f = c._seqIabs/1000; break; | |
case 3: f = c.sphDens*100; break; | |
case 4: f = c.sphDensNear*100; break; | |
case 5: f = c.pressure(); break; | |
case 6: f = c.pressureNear(); break; | |
} | |
f /= g_HeatMax * 100; | |
if (!c.active) | |
c.setHeat(f); | |
else | |
c.unsetHeat(); | |
}); | |
} | |
else | |
{ | |
if (!cc.spriteHeat) return; | |
$.each(circles, function(i, c) | |
{ | |
c.unsetHeat(); | |
}); | |
} | |
} | |
/* | |
replace $.each with for loop | |
FIND: | |
\$\.each\(([A-z]+),[ ]+function[ \t]*\(i, ([a-z])\)([ \n\t]+)\{([ \n\t]+) | |
REPLACE: | |
for \(var i=0; i < \1.length; i++\)\3{\4var \2 = \1[i];\4 | |
*/ | |
// dahulukan dinamik circle (water, oil ) di bagian pertama array | |
function sortDynamicsFirst(arr) | |
{ | |
var i; | |
var currentlyDynamics = true; | |
for (i=0; i < arr.length; i++) | |
{ | |
var c = arr[i]; | |
if (currentlyDynamics && !c.mass) | |
currentlyDynamics = false; | |
if (!currentlyDynamics && c.mass) | |
break; | |
} | |
// dont have to sort if it didnt break | |
if (i==arr.length) return arr; | |
///////////////////////////////////// | |
// otherwise SORT | |
var sorted = []; | |
for (var i=0; i < arr.length; i++) | |
{ | |
var c = arr[i]; | |
if (c.mass) sorted.push(c); | |
} | |
for (var i=0; i < arr.length; i++) | |
{ | |
var c = arr[i]; | |
if (!c.mass) sorted.push(c); | |
} | |
for (var i=0; i < sorted.length; i++) | |
{ | |
sorted[i].order = i; | |
} | |
return sorted; | |
} | |
var g_avgSphDensity = 0; | |
var g_maxPressure = 0; | |
var g_maxPressureNear = 0; | |
function simulatePhysics(substep_dt) | |
{ | |
dt = substep_dt; | |
pairs = []; | |
g_avgSphDensity = 0; | |
g_numSph = 0; | |
g_maxPressure = 0; | |
g_maxPressureNear = 0; | |
g_currMaxVel2 = 0; | |
/////////////////////////////////////////////////// | |
// PARTICLE BASICS | |
// inisialisasi | |
for (var i=0; i < circles.length; i++) | |
{ | |
var c = circles[i]; | |
c.frameStart(); // sph dens dan sph near dibuat sama dengan nol | |
} | |
for (var i=0; i < circlesActive.length; i++) | |
{ | |
var c = circlesActive[i]; | |
if (!c.mass) break; // hanya diberlakukan untuk air, oli, dan partikel-partikel yang memiliki massa | |
// setelah disorting... maka pada array circlesActive yang dahulu muncul adalah dinamik partikel | |
c.gravity(); | |
c.moveByVelocity(); | |
c.odrazOdStran(); // jika partikel melewati batas dinding.... pukul kembali | |
} | |
/* | |
if (g_bMelding) | |
for (var i=0; i < circles.length; i++) | |
{ | |
var c = circles[i]; | |
c.checkNewJoints(true); // true=only check orderly later | |
} | |
*/ | |
// find pairs | |
if (dt) | |
for (var i=0; i < circlesActive.length; i++) | |
{ | |
var c = circlesActive[i]; | |
// since circles are sorted with dynamics first | |
// we can stop iterating when we find static circle | |
if (!c.mass) break; | |
c.findPairs(); // cari pasangan | |
} | |
/////////////////////////////////////////////////// | |
var addActive = []; | |
var addActiveEnd = []; | |
// smooth collisions | |
for (var i=0; i < pairs.length; i++) | |
{ | |
var p = pairs[i]; | |
var A = p.A; | |
var B = p.B; | |
A.sphCalculateDensity(B, p); // hitung densitas dan dens-near untuk partikel yag berinteraksi | |
//if (!A.active) (A.mass?addActive:addActiveEnd).push(A); | |
//if (!B.active) (B.mass?addActive:addActiveEnd).push(B); | |
} | |
var arrX = []; | |
arrX.append(addActive); | |
arrX.append(circlesActive); | |
//arrX.append(addActiveEnd); | |
//circlesActive = arrX; | |
for (var i=0; i < circlesActive.length; i++) | |
{ | |
var c = circlesActive[i]; | |
//if (!c.mass) break; | |
c.sphCalculatePressure(); // hitung tekanan dan pressure-near | |
} | |
for (var i=0; i < pairs.length; i++) | |
{ | |
var p = pairs[i]; | |
var A = p.A; | |
var B = p.B; | |
A.solveCollision(B, p); // gunakan SPH untuk partikel dinamik dan gaya repulsive untuk partikel static | |
} | |
for (var i=0; i < circlesActive.length; i++) | |
{ | |
var c = circlesActive[i]; | |
if (!c.mass) break; | |
if (c.sph) | |
c.calcVelocityFromDisplacement(); | |
} | |
/////////////////////////////////////////////////// | |
// COLLISIONS - RIGID | |
if (0) | |
for (var i=0; i < pairs.length; i++) // <-- wtf is this shit? | |
{ | |
var p = pairs[i]; | |
// compute toTouch to slow particles before collisions | |
var A = p.A; | |
var B = p.B; | |
if (!A.sph && !B.sph) | |
{ | |
var v = v2sub(A.v, B.v); | |
v2multMe( v, dt/(A.invM+B.invM)*10 ); | |
v2addMe( A.v, v2mult(v, A.invM) ); | |
v2addMe( B.v, v2mult(v, B.invM) ); | |
} | |
} | |
/////////////////////////////////////////////////// | |
for (var i=0; i < circles.length; i++) | |
{ | |
var c = circles[i]; | |
if (!c.links.length) continue; | |
c.prepareRK(); | |
} | |
// only active joints (either of its circles is active) | |
var jointsA = []; // active | |
for (var i=0; i < joints.length; i++) joints[i].active = false; | |
for (var i=0; i < joints.length; i++) | |
{ | |
var j = joints[i]; | |
if (j.A.active || j.B.active) | |
jointsA.push(j); | |
//else drawLine(j.A.p, j.B.p, '000', 3); // show inactive joints | |
} | |
// JOINTS | |
for (var i=0; i < jointsA.length; i++) { jointsA[i].updateRK(1); } | |
for (var i=0; i < jointsA.length; i++) { jointsA[i].updateRK(2); } | |
for (var i=0; i < jointsA.length; i++) { jointsA[i].updateRK(3); } | |
for (var i=0; i < jointsA.length; i++) { jointsA[i].updateRK(4); } | |
for (var i=0; i < jointsA.length; i++) | |
{ | |
var j = jointsA[i]; | |
j.update(); | |
if (j.isBroken()) j.remove(); | |
} | |
joints = onlyUnremoved(joints); | |
for (var i=0; i < circlesActive.length; i++) | |
{ | |
var c = circlesActive[i]; | |
if (!c.mass) break; | |
if (!c.links.length) continue; | |
v2addMe(c.v, c.a); | |
//drawLineN(c.p, v2mult(c.a, 0.5), 'fff', 3); | |
c.a = v2(0, 0); | |
} | |
//////////////////////////////////////////// | |
// VISIBILITY | |
var w = stage.stageWidth; | |
var h = stage.stageHeight; | |
// calc AABB | |
var aabb = getScreenAABB(visibleScreenRatio); | |
var mn = aabb.mn; | |
var mx = aabb.mx; | |
// NOT visible treba vsetkym circles | |
// a visible by stacilo aj len aktivnym z aabb, ale to mi moc nepomoze | |
for (var i=0; i < circles.length; i++) | |
{ | |
var c = circles[i]; | |
var bOut = (c.p.x < mn.x || c.p.x > mx.x || c.p.y < mn.y || c.p.y > mx.y); | |
if (bOut) | |
{ | |
c.o.visible = false; | |
} | |
else | |
{ | |
c.o.visible = true; | |
c.updateEngineData(); | |
} | |
} | |
g_avgSphDensity = g_numSph? | |
g_avgSphDensity/g_numSph: | |
0; | |
} | |
function drawText(x, y, s, clr, nice_number, optionalStage) | |
{ | |
if (typeof x.x != 'undefined') | |
{ | |
nice_number=clr; | |
clr=s; | |
s=y; | |
y=x.y; | |
x=x.x; | |
} | |
nice_number = 1; // tmp | |
if (nice_number && typeof s == 'number') | |
s = nice(s); | |
var fontSize = 20; | |
var t = new TextField(); | |
clr = normalizeClr(clr); | |
t.setTextFormat( new TextFormat("Arial", fontSize, clr) ); | |
if (!optionalStage) optionalStage = dbgs; | |
optionalStage.addChild(t); | |
t.setText(s); | |
t.x = x; | |
t.y = y; | |
} | |
function drawCircleO(x, y, r, clr, w, parts) | |
{ | |
var xIsV = (typeof x.x != 'undefined'); | |
if (xIsV) | |
{ // ak je to vektor.. | |
parts=w; | |
w=clr; | |
clr=r; | |
r=y; | |
y=x.y; | |
x=x.x; | |
} | |
_drawCircleO(x, y, r, clr, w, parts); | |
} | |
function _drawCircleO(x, y, r, clr, w, parts) | |
{ | |
parts = parts || 20; | |
var arr = getCirclePoints(parts, r, x, y); | |
var len = arr.length; | |
for (var i=0; i < len; i++) | |
{ | |
var a = arr[i]; | |
var b = arr[ (i+1)%len ]; | |
drawLine(a, b, clr, w); | |
} | |
} | |
function getCirclePoints(parts, r, x, y) | |
{ | |
var arr = []; | |
x = x || 0; | |
y = y || 0; | |
r = r || 1; | |
var start = v2(0, -r); | |
for (var i=0; i <= parts; i++) | |
{ | |
var n = v2rot(start, i * (360/parts)); | |
arr.push(n); | |
} | |
if (x || y) | |
{ | |
for (var i=0; i < arr.length; i++) | |
v2addMe( arr[i], v2(x, y) ); | |
} | |
return arr; | |
} | |
function drawCross(v, r, clr, w) | |
{ | |
drawLineN(v.x-r, v.y, r*2, 0, clr, w); | |
drawLineN(v.x, v.y-r, 0, r*2, clr, w); | |
} | |
function drawCrossBW(v, r) | |
{ | |
drawLineN(v.x-r, v.y, r*2, 0, '000'); | |
drawLineN(v.x, v.y-r, 0, r*2, 'fff'); | |
} | |
// drawLineN(vA, vN, c, w) | |
// drawLineN(vA, nx, ny, c, w) | |
function drawLineN(ax, ay, bx, by, c, w, perp) | |
{ | |
var axIsV = (typeof ax.x != 'undefined'); | |
if (axIsV) { // ak je to vektor.. | |
perp=w; | |
w=c; // vaha je uz v 'c', takze to treba posunut.. | |
c=by; | |
by=bx; | |
bx=ay; | |
ay = ax.y; | |
ax = ax.x; | |
} | |
var bxIsV = (typeof bx.x != 'undefined'); | |
if (bxIsV) { | |
perp=w; | |
w=c; | |
c=by; | |
by = bx.y; | |
bx = bx.x; | |
} | |
// perpendicular | |
if (perp) | |
{ | |
var x = bx; | |
var y = by; | |
if (perp=='r' || perp==1) { | |
bx = -y; // right = 'r' OR 1 | |
by = x; | |
} | |
else { | |
bx = y; // left = anything else | |
by = -x; | |
} | |
} | |
_drawLine(ax, ay, ax+bx, ay+by, c, w); | |
} | |
// drawLine(vA, vB, c, w) | |
// drawLine(vA, bx, by, c, w) | |
function drawLine(ax, ay, bx, by, c, w) | |
{ | |
var axIsV = (typeof ax.x != 'undefined'); | |
if (axIsV) { // ak je to vektor.. | |
w=c; // vaha je uz v 'c', takze to treba posunut.. | |
c=by; | |
by=bx; | |
bx=ay; | |
ay = ax.y; | |
ax = ax.x; | |
} | |
var bxIsV = (typeof bx.x != 'undefined'); | |
if (bxIsV) { | |
w=c; | |
c=by; | |
by = bx.y; | |
bx = bx.x; | |
} | |
_drawLine(ax, ay, bx, by, c, w); | |
} | |
function _drawLine(x, y, x2, y2, clr, w) | |
{ | |
if (!w) w = 1; | |
clr = normalizeClr(clr); | |
dbg.lineStyle(w, clr); | |
dbg.moveTo(x, y); | |
dbg.lineTo(x2, y2); | |
return; // new ivank has working width | |
// fix, kedze to nejde.. | |
if (w > 1) | |
{ | |
var a = v2(x, y); | |
var b = v2(x2, y2); | |
var n = v2dirTo(a, b); | |
for (var i=1; i < w/2+1; i++) | |
{ | |
var dx = -n.y * i; | |
var dy = n.x * i; | |
drawLine(x+dx, y+dy, x2+dx, y2+dy, clr); | |
drawLine(x+dx, y-dy, x2+dx, y2-dy, clr); | |
} | |
} | |
} | |
function drawRectAB(x, y, bx, by, clr, alpha) | |
{ | |
var xIsV = (typeof x.x != 'undefined'); | |
if (xIsV) { // ak je to vektor.. | |
alpha=clr; | |
clr=by; | |
by=bx; | |
bx=y; | |
y=x.y; | |
x=x.x; | |
} | |
var bxIsV = (typeof bx.x != 'undefined'); | |
if (bxIsV) { | |
alpha=clr; | |
clr=by; | |
by=bx.y; | |
bx=bx.x; | |
} | |
_drawRect(x, y, bx-x, by-y, clr, alpha); | |
} | |
function drawRect(x, y, w, h, clr, alpha) | |
{ | |
var xIsV = (typeof x.x != 'undefined'); | |
if (xIsV) { // ak je to vektor.. | |
alpha=clr; | |
clr=h; | |
h=w; | |
w=y; | |
y=x.y; | |
x=x.x; | |
} | |
var wIsV = (typeof w.x != 'undefined'); | |
if (wIsV) { | |
alpha=clr; | |
clr=h; | |
h=w.y; | |
w=w.x; | |
} | |
_drawRect(x, y, w, h, clr, alpha); | |
} | |
function drawRectO(ax, ay, bx, by, clr) | |
{ | |
var axIsV = (typeof ax.x != 'undefined'); | |
if (axIsV) { // ak je to vektor.. | |
clr=by; | |
by=bx; | |
bx=ay; | |
ay=ax.y; | |
ax=ax.x; | |
} | |
var bxIsV = (typeof bx.x != 'undefined'); | |
if (bxIsV) { | |
clr=by; | |
by=bx.y; | |
bx=bx.x; | |
} | |
_drawRectO(ax, ay, bx, by, clr); | |
} | |
function _drawRectO(x, y, x2, y2, clr) | |
{ | |
// A---| | |
// |___B | |
drawLine(x, y, x2, y, clr); | |
drawLine(x, y2, x2, y2, clr); | |
drawLine(x, y, x, y2, clr); | |
drawLine(x2, y, x2, y2, clr); | |
} | |
function _drawRect(x, y, w, h, clr, alpha) | |
{ | |
if (typeof alpha == 'undefined') alpha = 1; | |
clr = normalizeClr(clr); | |
dbg.beginFill(clr, alpha); | |
dbg.drawRect(x, y, w, h); | |
} | |
function drawCircle(x, y, r, c, alpha) | |
{ | |
var xIsV = (typeof x.x != 'undefined'); | |
if (xIsV) // ak je to vektor.. | |
{ | |
alpha=c; | |
c=r; | |
r=y; | |
y=x.y; | |
x=x.x; | |
} | |
_drawCircle(x, y, r, c, alpha); | |
} | |
function _drawCircle(x, y, r, c, alpha) | |
{ | |
alpha = alpha || 1; | |
c = normalizeClr(c); | |
dbg.beginFill(c, alpha); | |
dbg.drawCircle(x, y, r); | |
} | |
function normalizeClr(c) | |
{ | |
if (typeof c == 'string' && c.length==3) | |
{ | |
function val(ch) { | |
ch = parseInt(ch, 16); | |
ch = minmax(ch, 0, 15) * 17; | |
return parseInt( ch.toString(16), 16 ); | |
} | |
var i = 0; | |
i += val( c[0] ) * 256*256; | |
i += val( c[1] ) * 256; | |
i += val( c[2] ); | |
c = i; | |
} | |
return c; | |
} | |
var last_fps_change = 0, fps_sum=0, fps_num=0; | |
var last_frame; | |
function get_dt() | |
{ | |
var now = time() * 0.001; | |
if (!last_frame) | |
last_frame = now; | |
var dt = (now - last_frame); | |
// fps | |
var fps = to_i(1/(max(dt, 0.001))); | |
fps_sum += fps; | |
fps_num++; | |
if (abs(last_fps_change - now) > 0.1) | |
{ | |
last_fps_change = now; | |
g_fps = to_i(fps_sum / fps_num); | |
fps_sum = 0; | |
fps_num = 0; | |
} | |
// | |
dt = minmax(dt, 0.000001, 0.1); | |
last_frame = now; | |
return dt; | |
} | |
/////////////////////////////////////////////////////////////////// | |
// libs | |
function floor(f) { return Math.floor(f); } | |
function min(a, b) { return Math.min(a, b); } | |
function max(a, b) { return Math.max(a, b); } | |
function maxn() { | |
if (!arguments.length) return; | |
var mx = arguments[0]; | |
for (var i=1; i < arguments.length; i++) | |
mx = max(mx, arguments[i]); | |
return mx; | |
} | |
function minmax(f, mn, mx) | |
{ | |
if (f > mx) return mx; | |
if (f < mn) return mn; | |
return f; | |
} | |
function minmaxFix(f, mn, mx) | |
{ | |
if (!isOk(f)) return (mn+mx)/2; | |
return minmax(f, mn, mx); | |
} | |
function absmin(a, b) { return sign(a) * min( abs(a), b ); } | |
function absmax(a, b) { return sign(a) * max( abs(a), b ); } | |
function abspow(a, b) { return sign(a) * pow( abs(a), b ); } | |
function abs(f) { return Math.abs(f); } | |
function sqrt(f) { return Math.sqrt(f); } | |
function sign(f) { return f<0?-1:1; } | |
function pow(f, e) { return Math.pow(f, e); } | |
function powe(f) { return pow(2.71828183, f); } | |
function pow10(f) { return pow(10, f); } | |
function logn(f, n) { return loge(f) / loge(n); } | |
function loge(f) { return Math.log(f); } | |
function log10(f) { return loge(f) / Math.log(10); } | |
function minmax(f, mn, mx) { | |
if (f<mn) return mn; | |
if (f>mx) return mx; | |
return f; | |
} | |
function to_i(f) { return parseInt(f); } | |
function to_i255(f) { return parseInt( minmax(f,0,1)*255 ); } | |
function fixed(f, dec) { return parseFloat( f.toFixed(dec) ); } | |
function nicelog() | |
{ | |
var arr = arguments; | |
var s = ''; | |
var len = 0; | |
for (var i=0; i < arr.length; i++) | |
{ | |
if (typeof arr[i] != 'undefined') | |
len = i+1; | |
} | |
for (var i=0; i < len; i++) | |
{ | |
var a = arr[i]; | |
var notFirst = i>0; | |
var isNumber = (typeof a == 'number'); | |
var previousWasString = notFirst && (typeof arr[i-1] == 'string'); | |
if (isNumber) | |
{ | |
a = nice(a); | |
a = (a+'').normalizeLength(10); | |
} | |
// vector | |
if (typeof a.x != 'undefined') | |
a = a.x+' '+a.y; | |
if (!(isNumber && previousWasString)) | |
a = ' '+a; | |
s += a; | |
} | |
console.log(s); | |
} | |
function nice(f) | |
{ | |
var a = abs(f); | |
if (a>=10) return fixed(f); | |
if (a>=1) return fixed(f, 1); | |
if (a>=0.1) return fixed(f, 2); | |
return fixed(f, 3); | |
} | |
function rndsign() { return rndi()?1:-1; } | |
function rnd11(f) { return rnd(-f, f); } | |
/* Maksudnya adalah | |
jika dipanggil dengan argument mx, maka kembalikan | |
x + random * (mx -x ) | |
akan tetapi jika hanya dipanggil dengan argument x | |
makan kembalikan random * x saja. | |
*/ | |
function rnd(x, mx) | |
{ | |
if (typeof x != 'number') x = 1; | |
if (typeof mx == 'number') | |
return x + rnd(mx-x); | |
return Math.random()*x; | |
} | |
function rndi(x, mx) | |
{ | |
if (typeof x != 'number') x = 2; | |
if (typeof mx == 'number') | |
return x + rndi(mx-x); | |
return Math.floor( rnd(x) ); | |
} | |
function rndclr() { return rndi(0xffffff); } | |
function time() | |
{ | |
return (new Date).getTime(); | |
} | |
function removeAt(arr, i) | |
{ | |
if (arr) | |
return arr.splice(i, 1); | |
} | |
function removeEq(arr, x) | |
{ | |
if (arr) | |
for (var i=0; i < arr.length; i++) | |
{ | |
if (arr[i] === x) | |
return arr.splice(i, 1); | |
} | |
} | |
function test_fns() | |
{ | |
var v = v2(2, 5); | |
return; | |
v = v2mult(v, 4); | |
var n = v2norm(v); | |
v = v2sub(v, n); | |
var d2 = v2len2(v); | |
} | |
function test_class() | |
{ | |
var v = new V2(2, 5); | |
return; | |
v.multMe(4); | |
var n = v.norm(); | |
v.subMe(n); | |
var d2 = v.len2(); | |
} | |
test_fns(); | |
test_class(); | |
// ...Me -> v2multMe, etc ma minimalny rozdiel, ale je kratsi zapis | |
// trvanie (1000000x): | |
// var v = v2(1,2); v = v2mult(v, 5); 1550 1590 1600 | |
// var v = v2(1,2); v2multMe(v, 5); 1550 1550 1530 | |
////////////////////////////////////////////////////// | |
function v2(x, y) { return {x:x, y:y}; } | |
function v2c(v) { return {x:v.x, y:v.y}; } | |
function v2copy(v) { return {x:v.x, y:v.y}; } | |
function v2mult(v, f) { return {x:v.x*f, y:v.y*f}; } | |
function v2m(v, f) { return {x:v.x*f, y:v.y*f}; } | |
function v2multxy(v,x,y){ return {x:v.x*x, y:v.y*y}; } | |
function v2multV(v, b) { return {x:v.x*b.x, y:v.y*b.y}; } | |
function v2div(v, f) { return {x:v.x/f, y:v.y/f}; } | |
function v2divV(v, b) { return {x:v.x/b.x, y:v.y/b.y}; } | |
function v2add(v, b) { return {x:v.x+b.x, y:v.y+b.y}; } | |
function v2sub(v, b) { return {x:v.x-b.x, y:v.y-b.y}; } | |
function v2addxy(v, x,y){ return {x:v.x+x, y:v.y+y}; } | |
function v2subxy(v, x,y){ return {x:v.x-x, y:v.y-y}; } | |
function v2inv(v) { return {x:-v.x, y:-v.y}; } | |
function v2len(t) { return Math.sqrt(t.x*t.x + t.y*t.y); } | |
function v2len2(t) { return t.x*t.x + t.y*t.y; } | |
function v2dist(t, v) { var x=t.x-v.x, y=t.y-v.y; return Math.sqrt(x*x+y*y); } | |
function v2dist2(t, v) { var x=t.x-v.x, y=t.y-v.y; return x*x+y*y; } | |
function v2dirTo(t, v) { return v2norm(v2sub(v, t)); } | |
function v2dot(t, v) { return t.x*v.x + t.y*v.y; } | |
function v2p(t) { return t.x.toFixed(2)+' '+t.y.toFixed(2); } | |
function v2null(v) { if (v) v.x=v.y=0; else return {x:0, y:0}; } | |
function v2min(a, b) { return v2( min(a.x,b.x), min(a.y,b.y) ); } | |
function v2max(a, b) { return v2( max(a.x,b.x), max(a.y,b.y) ); } | |
function v2norm(v) | |
{ | |
var len = Math.sqrt(v.x*v.x+v.y*v.y); | |
if (len == 0) len = 1; | |
len = 1/len; | |
return {x: v.x*len, y: v.y*len}; | |
} | |
function v2center(a, b) { return v2add( a, v2mult( v2sub(b,a),0.5 ) ); } | |
function v2perp(a, f) { f=f||1; return v2(-a.y*f, a.x*f); } | |
function v2perpL(a) { return v2(a.y, -a.x); } | |
function v2perpMe(v, f) { f=f||1; var y=v.y; v.y=v.x*f; v.x=-y*f; } | |
function v2perpMeL(v) { var x=v.x; v.x=v.y; v.y=-x; } | |
function v2pow(v, f) { return v2( abspow(v.x, f), abspow(v.y, f) ); } | |
function v2powMe(v, f) { v.x = abspow(v.x, f); v.y = abspow(v.y, f); } | |
function v2avg() | |
{ | |
var v = v2(0, 0); | |
var num = arguments.length; | |
for (var i=0; i < num; i++) | |
{ | |
var a = arguments[i]; | |
v.x += a.x; | |
v.y += a.y; | |
} | |
v2divMe(v, num); | |
return v; | |
} | |
function toRad(deg) { return deg * Math.PI / 180; } | |
function toDeg(rad) { return deg / (Math.PI / 180); } | |
function v2rot(v, ang) | |
{ | |
var rad = toRad(ang); | |
var c = Math.cos(rad); | |
var s = Math.sin(rad); | |
var x = v.x*c - v.y*s; | |
var y = v.x*s + v.y*c; | |
return v2(x, y); | |
} | |
// a,b - circles positions | |
// m - maxDist | |
function v2isCloserThan(a, b, m) | |
{ | |
var x = a.x-b.x; | |
if (x > m || -x > m) return false; | |
var y = a.y-b.y; | |
if (y > m || -y > m) return false; | |
var d2 = x*x + y*y; | |
var m2 = m*m; | |
return (d2 < m2); | |
} | |
function v2isFurtherThan(t, v, maxDist) | |
{ | |
return !v2isCloserThan(t, v, maxDist); | |
} | |
function v2rnd(mn, mx) | |
{ | |
return v2( rnd(mn, mx)*rndsign(), rnd(mn, mx)*rndsign() ); | |
} | |
///////////// | |
function v2multMe(v, f) { v.x*=f; v.y*=f; } | |
function v2divMe(v, f) { v.x/=f; v.y/=f; } | |
function v2addMe(v, b) { v.x+=b.x; v.y+=b.y; } | |
function v2addMex(v, x) { v.x+=x; } | |
function v2addMey(v, y) { v.y+=y; } | |
function v2addMexy(v, x, y) { v.x+=x; v.y+=y; } | |
function v2subMe(v, b) { v.x-=b.x; v.y-=b.y; } | |
function v2normMe(v) | |
{ | |
var len = Math.sqrt(v.x*v.x+v.y*v.y); | |
if (len == 0) len = 1; | |
len = 1/len; | |
v.x*=len; | |
v.y*=len; | |
} | |
////////////////////////////////////////////////////// | |
function V2(x, y) | |
{ | |
var t = this; | |
t.x = x || 0; | |
t.y = y || 0; | |
t.copy = function() | |
{ | |
return new V2(t.x, t.y); | |
} | |
t.set = function(x, y) | |
{ | |
t.x = x; | |
t.y = y; | |
return this; | |
} | |
t.multMe = function(f) | |
{ | |
t.x *= f; | |
t.y *= f; | |
return t; | |
} | |
t.addMe = function(v) | |
{ | |
t.x += v.x; | |
t.y += v.y; | |
return t; | |
} | |
t.subMe = function(v) | |
{ | |
t.x -= v.x; | |
t.y -= v.y; | |
return t; | |
} | |
t.normalizeMe = function() | |
{ | |
var v = normalized(t); | |
t.x = v.x; | |
t.y = v.y; | |
return t; | |
} | |
t.len = function() { return Math.sqrt(t.x*t.x + t.y*t.y); } | |
t.len2 = function() { return t.x*t.x + t.y*t.y; } | |
t.dist = function(v) { var x=t.x-v.x, y=t.y-v.y; return Math.sqrt(x*x+y*y); } | |
t.dist2 = function(v) { var x=t.x-v.x, y=t.y-v.y; return x*x+y*y; } | |
t.dirTo = function(v) { return v.sub(t).norm(); } | |
// operatory: c=a*f -> c=a.mult(f) | |
t.norm = function() { return normalized(t); } | |
t.dot = function(v) { return t.x*v.x + t.y*v.y; } | |
t.mult = function(f) { return new V2(t.x*f, t.y*f); } | |
t.sub = function(v) { return new V2(t.x-v.x, t.y-v.y); } | |
t.add = function(v) { return new V2(t.x+v.x, t.y+v.y); } | |
t.isFurtherThan = function(v, maxDist) | |
{ | |
var d2 = t.dist2(v); | |
var m2 = maxDist*maxDist; | |
if (d2 > m2) | |
return true; | |
} | |
function normalized(a) | |
{ | |
var len = a.len(); | |
var inv = len>0 ? 1/len : 1; | |
var x = a.x * inv; | |
var y = a.y * inv; | |
return new V2(x, y); | |
} | |
// len pre zaujimavost, toto je 3-tia verzia funkcie, ktora nasobi.. | |
// treba to nejak domysliet, ako umoznit spravit jeden vzorec | |
// podla ktoreho sa vygeneruju vsetky druhy funkcii | |
t.multing = function(a, b) | |
{ | |
return new V2(a.x*b.y - a.y*b.x); | |
} | |
t.p = function() | |
{ | |
return t.x.toFixed(2)+' '+t.y.toFixed(2); | |
} | |
} | |
</script> | |
<body> | |
<canvas id="c"></canvas> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment