let reacts=[],lt=0,testcraft,rnd,rd2,r=[0,0,1],fr=60,fSamples=10,pn=0,grTex,wtTex,glContext,anchor,lxz=300,dt=1,frs=[],players=[],
createCanvas(Math.min(windowWidth-10,800),Math.min(windowHeight-10,550))
grTex=createGraphics(200,200)
grTex.fill(196,120,57);grTex.noStroke()
grTex.circle(Math.floor(Math.random()*200),Math.floor(Math.random()*200),4)
rnd=createGraphics(width,height,WEBGL)
rd2=createGraphics(1,3,WEBGL)
glContext=rnd._renderer.GL
rnd.frustum(-Math.min(width,height)/height/10,Math.min(width,height)/height/10,Math.min(width,height)/width/10,-Math.min(width,height)/width/10,0.1,1e5)
rd2.frustum(-Math.min(width,height)/height/10,Math.min(width,height)/height/10,Math.min(width,height)/width/10,-Math.min(width,height)/width/10,0.1,1e5)
testReact.generateFriction='[0,0,0]'
testReact.returnCollides=1
reactive:{anchor:{p:[450,-30,450]}}
testcraft.addFixture([2,0,1])
testcraft.addFixture([2,0,-1])
testcraft.addFixture([2,0.3,0])
testcraft.addFixture([2,-0.3,0])
testcraft.addFixture([3,0,0])
testcraft.addFixture([1,0,0])
testcraft.addJoint([0,0,-2],[0,0,1],-1,{friction:0.001,stiff:1})
testcraft.addJoint([0,0,2],[0,0,1],-1,{friction:0.001,stiff:1})
testcraft.joints[1].a.a=[[1,0,0],[0,-1,0]]
testcraft.addFixture([Math.cos(Math.PI*2/20*i),Math.sin(Math.PI*2/20*i),-2],{grip:0.5,rebound:0.2},0)
testcraft.addFixture([Math.cos(Math.PI*2/20*i),Math.sin(Math.PI*2/20*i),2],{grip:0.5,rebound:0.2},0)
testcraft.addJoint([4,0,0],[0,1,0],-1,{friction:10,stiff:0.1})
testcraft.addJoint([4,0,0],[0,0,1],2,{friction:0.001,stiff:1})
testcraft.addFixture([4+Math.cos(Math.PI*2/20*i),Math.sin(Math.PI*2/20*i),0],{grip:0.5,rebound:0.2},3)
reactive:{anchor:{p:[450,-30,450]}}
b.addFixture([0.5,0,-0.5])
b.addFixture([0.5,0,0.5])
b.addFixture([-0.5,-0.2,-0.5])
b.addFixture([-0.5,0.2,0.5])
b.addFace(a+4,a,a+2,0,20)
b.addFace(a+4,a+5,a+2,0,20)
b.addFace(a+4,a+1,a+3,0,20)
b.addFace(a+4,a+5,a+3,0,20)
b.addEdge(a,a+1,0,'#999')
b.addEdge(a+2,a+3,0,'#999')
b.addEdge(a,a+2,0,'#999')
b.addEdge(a+1,a+3,0,'#999')
b.addFixture([0.5,0.5,0])
b.addFixture([0.5,-0.5,0])
b.addFixture([-0.5,0.5,-0.2])
b.addFixture([-0.5,-0.5,0.2])
b.addFace(a+4,a,a+2,0,20)
b.addFace(a+4,a+5,a+2,0,20)
b.addFace(a+4,a+1,a+3,0,20)
b.addFace(a+4,a+5,a+3,0,20)
b.addEdge(a,a+1,0,'#999')
b.addEdge(a+2,a+3,0,'#999')
b.addEdge(a,a+2,0,'#999')
b.addEdge(a+1,a+3,0,'#999')
SCH.addServer('sketch162230','SND')
SCH.addServer('https://echoserver.lrCr.repl.co','RPL')
SCH.addServer('https://echoes-vm.herokuapp.com','HKU')
SCH.whenPing((t1,t2,t3)=>{pn=t3-t1})
let a=players.filter(x=>x.id2==e.id2)
if(!a[0].t||(a[0].t<e.t)){
a[0].a=e2.a||[[0,0,1],[0,1,0]]
players.push({id:e.id,id2:e.id2,m:e.m,t:e.t,fix:e2.fix||[],edges:e2.edges||[],fc:e2.fc||[],faces:e2.faces||[],p:e2.p||[0,0,0],a:e2.a||[[0,0,1],[0,1,0]]})
frs=frs.slice(1,frs.length)
if(frs.length!=fSamples)console.log('ccc')
for(let i=0;i<frs.length;i++){
if(mouseButton==LEFT&&mouseIsPressed){
r[0]-=(mouseX-pmouseX)/200
r[1]=Math.max(-Math.PI/2,Math.min(Math.PI/2,r[1]+(mouseY-pmouseY)/200))
lt=(lt+reacts.length)%reacts.length
anchor=reacts[lt].reactive
if(keyIsDown(192))reacts[1].applyForce([0,1,0],[0,0,1])
if(keyIsDown(192))reacts[1].applyForce([0,-1,0],[0,0,-1])
if(keyIsDown(87))testcraft.applyJointForce(0,[1,0,0],[0,6,0])
if(keyIsDown(83))testcraft.applyJointForce(0,[1,0,0],[0,-6,0])
testcraft.turnJoint(2,[-1,0,1],[0,0,1],5,200)
testcraft.turnJoint(2,[1,0,1],[0,0,1],5,200)
testcraft.turnJoint(2,[0,0,1],[0,0,1],5,200)
let xz=r[2]*Math.min(300,lxz+20),rt=50,sp=r[2]*10
let dr_r=eval('['+getCamData()+']')
let cp=vadd(anchor.anchor.p,vmultf([dr_r[0],dr_r[1],dr_r[2]],1/30))
testReact.anchor.a=[[1,0,0],[0,1,0]]
testReact.anchor.v=[0,0,0]
testReact.anchor.r=[[0,0,0],[0,0,0]]
let n=testReact.collidef(p=>{
let s=[Math.max(0,Math.min(ns.dm[0]-1,Math.floor(p[0]/ns.sc))),Math.max(0,Math.min(ns.dm[1]-1,Math.floor(p[2]/ns.sc)))]
if((p[0]/ns.sc+p[2]/ns.sc-Math.floor(p[0]/ns.sc)-Math.floor(p[2]/ns.sc))>1){
if((p[2]/ns.sc+Math.ceil(p[0]/ns.sc)-p[0]/ns.sc-Math.floor(p[2]/ns.sc))>1){
if((p[2]/ns.sc+Math.ceil(p[0]/ns.sc)-p[0]/ns.sc-Math.floor(p[2]/ns.sc))>1){
return {p:[0,20,0],d:[[0,0,1],[0,1,0]]}
eval('rnd.camera('+getCamData()+')')
rnd.fill(130,176,250);rnd.noStroke()
glContext.clear(glContext.DEPTH_BUFFER_BIT)
rnd.translate(...vmultf(anchor.anchor.p,-30))
rnd.fill(255);rnd.stroke(0)
let x=Math.min(4,Math.ceil(dt)),dr_r=eval('['+getCamData()+']')
let drs=vmultf(vnorm([dr_r[0]-dr_r[3],0,dr_r[2]-dr_r[5]]),-5),cp=vadd(anchor.anchor.p,vmultf([dr_r[0],dr_r[1],dr_r[2]],1/30))
if(keyIsDown(32))anchor.applyForce([0,0,0],anchor.absolNormal([0,-9*x,0]))
if(keyIsDown(16))anchor.applyForce([0,0,0],anchor.absolNormal([0,5*x,0]))
if(keyIsDown(74))anchor.applyForce([0,0,0],anchor.absolNormal(vmultf(vcross(drs,[0,-1,0]),x)))
if(keyIsDown(76))anchor.applyForce([0,0,0],anchor.absolNormal(vmultf(vcross(drs,[0,1,0]),x)))
if(keyIsDown(73))anchor.applyForce([0,0,0],anchor.absolNormal(vmultf(drs,x)))
if(keyIsDown(75))anchor.applyForce([0,0,0],anchor.absolNormal(vmultf(drs,-x)))
for(let i=0;i<players.length;i++){
if(players[i].p&&players[i].a&&players[i].faces&&players[i].fix&&players[i].edges){
if(players[i].p)rnd.strokeWeight(5/(1+vmag(vadd(cp,vmultf(players[i].p,-1)))/30))
for(let f=0;f<players[i].edges.length;f++){
rnd.stroke(players[i].edges[f].c)
rnd.line(...vtransform(players[i].a,players[i].p,players[i].fix[players[i].edges[f].p[0]]),...vtransform(players[i].a,players[i].p,players[i].fix[players[i].edges[f].p[1]]))
for(let f=0;f<players[i].faces.length;f++){
rnd.fill(players[i].faces[f].c)
rnd.vertex(...vtransform(players[i].a,players[i].p,players[i].fix[players[i].faces[f].p[0]]))
rnd.vertex(...vtransform(players[i].a,players[i].p,players[i].fix[players[i].faces[f].p[1]]))
rnd.vertex(...vtransform(players[i].a,players[i].p,players[i].fix[players[i].faces[f].p[2]]))
for(let f=0;f<players[i].fix.length;f++){
rnd.stroke(players[i].fc[f])
rnd.point(...vtransform(players[i].a,players[i].p,players[i].fix[f]))
players=players.filter(x=>x.m)
for(let i=0;i<reacts.length;i++){
reacts[i].applyForce([0,0,0],reacts[i].reactive.absolNormal([0,8,0]))
reacts[i].collide(dt/x,[0,0,0],[[0,0,1],[-1,0,0]])
reacts[i].collide(dt/x,[0,0,0],[[1,0,0],[0,0,-1]])
reacts[i].collide(dt/x,[ns.dm[0]*ns.sc-ns.sc*1,0,ns.dm[0]*ns.sc-ns.sc*1],[[0,0,1],[1,0,0]])
reacts[i].collide(dt/x,[ns.dm[0]*ns.sc-ns.sc*1,0,ns.dm[0]*ns.sc-ns.sc*1],[[1,0,0],[0,0,1]])
reacts[i].collide(dt/x,[0,10,0],[[0,0,1],[0,1,0]])
reacts[i].collidef(dt/x,p=>{
let s=[Math.max(0,Math.min(ns.dm[0]-1,Math.floor(p[0]/ns.sc))),Math.max(0,Math.min(ns.dm[1]-1,Math.floor(p[2]/ns.sc)))]
if((p[0]/ns.sc+p[2]/ns.sc-Math.floor(p[0]/ns.sc)-Math.floor(p[2]/ns.sc))>1){
if((p[2]/ns.sc+Math.ceil(p[0]/ns.sc)-p[0]/ns.sc-Math.floor(p[2]/ns.sc))>1){
if((p[2]/ns.sc+Math.ceil(p[0]/ns.sc)-p[0]/ns.sc-Math.floor(p[2]/ns.sc))>1){
return {p:[0,20,0],d:[[0,0,1],[0,1,0]]}
let n=reacts[i].joints.length
reacts[i].applyJointForce(y,reacts[i].joints[y].axis[0]?[0,1,0]:[1,0,0],vmultf(reacts[i].joints[y].a.r[reacts[i].joints[y].axis[0]?1:0],reacts[i].joints[y].friction))
for(let i=0;i<reacts.length;i++){
let r=(1+vmag(vadd(cp,vmultf(reacts[i].reactive.anchor.p,-1)))/30)
rnd.line(...reacts[i].reactive.anchor.p,...vadd(reacts[i].reactive.anchor.p,reacts[i].reactive.anchor.a[0]))
rnd.line(...reacts[i].reactive.anchor.p,...vadd(reacts[i].reactive.anchor.p,reacts[i].reactive.anchor.a[1]))
rnd.line(...reacts[i].reactive.anchor.p,...vadd(reacts[i].reactive.anchor.p,vcross(...reacts[i].reactive.anchor.a)))
for(let f=0;f<reacts[i].edges.length;f++){
rnd.stroke(reacts[i].edges[f].c)
rnd.line(...reacts[i].reactive.fromGrid(reacts[i].reactive.fix[reacts[i].edges[f].p[0]]),...reacts[i].reactive.fromGrid(reacts[i].reactive.fix[reacts[i].edges[f].p[1]]))
for(let f=0;f<reacts[i].faces.length;f++){
rnd.fill(reacts[i].faces[f].c)
rnd.vertex(...reacts[i].reactive.fromGrid(reacts[i].reactive.fix[reacts[i].faces[f].p[0]]))
rnd.vertex(...reacts[i].reactive.fromGrid(reacts[i].reactive.fix[reacts[i].faces[f].p[1]]))
rnd.vertex(...reacts[i].reactive.fromGrid(reacts[i].reactive.fix[reacts[i].faces[f].p[2]]))
for(let f=0;f<reacts[i].reactive.fix.length;f++){
rnd.stroke(reacts[i].fix[f].ptCol[0])
rnd.point(...reacts[i].reactive.fromGrid(reacts[i].reactive.fix[f]))
for(let f=0;f<reacts[i].joints.length;f++){
rnd.line(...reacts[i].reactive.fromGrid(vadd(reacts[i].p_jt[0][f],reacts[i].p_jt[2])),
...reacts[i].reactive.fromGrid(vadd(vadd(reacts[i].p_jt[0][f],reacts[i].p_jt[1][f][1]),reacts[i].p_jt[2])))
for(let f=0;f<reacts[i].joints.length;f++){
let axis=[0,0,0],b=[...reacts[i].p_jt[1][f],vcross(...reacts[i].p_jt[1][f])]
for(let h=0;h<3;h++){for(let m=0;m<3;m++){axis[m]+=b[h][m]*reacts[i].joints[f].axis[h]}}
rnd.line(...reacts[i].reactive.fromGrid(vadd(reacts[i].p_jt[0][f],reacts[i].p_jt[2])),
...reacts[i].reactive.fromGrid(vadd(vadd(reacts[i].p_jt[0][f],axis),reacts[i].p_jt[2])))
rnd.stroke(0);rnd.strokeWeight(2/r)
rnd.line(...reacts[i].reactive.anchor.p,...vadd(reacts[i].reactive.anchor.p,vmultf(reacts[i].reactive.anchor.v,100)))
image(rnd,0,0,width,height)
if(frameCount%10==0)fr=Math.floor(frs.reduce((a,b)=>a+b)/fSamples)
text('FPS: '+fr.toString(),10,10)
text((SCH.connected?'Server: '+SCH.server:'Connecting to server...'),width-10,10)
text(SCH.sockets[SCH.chosenSocket].u.startsWith('sketch')?'Ping unavailable on server SND':('Ping: '+pn.toString()),width-10,30)
text('Subdivisions: '+x.toString(),width-10,50)
if(frameCount%10==0)SCH.ping(Date.now())
for(let i=0;i<reacts.length;i++){
id2:SCH.id+'_fix'+i.toString(),m:150,t:frameCount,
edges:reacts[i].edges,fix:reacts[i].reactive.fix,fc:reacts[i].fc,faces:reacts[i].faces,p:reacts[i].reactive.anchor.p,a:reacts[i].reactive.anchor.a
fill(0);noStroke();textAlign(CENTER,CENTER);textSize(30)
text('Loading...',width/2,height/2)
if(keyCode==UP_ARROW)lt++
if(keyCode==DOWN_ARROW)lt--
if(key=='c')cameraMode=(cameraMode+1)%cameraModes
r[2]=Math.max(0.1,Math.min(10,r[2]*(1+e.delta/1000)))