Skip to content

Instantly share code, notes, and snippets.

@rolandkorgowski
Created November 8, 2020 20:53
Show Gist options
  • Save rolandkorgowski/5affa926ba2e0a33c2dd91f3c63f05be to your computer and use it in GitHub Desktop.
Save rolandkorgowski/5affa926ba2e0a33c2dd91f3c63f05be to your computer and use it in GitHub Desktop.
11012020 - JavaScript
/*
* File Name / template.js
* Created Date / Oct 01, 2020
* Aurhor / Toshiya Marukubo
* Twitter / https://twitter.com/toshiyamarukubo
*/
/*
Common Tool.
*/
class Tool {
// random number.
static randomNumber(min, max) {
return Math.floor(Math.random() * (max - min + 1) + min);
}
// random color rgb.
static randomColorRGB() {
return (
"rgb(" +
this.randomNumber(0, 255) +
", " +
this.randomNumber(0, 255) +
", " +
this.randomNumber(0, 255) +
")"
);
}
// random color hsl.
static randomColorHSL(hue, saturation, lightness) {
return (
"hsl(" +
hue +
", " +
saturation +
"%, " +
lightness +
"%)"
);
}
// gradient color.
static gradientColor(ctx, cr, cg, cb, ca, x, y, r) {
const col = cr + "," + cg + "," + cb;
const g = ctx.createRadialGradient(x, y, 0, x, y, r);
g.addColorStop(0, "rgba(" + col + ", " + (ca * 1) + ")");
g.addColorStop(0.5, "rgba(" + col + ", " + (ca * 0.5) + ")");
g.addColorStop(1, "rgba(" + col + ", " + (ca * 0) + ")");
return g;
}
// framerate
static calcFPS() {
const now = (+new Date());
const fps = 1000 / (now - lastTime);
lastTime = now;
return fps.toFixed();
}
}
/*
When want to use angle.
*/
class Angle {
constructor(angle) {
this.a = angle;
this.rad = this.a * Math.PI / 180;
}
incDec(num) {
this.a += num;
this.rad = this.a * Math.PI / 180;
return this.rad;
}
}
/*
When want to use vector.
*/
class Vector2d {
constructor(x, y) {
this.vx = x;
this.vy = y;
}
scale(scale) {
this.vx *= scale;
this.vy *= scale;
}
add(vec2) {
this.vx += vec2.vx;
this.vy += vec2.vy
}
sub(vec2) {
this.vx -= vec2.vx;
this.vy -= vec2.vy;
}
negate() {
this.vx = -this.vx;
this.vy = -this.vy;
}
length() {
return Math.sqrt(this.vx * this.vx + this.vy * this.vy);
}
lengthSquared() {
return this.vx * this.vx + this.vy * this.vy;
}
normalize() {
let len = Math.sqrt(this.vx * this.vx + this.vy * this.vy);
if (len) {
this.vx /= len;
this.vy /= len;
}
return len;
}
rotate(angle) {
let vx = this.vx;
let vy = this.vy;
let cosVal = Math.cos(angle);
let sinVal = Math.sin(angle);
this.vx = vx * cosVal - vy * sinVal;
this.vy = vx * sinVal + vy * cosVal;
}
toString() {
return '(' + this.vx.toFixed(3) + ',' + this.vy.toFixed(3) + ')';
}
}
/*
When want to use time.
*/
class Stopwatch {
constructor(time) {
this.startTime = 0;
this.running = false;
this.elapsed = undefined;
}
start() {
this.startTime = +new Date();
this.elapsedTime = null;
this.running = true;
}
stop() {
this.elapsed = (+new Date()) - this.startTime;
this.running = false;
}
getElapsedTime() {
if (this.running) {
return (+new Date()) - this.startTime;
} else {
return this.elapsed;
}
}
isRunning() {
return this.running;
}
reset() {
this.elapsed = 0;
}
}
/*
When want to use collision detection.
*/
class Collision {
constructor(targetArr) {
this.arr = targetArr;
}
collideAll() {
let vec = new Vector2d(0, 0);
let dist;
let obj1;
let obj2;
let c;
let i;
for (c = 0; c < this.arr.length; c++) {
obj1 = this.arr[c];
for (i = c + 1; i < this.arr.length; i++) {
obj2 = this.arr[i];
vec.vx = obj2.x - obj1.x;
vec.vy = obj2.y - obj1.y;
dist = vec.length();
if (dist < obj1.r + obj2.r) {
vec.normalize();
vec.scale(obj1.r + obj2.r - dist);
vec.negate();
obj1.x += vec.vx;
obj1.y += vec.vy;
this.bounce(obj1, obj2);
}
}
}
}
bounce(obj1, obj2) {
let colnAngle = Math.atan2(obj1.y - obj2.y, obj1.x - obj2.x);
let length1 = obj1.v.length();
let length2 = obj2.v.length();
let dirAngle1 = Math.atan2(obj1.v.vy, obj1.v.vx);
let dirAngle2 = Math.atan2(obj2.v.vy, obj2.v.vx);
let newVX1 = length1 * Math.cos(dirAngle1 - colnAngle);
let newVX2 = length2 * Math.cos(dirAngle2 - colnAngle);
obj1.v.vy = length1 * Math.sin(dirAngle1 - colnAngle);
obj2.v.vy = length2 * Math.sin(dirAngle2 - colnAngle);
obj1.v.vx = ((obj1.r - obj2.r) * newVX1 + (2 * obj2.r) * newVX2) / (obj1.r + obj2.r);
obj2.v.vx = ((obj2.r - obj1.r) * newVX2 + (2 * obj1.r) * newVX1) / (obj1.r + obj2.r);
obj1.v.rotate(colnAngle);
obj2.v.rotate(colnAngle);
}
}
/*
When want to use controller.
*/
class Controller {
constructor(id) {
this.id = document.getElementById(id);
}
getVal() {
return this.id.value;
}
}
let canvas;
let lastTime = 0; // to use framerate.
const simplex = new SimplexNoise();
class Canvas {
constructor(bool) {
// create canvas.
this.canvas = document.createElement("canvas");
// if on screen.
if (bool === true) {
this.canvas.style.position = 'fixed';
this.canvas.style.display = 'block';
this.canvas.style.top = '0';
this.canvas.style.left = '0';
document.getElementsByTagName("body")[0].appendChild(this.canvas);
}
this.ctx = this.canvas.getContext("2d");
this.width = this.canvas.width = window.innerWidth;
this.height = this.canvas.height = window.innerHeight;
// mouse infomation.
this.mouseX = null;
this.mouseY = null;
this.mouseZ = null;
// shape
this.shapeNum = 360;
this.shapes = [];
}
// init, render, resize
init() {
for (let i = 0; i < this.shapeNum; i++) {
const s = new Shape(this.ctx, this.width / 2, this.height / 2, i);
this.shapes.push(s);
}
}
render() {
this.ctx.clearRect(0, 0, this.width, this.height);
for (let i = 0; i < this.shapes.length; i++) {
this.shapes[i].render();
}
this.drawFPS();
}
drawFPS() {
const ctx = this.ctx;
ctx.save();
ctx.fillStyle = 'white';
ctx.font = '16px sans-selif';
ctx.textAlign = 'right';
ctx.textBaseline = 'bottom';
ctx.fillText(Tool.calcFPS() + ' FPS', this.width, this.height);
ctx.restore();
}
resize() {
this.shapes = [];
this.width = this.canvas.width = window.innerWidth;
this.height = this.canvas.height = window.innerHeight;
this.init();
}
}
/*
Shape class.
*/
class Shape {
constructor(ctx, x, y, i) {
this.ctx = ctx;
this.init(x, y, i);
}
init(x, y, i) {
this.x = x;
this.y = y;
this.i = i;
this.r = 100;
this.cr = 100;
this.a = new Angle(this.i * 1);
this.ac = new Angle(180);
}
draw() {
const ctx = this.ctx;
const x = Math.cos(this.a.rad) * this.r + this.x;
const y = Math.sin(this.a.rad) * this.r + this.y;
const noise = simplex.noise3D(x / 100, y / 100, this.ac.rad);
ctx.save();
ctx.translate(this.x, this.y);
ctx.rotate(Math.sin(this.ac.rad));
ctx.scale(Math.cos(this.ac.rad / 5), Math.sin(this.ac.rad / 3));
ctx.translate(-this.x, -this.y);
ctx.globalCompositeOperation = 'lighter'
ctx.lineWidth = 0.4;
ctx.strokeStyle = 'hsl(' + this.i + ', 80%, 60%)';
ctx.beginPath();
ctx.arc(x + Math.cos(this.ac.rad) * 10 * noise, y + Math.sin(this.ac.rad) * 10 * noise, 0.3 * Math.sin(this.ac.rad) * this.cr + this.cr, 0, Math.PI * 2, false);
ctx.stroke();
ctx.restore();
}
updateParams() {
//this.a.incDec(1);
this.ac.incDec(1);
}
render() {
this.draw();
this.updateParams();
}
}
(function () {
"use strict";
window.addEventListener("load", function () {
canvas = new Canvas(true);
canvas.init();
function render() {
window.requestAnimationFrame(function () {
canvas.render();
render();
});
}
render();
// event
window.addEventListener("resize", function() {
canvas.resize();
}, false);
});
})();
<script src="https://cdnjs.cloudflare.com/ajax/libs/simplex-noise/2.4.0/simplex-noise.min.js"></script>
* {
margin: 0;
padding: 0;
}
html,
body {
overflow: hidden;
}
body {
position: relative;
background-color: #000;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment