Skip to content

Commit

Permalink
add collision detection
Browse files Browse the repository at this point in the history
  • Loading branch information
kynd committed Jun 28, 2017
1 parent 95b2195 commit d307955
Show file tree
Hide file tree
Showing 9 changed files with 375 additions and 5 deletions.
65 changes: 65 additions & 0 deletions collision.html
@@ -0,0 +1,65 @@

<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
<title>Detecting Collision</title>
<link href="https://fonts.googleapis.com/css?family=Amatic+SC:400,700|Fredericka+the+Great|Open+Sans:300,400|Roboto+Mono:300" rel="stylesheet">
<link href="css/style.css" rel="stylesheet">
</head>
<body>
<div id="header"><div class="example" data-embed="collision/collision_triangles"></div></div>

<div id="main">
<h1>Detecting Collision</h1>
<p><a href="index.html">Sketching with Math and Quasi Physics</a></p>

<h2>Circles</h2>
<p>Two circles, <span class="math-wrapper">
\(A\)</span> and <span class="math-wrapper">
\(B\)</span> collide if <a href="handy_math.html#distance">the distance between the center points</a> is equal or less than the two radii added together.</p>
<div class="math-wrapper">
<p>$$distance(A_{center},B_{center}) \leq A_{radius}+B_{radius}\Rightarrow$$</p>
<p>$$distance(A_{center},B_{center})-A_{radius}-B_{radius}\leq 0$$</p>
</div>

<div class="example" data-embed="collision/collision_circles" data-edit="https://codepen.io/kynd/pen/MorWPr"></div>

<h2>Rectangles</h2>
<p>Two rectangles, <span class="math-wrapper">
\(A\)</span> and <span class="math-wrapper">
\(B\)</span> that are axis aligned collide if</p>
<div class="math-wrapper">
<p>$$(A_{left}\leq B_{right})\;\wedge\;(A_{right}\geq B_{left})\;\wedge\;(A_{top}\leq B_{bottom})\wedge(A_{bottom}\geq B_{top})$$</p>
</div>
<p>This is to project the shapes to x and y-axis and checking overlap on each axis. Note that screen coordinate system in which y increase from top to bottom is assumed.</p>

<div class="example" data-embed="collision/collision_rectangles" data-edit="https://codepen.io/kynd/pen/eRyYLV"></div>


<h2>Triangles</h2>
<p>Similarly, collision between two convex polygons can be detected by <a href="handy_math.html#dot_product">projecting the shapes to the vectors</a> perpendicular to each side of one of the polygons.</p>

<div class="example" data-embed="collision/collision_triangles" data-edit="https://codepen.io/kynd/pen/GEyRXg"></div>

<h3>Learn More</h3>
<p><a href="https://gamedevelopment.tutsplus.com/tutorials/collision-detection-using-the-separating-axis-theorem--gamedev-169" target="_blank">Collision Detection Using the Separating Axis Theorem</a></p>

<br/>
<br/>

<p><a href="index.html">index</a></p>
<footer><a href="https://twitter.com/kyndinfo">kynd</a> 2017 | Please suggest edits and/or better code at <a href="https://github.com/kynd/p5sketches">Github</a></footer>
</div>

<script src="js/main.js" type="text/javascript"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.11.0/styles/vs.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.11.0/highlight.min.js"></script>

<script type="text/javascript"
src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.0/MathJax.js?config=TeX-AMS_CHTML">
</script>

</body>
</html>
23 changes: 23 additions & 0 deletions dev.html
@@ -0,0 +1,23 @@

<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
<title>Dev</title>
<link href="https://fonts.googleapis.com/css?family=Amatic+SC:400,700|Fredericka+the+Great|Open+Sans:300,400|Roboto+Mono:300" rel="stylesheet">
<link href="css/style.css" rel="stylesheet">
</head>
<body>
<div id="header"><div class="example" data-embed="physics/gravity"></div></div>

<script src="js/main.js" type="text/javascript"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.11.0/styles/vs.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.11.0/highlight.min.js"></script>

<script type="text/javascript"
src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.0/MathJax.js?config=TeX-AMS_CHTML">
</script>

</body>
</html>
4 changes: 1 addition & 3 deletions extra/wave_function/bundle.js
Expand Up @@ -16,12 +16,10 @@ class glRenderer {

init() {
let gl = this.shell.gl;
this.shell.canvas.setAttribute("width", 640);
this.shell.canvas.setAttribute("height", 640);
//this.shell.on("tick", this.update.bind(this));
this.shell.on("gl-render", this.draw.bind(this));

this.updateShader = glShader( gl, glslify(["#define GLSLIFY 1\nattribute vec2 position;\nvarying vec2 uv;\n\nvoid main() {\n gl_Position = vec4(position,0.0,1.0);\n uv = 0.5 * (position+1.0);\n}\n"]), glslify(["\nprecision mediump float;\n#define GLSLIFY 1\nuniform float frameCount;\nuniform sampler2D buffer;\nuniform vec2 dims;\nvarying vec2 uv;\n\nvoid main() {\n\n vec4 color;\n if (length(uv - vec2(0.5, 0.7)) < 0.025) {\n // source\n color = vec4(0.5 + sin(frameCount * 0.5) * 0.2 * (sin(frameCount * 0.05) + 1.0), 0.5, 0.5, 1.0);\n } else if (abs(uv.x - 0.5) < 0.3 && abs(uv.y - 0.5) < 0.02) {\n color = vec4(0.5, 0.5, 0.5, 1.0);\n } else {\n vec4 samp = texture2D(buffer, uv);\n float va = samp.r;\n\n vec2 d[4];\n d[0] = vec2(-1.0, -0.0);\n d[1] = vec2(0.0, -1.0);\n d[2] = vec2(1.0, 0.0);\n d[3] = vec2(-0.0, 1.0);\n\n float vb = 0.0;\n for (int i = 0; i < 4; i ++) {\n vb += texture2D(buffer, uv + d[i] / dims * 2.0).r;\n }\n float vc = samp.g;\n samp.b = va * 2.0 + 0.2 * (vb - va * 4.0) - vc;\n color = clamp(vec4(0.0), vec4(1.0), samp.brga);\n }\n\n gl_FragColor = color;\n}\n"]) );
this.updateShader = glShader( gl, glslify(["#define GLSLIFY 1\nattribute vec2 position;\nvarying vec2 uv;\n\nvoid main() {\n gl_Position = vec4(position,0.0,1.0);\n uv = 0.5 * (position+1.0);\n}\n"]), glslify(["\nprecision mediump float;\n#define GLSLIFY 1\nuniform float frameCount;\nuniform sampler2D buffer;\nuniform vec2 dims;\nvarying vec2 uv;\n\nvoid main() {\n\n vec4 color;\n if (length(uv - vec2(0.5, 0.7)) < 0.025) {\n // Source\n color = vec4(0.5 + sin(frameCount * 0.5) * 0.2 * (sin(frameCount * 0.05) + 1.0), 0.5, 0.5, 1.0);\n } else if (abs(uv.x - 0.5) < 0.3 && abs(uv.y - 0.5) < 0.02) {\n // Obstacle\n color = vec4(0.5, 0.5, 0.5, 1.0);\n } else {\n vec4 samp = texture2D(buffer, uv);\n float va = samp.r;\n\n vec2 d[4];\n d[0] = vec2(-1.0, -0.0);\n d[1] = vec2(0.0, -1.0);\n d[2] = vec2(1.0, 0.0);\n d[3] = vec2(-0.0, 1.0);\n\n float vb = 0.0;\n for (int i = 0; i < 4; i ++) {\n vb += texture2D(buffer, uv + d[i] / dims * 2.0).r;\n }\n \n float vc = samp.g;\n samp.b = va * 2.0 + 0.2 * (vb - va * 4.0) - vc;\n color = clamp(vec4(0.0), vec4(1.0), samp.brga);\n }\n\n gl_FragColor = color;\n}\n"]) );
this.renderShader = glShader( gl, glslify(["#define GLSLIFY 1\nattribute vec2 position;\nvarying vec2 uv;\n\nvoid main() {\n gl_Position = vec4(position,0.0,1.0);\n uv = 0.5 * (position+1.0);\n}\n"]), glslify(["precision mediump float;\n#define GLSLIFY 1\nuniform sampler2D buffer;\nuniform int channelIndex;\nuniform vec2 dims;\nvarying vec2 uv;\n\nvoid main() {\n vec4 samp0 = texture2D(buffer, uv + vec2(0.0, -1.0) / dims);\n vec4 samp1 = texture2D(buffer, uv + vec2(0.0, 1.0) / dims);\n\n vec4 color = vec4(0.88, 0.94, 0.95, 1.0);\n if (abs(uv.x - 0.5) < 0.3 && abs(uv.y - 0.5) < 0.02) {\n color = vec4(0.0, 0.0, 0.0, 1.0);\n }\n color.rgb -= smoothstep(0.026, 0.025, length(uv - vec2(0.5, 0.7)));\n\n float v = smoothstep(0.0, 0.1, samp0.r - samp1.r);\n color = vec4(color.rgb * (1.0 - v), 1.0);\n gl_FragColor = color;\n}\n"]) );

let w = 640, h = 640;
Expand Down
4 changes: 2 additions & 2 deletions handy_math.html
Expand Up @@ -34,7 +34,7 @@ <h2>Rotate 2D points</h2>
<h3>Learn more</h3>
<p><a href="http://www.alanzucconi.com/2016/02/03/2d-rotations/" target="_blank">A Gentle Primer on 2D Rotations</a></p>

<h2>Euclidean distance between two points</h2>
<h2 id="distance">Euclidean distance between two points</h2>

<div class="math-wrapper">
<h3>Two dimensions</h3>
Expand Down Expand Up @@ -62,7 +62,7 @@ <h2>Perspective Projection (Fixed Camera)</h2>
<div class="example" data-embed="math/perspective" data-edit='https://codepen.io/kynd/pen/pPqOYP'></div>


<h2>Dot Product</h2>
<h2 id="dot_product">Dot Product</h2>
<h3>Two dimensions</h3>
<div class="math-wrapper">
<p>$${\boldsymbol v}_\mathbf1=\lbrack x_1,y_1\rbrack,\hspace{8px}{\boldsymbol v}_\mathbf2=\lbrack x_2,y_2\rbrack$$</p>
Expand Down
64 changes: 64 additions & 0 deletions js/examples/collision/collision_circles.js
@@ -0,0 +1,64 @@
let A, B;

function setup() {
canvas = createCanvas(windowWidth, windowHeight);

A = {center: createVector(), radius: 80};
B = {center: createVector(), radius: 60};
}

function draw() {
clear();
background(249, 246, 236);
let t = radians(frameCount) / 2;
A.center.x = cos(t) * 120;
A.center.y = sin((t + 1) * 2) * 120;
B.center.x = -cos((t + 2) * 3) * 100;
B.center.y = -sin((t + 3) * 4) * 100;

// test

let result = A.center.dist(B.center) - A.radius - B.radius <= 0;

// rendering

push();
translate(width / 2, height / 2);

noStroke();
if (result) {
fill(225, 81, 106);
} else {
fill(255);
}
ellipse(A.center.x, A.center.y, A.radius * 2);
ellipse(B.center.x, B.center.y, B.radius * 2);

noFill(); stroke(0); strokeWeight(1);
ellipse(A.center.x, A.center.y, A.radius * 2);
ellipse(B.center.x, B.center.y, B.radius * 2);

let pA = A.center.copy().add(B.center.copy().sub(A.center).normalize().mult(A.radius));
let pB = B.center.copy().add(A.center.copy().sub(B.center).normalize().mult(B.radius));

strokeWeight(1);
let boundary = {x: -width / 2, y: -height / 2, w: width, h: height};
let l = new Line().fromTwoPoints(A.center, B.center);
let perpA = l.getPerpendicular(pA);
let perpB = l.getPerpendicular(pB);
l.draw(boundary);

stroke(0, 0, 0, 128);
perpA.draw(boundary);
perpB.draw(boundary);

if (result) {
strokeWeight(3);
stroke(0, 0, 0, 255);
line(pA.x, pA.y, pB.x, pB.y);
}

pop();
}

/** Line **/
74 changes: 74 additions & 0 deletions js/examples/collision/collision_rectangles.js
@@ -0,0 +1,74 @@
let A, B;

function setup() {
canvas = createCanvas(windowWidth, windowHeight);

A = {x: 0, y: 0, w: 160, h: 90};
B = {x: 0, y: 0, w: 90, h: 160};
}

function draw() {
clear();
background(249, 246, 236);
let t = radians(frameCount) / 2;
A.x = cos(t) * 120 - A.w / 2;
A.y = sin(t * 2) * 120 - A.h / 2;
B.x = -cos(t * 3) * 120 - B.w / 2;
B.y = -sin(t * 4) * 120 - B.h / 2;

// test

let xResult = A.x <= B.x + B.w && A.x + A.w >= B.x;
let yResult = A.y <= B.y + B.h && A.h + A.y >= B.y;
let result = xResult && yResult;

// rendering

push();
translate(width / 2, height / 2);

noStroke();
if (result) {
fill(225, 81, 106);
} else {
fill(255);
}
rect(A.x, A.y, A.w, A.h);
rect(B.x, B.y, B.w, B.h);

noFill(); stroke(0); strokeWeight(1);
rect(A.x, A.y, A.w, A.h);
rect(B.x, B.y, B.w, B.h);

fill(0); strokeWeight(1);
let l0 = -width / 2, l1 = l0 + 16;
let b0 = height / 2, b1 = b0 - 16;

line(-width / 2, b1, width / 2, b1);
line(l1, -height / 2, l1, height / 2);

stroke(0, 0, 0, 32);
line(A.x, A.y, A.x, b0);
line(A.x + A.w, A.y, A.x + A.w, b0);
line(A.x, A.y, l0, A.y);
line(A.x, A.y + A.h, l0, A.y + A.h);

line(B.x, B.y, l0, B.y);
line(B.x, B.y + B.h, l0, B.y + B.h);
line(B.x, B.y, B.x, b0);
line(B.x + B.w, B.y, B.x + B.w, b0);

stroke(0);
strokeWeight(3);
if (xResult) {
let sorted = [A.x, B.x + B.w, A.x + A.w, B.x].sort((a,b)=>{return a > b ? 1: -1});
line(sorted[1], b1, sorted[2], b1);
}

if (yResult) {
let sorted = [A.y, B.y + B.h, A.y + A.h, B.y].sort((a,b)=>{return a > b ? 1: -1});
line(l1, sorted[1], l1, sorted[2]);
}

pop();
}

0 comments on commit d307955

Please sign in to comment.