├── .github └── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── CONTRIBUTING.md ├── Engine.js ├── LICENSE.md ├── README.md └── index.html /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [e.g. iOS] 28 | - Browser [e.g. chrome, safari] 29 | - Version [e.g. 22] 30 | 31 | **Smartphone (please complete the following information):** 32 | - Device: [e.g. iPhone6] 33 | - OS: [e.g. iOS8.1] 34 | - Browser [e.g. stock browser, safari] 35 | - Version [e.g. 22] 36 | 37 | **Additional context** 38 | Add any other context about the problem here. 39 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | If you find an issue, let me know please 2 | -------------------------------------------------------------------------------- /Engine.js: -------------------------------------------------------------------------------- 1 | 2 | window.addEventListener('DOMContentLoaded', (event) => { 3 | const squaretable = {} // this section of code is an optimization for use of the hypotenuse function on Line and LineOP objects 4 | for (let t = 0; t < 10000000; t++) { 5 | squaretable[`${t}`] = Math.sqrt(t) 6 | if (t > 999) { 7 | t += 9 8 | } 9 | } 10 | let video_recorder 11 | let recording = 0 12 | function CanvasCaptureToWEBM(canvas, bitrate) { 13 | // the video_recorder is set to '= new CanvasCaptureToWEBM(canvas, 4500000);' in the setup, 14 | // it uses the same canvas as the rest of the file. 15 | // to start a recording call .record() on video_recorder 16 | /* 17 | for example, 18 | if(keysPressed['-'] && recording == 0){ 19 | recording = 1 20 | video_recorder.record() 21 | } 22 | if(keysPressed['='] && recording == 1){ 23 | recording = 0 24 | video_recorder.stop() 25 | video_recorder.download('File Name As A String.webm') 26 | } 27 | */ 28 | this.record = Record 29 | this.stop = Stop 30 | this.download = saveToDownloads 31 | let blobCaptures = [] 32 | let outputFormat = {} 33 | let recorder = {} 34 | let canvasInput = canvas.captureStream() 35 | if (typeof canvasInput == undefined || !canvasInput) { 36 | return 37 | } 38 | const video = document.createElement('video') 39 | video.style.display = 'none' 40 | 41 | function Record() { 42 | let formats = [ 43 | 'video/vp8', 44 | "video/webm", 45 | 'video/webm,codecs=vp9', 46 | "video/webm\;codecs=vp8", 47 | "video/webm\;codecs=daala", 48 | "video/webm\;codecs=h264", 49 | "video/mpeg" 50 | ]; 51 | 52 | for (let t = 0;t 0) { 78 | blobCaptures.push(event.data) 79 | } 80 | } 81 | function handleStop() { 82 | const superBuffer = new Blob(blobCaptures, { type: outputFormat }) 83 | video.src = window.URL.createObjectURL(superBuffer) 84 | } 85 | function Stop() { 86 | recorder.stop() 87 | video.controls = true 88 | } 89 | function saveToDownloads(input) { // specifying a file name for the output 90 | const name = input || 'video_out.webm' 91 | const blob = new Blob(blobCaptures, { type: outputFormat }) 92 | const url = window.URL.createObjectURL(blob) 93 | const storageElement = document.createElement('a') 94 | storageElement.style.display = 'none' 95 | storageElement.href = url 96 | storageElement.download = name 97 | document.body.appendChild(storageElement) 98 | storageElement.click() 99 | setTimeout(() => { 100 | document.body.removeChild(storageElement) 101 | window.URL.revokeObjectURL(url) 102 | }, 100) 103 | } 104 | } 105 | const gamepadAPI = { 106 | controller: {}, 107 | turbo: true, 108 | connect: function (evt) { 109 | if (navigator.getGamepads()[0] != null) { 110 | gamepadAPI.controller = navigator.getGamepads()[0] 111 | gamepadAPI.turbo = true; 112 | } else if (navigator.getGamepads()[1] != null) { 113 | gamepadAPI.controller = navigator.getGamepads()[0] 114 | gamepadAPI.turbo = true; 115 | } else if (navigator.getGamepads()[2] != null) { 116 | gamepadAPI.controller = navigator.getGamepads()[0] 117 | gamepadAPI.turbo = true; 118 | } else if (navigator.getGamepads()[3] != null) { 119 | gamepadAPI.controller = navigator.getGamepads()[0] 120 | gamepadAPI.turbo = true; 121 | } 122 | for (let i = 0; i < gamepads.length; i++) { 123 | if (gamepads[i] === null) { 124 | continue; 125 | } 126 | if (!gamepads[i].connected) { 127 | continue; 128 | } 129 | } 130 | }, 131 | disconnect: function (evt) { 132 | gamepadAPI.turbo = false; 133 | delete gamepadAPI.controller; 134 | }, 135 | update: function () { 136 | gamepadAPI.controller = navigator.getGamepads()[0] 137 | gamepadAPI.buttonsCache = [];// clear the buttons cache 138 | for (var k = 0; k < gamepadAPI.buttonsStatus.length; k++) {// move the buttons status from the previous frame to the cache 139 | gamepadAPI.buttonsCache[k] = gamepadAPI.buttonsStatus[k]; 140 | } 141 | gamepadAPI.buttonsStatus = [];// clear the buttons status 142 | var c = gamepadAPI.controller || {}; // get the gamepad object 143 | var pressed = []; 144 | if (c.buttons) { 145 | for (var b = 0, t = c.buttons.length; b < t; b++) {// loop through buttons and push the pressed ones to the array 146 | if (c.buttons[b].pressed) { 147 | pressed.push(gamepadAPI.buttons[b]); 148 | } 149 | } 150 | } 151 | var axes = []; 152 | if (c.axes) { 153 | for (var a = 0, x = c.axes.length; a < x; a++) {// loop through axes and push their values to the array 154 | axes.push(c.axes[a].toFixed(2)); 155 | } 156 | } 157 | gamepadAPI.axesStatus = axes;// assign received values 158 | gamepadAPI.buttonsStatus = pressed; 159 | // console.log(pressed); // return buttons for debugging purposes 160 | return pressed; 161 | }, 162 | buttonPressed: function (button, hold) { 163 | var newPress = false; 164 | for (var i = 0, s = gamepadAPI.buttonsStatus.length; i < s; i++) {// loop through pressed buttons 165 | if (gamepadAPI.buttonsStatus[i] == button) {// if we found the button we're looking for... 166 | newPress = true;// set the boolean variable to true 167 | if (!hold) {// if we want to check the single press 168 | for (var j = 0, p = gamepadAPI.buttonsCache.length; j < p; j++) {// loop through the cached states from the previous frame 169 | if (gamepadAPI.buttonsCache[j] == button) { // if the button was already pressed, ignore new press 170 | newPress = false; 171 | } 172 | } 173 | } 174 | } 175 | } 176 | return newPress; 177 | }, 178 | buttons: [ 179 | 'A', 'B', 'X', 'Y', 'LB', 'RB', 'Left-Trigger', 'Right-Trigger', 'Back', 'Start', 'Axis-Left', 'Axis-Right', 'DPad-Up', 'DPad-Down', 'DPad-Left', 'DPad-Right', "Power" 180 | ], 181 | buttonsCache: [], 182 | buttonsStatus: [], 183 | axesStatus: [] 184 | }; 185 | let canvas 186 | let canvas_context 187 | let keysPressed = {} 188 | let FLEX_engine 189 | let TIP_engine = {} 190 | let XS_engine 191 | let YS_engine 192 | class Point { 193 | constructor(x, y) { 194 | this.x = x 195 | this.y = y 196 | this.radius = 0 197 | } 198 | pointDistance(point) { 199 | return (new LineOP(this, point, "transparent", 0)).hypotenuse() 200 | } 201 | } 202 | 203 | class Vector { // vector math and physics if you prefer this over vector components on circles 204 | constructor(object = (new Point(0, 0)), xmom = 0, ymom = 0) { 205 | this.xmom = xmom 206 | this.ymom = ymom 207 | this.object = object 208 | } 209 | isToward(point) { 210 | let link = new LineOP(this.object, point) 211 | let dis1 = link.squareDistance() 212 | let dummy = new Point(this.object.x + this.xmom, this.object.y + this.ymom) 213 | let link2 = new LineOP(dummy, point) 214 | let dis2 = link2.squareDistance() 215 | if (dis2 < dis1) { 216 | return true 217 | } else { 218 | return false 219 | } 220 | } 221 | rotate(angleGoal) { 222 | let link = new Line(this.xmom, this.ymom, 0, 0) 223 | let length = link.hypotenuse() 224 | let x = (length * Math.cos(angleGoal)) 225 | let y = (length * Math.sin(angleGoal)) 226 | this.xmom = x 227 | this.ymom = y 228 | } 229 | magnitude() { 230 | return (new Line(this.xmom, this.ymom, 0, 0)).hypotenuse() 231 | } 232 | normalize(size = 1) { 233 | let magnitude = this.magnitude() 234 | this.xmom /= magnitude 235 | this.ymom /= magnitude 236 | this.xmom *= size 237 | this.ymom *= size 238 | } 239 | multiply(vect) { 240 | let point = new Point(0, 0) 241 | let end = new Point(this.xmom + vect.xmom, this.ymom + vect.ymom) 242 | return point.pointDistance(end) 243 | } 244 | add(vect) { 245 | return new Vector(this.object, this.xmom + vect.xmom, this.ymom + vect.ymom) 246 | } 247 | subtract(vect) { 248 | return new Vector(this.object, this.xmom - vect.xmom, this.ymom - vect.ymom) 249 | } 250 | divide(vect) { 251 | return new Vector(this.object, this.xmom / vect.xmom, this.ymom / vect.ymom) //be careful with this, I don't think this is right 252 | } 253 | draw() { 254 | let dummy = new Point(this.object.x + this.xmom, this.object.y + this.ymom) 255 | let link = new LineOP(this.object, dummy, "#FFFFFF", 1) 256 | link.draw() 257 | } 258 | } 259 | class Line { 260 | constructor(x, y, x2, y2, color, width) { 261 | this.x1 = x 262 | this.y1 = y 263 | this.x2 = x2 264 | this.y2 = y2 265 | this.color = color 266 | this.width = width 267 | } 268 | angle() { 269 | return Math.atan2(this.y1 - this.y2, this.x1 - this.x2) 270 | } 271 | squareDistance() { 272 | let xdif = this.x1 - this.x2 273 | let ydif = this.y1 - this.y2 274 | let squareDistance = (xdif * xdif) + (ydif * ydif) 275 | return squareDistance 276 | } 277 | hypotenuse() { 278 | let xdif = this.x1 - this.x2 279 | let ydif = this.y1 - this.y2 280 | let hypotenuse = (xdif * xdif) + (ydif * ydif) 281 | if (hypotenuse < 10000000 - 1) { 282 | if (hypotenuse > 1000) { 283 | return squaretable[`${Math.round(10 * Math.round((hypotenuse * .1)))}`] 284 | } else { 285 | return squaretable[`${Math.round(hypotenuse)}`] 286 | } 287 | } else { 288 | return Math.sqrt(hypotenuse) 289 | } 290 | } 291 | draw() { 292 | let linewidthstorage = canvas_context.lineWidth 293 | canvas_context.strokeStyle = this.color 294 | canvas_context.lineWidth = this.width 295 | canvas_context.beginPath() 296 | canvas_context.moveTo(this.x1, this.y1) 297 | canvas_context.lineTo(this.x2, this.y2) 298 | canvas_context.stroke() 299 | canvas_context.lineWidth = linewidthstorage 300 | } 301 | } 302 | class LineOP { 303 | constructor(object, target, color, width) { 304 | this.object = object 305 | this.target = target 306 | this.color = color 307 | this.width = width 308 | } 309 | squareDistance() { 310 | let xdif = this.object.x - this.target.x 311 | let ydif = this.object.y - this.target.y 312 | let squareDistance = (xdif * xdif) + (ydif * ydif) 313 | return squareDistance 314 | } 315 | hypotenuse() { 316 | let xdif = this.object.x - this.target.x 317 | let ydif = this.object.y - this.target.y 318 | let hypotenuse = (xdif * xdif) + (ydif * ydif) 319 | if (hypotenuse < 10000000 - 1) { 320 | if (hypotenuse > 1000) { 321 | return squaretable[`${Math.round(10 * Math.round((hypotenuse * .1)))}`] 322 | } else { 323 | return squaretable[`${Math.round(hypotenuse)}`] 324 | } 325 | } else { 326 | return Math.sqrt(hypotenuse) 327 | } 328 | } 329 | angle() { 330 | return Math.atan2(this.object.y - this.target.y, this.object.x - this.target.x) 331 | } 332 | draw() { 333 | let linewidthstorage = canvas_context.lineWidth 334 | canvas_context.strokeStyle = this.color 335 | canvas_context.lineWidth = this.width 336 | canvas_context.beginPath() 337 | canvas_context.moveTo(this.object.x, this.object.y) 338 | canvas_context.lineTo(this.target.x, this.target.y) 339 | canvas_context.stroke() 340 | canvas_context.lineWidth = linewidthstorage 341 | } 342 | } 343 | class Triangle { 344 | constructor(x, y, color, length, fill = 0, strokeWidth = 0, leg1Ratio = 1, leg2Ratio = 1, heightRatio = 1) { 345 | this.x = x 346 | this.y = y 347 | this.color = color 348 | this.length = length 349 | this.x1 = this.x + this.length * leg1Ratio 350 | this.x2 = this.x - this.length * leg2Ratio 351 | this.tip = this.y - this.length * heightRatio 352 | this.accept1 = (this.y - this.tip) / (this.x1 - this.x) 353 | this.accept2 = (this.y - this.tip) / (this.x2 - this.x) 354 | this.fill = fill 355 | this.stroke = strokeWidth 356 | } 357 | draw() { 358 | canvas_context.strokeStyle = this.color 359 | canvas_context.stokeWidth = this.stroke 360 | canvas_context.beginPath() 361 | canvas_context.moveTo(this.x, this.y) 362 | canvas_context.lineTo(this.x1, this.y) 363 | canvas_context.lineTo(this.x, this.tip) 364 | canvas_context.lineTo(this.x2, this.y) 365 | canvas_context.lineTo(this.x, this.y) 366 | if (this.fill == 1) { 367 | canvas_context.fill() 368 | } 369 | canvas_context.stroke() 370 | canvas_context.closePath() 371 | } 372 | isPointInside(point) { 373 | if (point.x <= this.x1) { 374 | if (point.y >= this.tip) { 375 | if (point.y <= this.y) { 376 | if (point.x >= this.x2) { 377 | this.accept1 = (this.y - this.tip) / (this.x1 - this.x) 378 | this.accept2 = (this.y - this.tip) / (this.x2 - this.x) 379 | this.basey = point.y - this.tip 380 | this.basex = point.x - this.x 381 | if (this.basex == 0) { 382 | return true 383 | } 384 | this.slope = this.basey / this.basex 385 | if (this.slope >= this.accept1) { 386 | return true 387 | } else if (this.slope <= this.accept2) { 388 | return true 389 | } 390 | } 391 | } 392 | } 393 | } 394 | return false 395 | } 396 | } 397 | class Rectangle { 398 | constructor(x, y, width, height, color, fill = 1, stroke = 0, strokeWidth = 1) { 399 | this.x = x 400 | this.y = y 401 | this.height = height 402 | this.width = width 403 | this.color = color 404 | this.xmom = 0 405 | this.ymom = 0 406 | this.stroke = stroke 407 | this.strokeWidth = strokeWidth 408 | this.fill = fill 409 | } 410 | draw() { 411 | canvas_context.fillStyle = this.color 412 | canvas_context.fillRect(this.x, this.y, this.width, this.height) 413 | } 414 | move() { 415 | this.x += this.xmom 416 | this.y += this.ymom 417 | } 418 | isPointInside(point) { 419 | if (point.x >= this.x) { 420 | if (point.y >= this.y) { 421 | if (point.x <= this.x + this.width) { 422 | if (point.y <= this.y + this.height) { 423 | return true 424 | } 425 | } 426 | } 427 | } 428 | return false 429 | } 430 | doesPerimeterTouch(point) { 431 | if (point.x + point.radius >= this.x) { 432 | if (point.y + point.radius >= this.y) { 433 | if (point.x - point.radius <= this.x + this.width) { 434 | if (point.y - point.radius <= this.y + this.height) { 435 | return true 436 | } 437 | } 438 | } 439 | } 440 | return false 441 | } 442 | } 443 | class Circle { 444 | constructor(x, y, radius, color, xmom = 0, ymom = 0, friction = 1, reflect = 0, strokeWidth = 0, strokeColor = "transparent") { 445 | this.x = x 446 | this.y = y 447 | this.radius = radius 448 | this.color = color 449 | this.xmom = xmom 450 | this.ymom = ymom 451 | this.friction = friction 452 | this.reflect = reflect 453 | this.strokeWidth = strokeWidth 454 | this.strokeColor = strokeColor 455 | } 456 | draw() { 457 | canvas_context.lineWidth = this.strokeWidth 458 | canvas_context.strokeStyle = this.color 459 | canvas_context.beginPath(); 460 | if (this.radius > 0) { 461 | canvas_context.arc(this.x, this.y, this.radius, 0, (Math.PI * 2), true) 462 | canvas_context.fillStyle = this.color 463 | canvas_context.fill() 464 | canvas_context.stroke(); 465 | } else { 466 | console.log("The circle is below a radius of 0, and has not been drawn. The circle is:", this) 467 | } 468 | } 469 | move() { 470 | if (this.reflect == 1) { 471 | if (this.x + this.radius > canvas.width) { 472 | if (this.xmom > 0) { 473 | this.xmom *= -1 474 | } 475 | } 476 | if (this.y + this.radius > canvas.height) { 477 | if (this.ymom > 0) { 478 | this.ymom *= -1 479 | } 480 | } 481 | if (this.x - this.radius < 0) { 482 | if (this.xmom < 0) { 483 | this.xmom *= -1 484 | } 485 | } 486 | if (this.y - this.radius < 0) { 487 | if (this.ymom < 0) { 488 | this.ymom *= -1 489 | } 490 | } 491 | } 492 | this.x += this.xmom 493 | this.y += this.ymom 494 | } 495 | unmove() { 496 | if (this.reflect == 1) { 497 | if (this.x + this.radius > canvas.width) { 498 | if (this.xmom > 0) { 499 | this.xmom *= -1 500 | } 501 | } 502 | if (this.y + this.radius > canvas.height) { 503 | if (this.ymom > 0) { 504 | this.ymom *= -1 505 | } 506 | } 507 | if (this.x - this.radius < 0) { 508 | if (this.xmom < 0) { 509 | this.xmom *= -1 510 | } 511 | } 512 | if (this.y - this.radius < 0) { 513 | if (this.ymom < 0) { 514 | this.ymom *= -1 515 | } 516 | } 517 | } 518 | this.x -= this.xmom 519 | this.y -= this.ymom 520 | } 521 | frictiveMove() { 522 | if (this.reflect == 1) { 523 | if (this.x + this.radius > canvas.width) { 524 | if (this.xmom > 0) { 525 | this.xmom *= -1 526 | } 527 | } 528 | if (this.y + this.radius > canvas.height) { 529 | if (this.ymom > 0) { 530 | this.ymom *= -1 531 | } 532 | } 533 | if (this.x - this.radius < 0) { 534 | if (this.xmom < 0) { 535 | this.xmom *= -1 536 | } 537 | } 538 | if (this.y - this.radius < 0) { 539 | if (this.ymom < 0) { 540 | this.ymom *= -1 541 | } 542 | } 543 | } 544 | this.x += this.xmom 545 | this.y += this.ymom 546 | this.xmom *= this.friction 547 | this.ymom *= this.friction 548 | } 549 | frictiveunMove() { 550 | if (this.reflect == 1) { 551 | if (this.x + this.radius > canvas.width) { 552 | if (this.xmom > 0) { 553 | this.xmom *= -1 554 | } 555 | } 556 | if (this.y + this.radius > canvas.height) { 557 | if (this.ymom > 0) { 558 | this.ymom *= -1 559 | } 560 | } 561 | if (this.x - this.radius < 0) { 562 | if (this.xmom < 0) { 563 | this.xmom *= -1 564 | } 565 | } 566 | if (this.y - this.radius < 0) { 567 | if (this.ymom < 0) { 568 | this.ymom *= -1 569 | } 570 | } 571 | } 572 | this.xmom /= this.friction 573 | this.ymom /= this.friction 574 | this.x -= this.xmom 575 | this.y -= this.ymom 576 | } 577 | isPointInside(point) { 578 | this.areaY = point.y - this.y 579 | this.areaX = point.x - this.x 580 | if (((this.areaX * this.areaX) + (this.areaY * this.areaY)) <= (this.radius * this.radius)) { 581 | return true 582 | } 583 | return false 584 | } 585 | doesPerimeterTouch(point) { 586 | this.areaY = point.y - this.y 587 | this.areaX = point.x - this.x 588 | if (((this.areaX * this.areaX) + (this.areaY * this.areaY)) <= ((this.radius + point.radius) * (this.radius + point.radius))) { 589 | return true 590 | } 591 | return false 592 | } 593 | } class Polygon { 594 | constructor(x, y, size, color, sides = 3, xmom = 0, ymom = 0, angle = 0, reflect = 0) { 595 | if (sides < 2) { 596 | sides = 2 597 | } 598 | this.reflect = reflect 599 | this.xmom = xmom 600 | this.ymom = ymom 601 | this.body = new Circle(x, y, size - (size * .293), "transparent") 602 | this.nodes = [] 603 | this.angle = angle 604 | this.size = size 605 | this.color = color 606 | this.angleIncrement = (Math.PI * 2) / sides 607 | this.sides = sides 608 | for (let t = 0; t < sides; t++) { 609 | let node = new Circle(this.body.x + (this.size * (Math.cos(this.angle))), this.body.y + (this.size * (Math.sin(this.angle))), 0, "transparent") 610 | this.nodes.push(node) 611 | this.angle += this.angleIncrement 612 | } 613 | } 614 | isPointInside(point) { // rough approximation 615 | this.body.radius = this.size - (this.size * .293) 616 | if (this.sides <= 2) { 617 | return false 618 | } 619 | this.areaY = point.y - this.body.y 620 | this.areaX = point.x - this.body.x 621 | if (((this.areaX * this.areaX) + (this.areaY * this.areaY)) <= (this.body.radius * this.body.radius)) { 622 | return true 623 | } 624 | return false 625 | } 626 | move() { 627 | if (this.reflect == 1) { 628 | if (this.body.x > canvas.width) { 629 | if (this.xmom > 0) { 630 | this.xmom *= -1 631 | } 632 | } 633 | if (this.body.y > canvas.height) { 634 | if (this.ymom > 0) { 635 | this.ymom *= -1 636 | } 637 | } 638 | if (this.body.x < 0) { 639 | if (this.xmom < 0) { 640 | this.xmom *= -1 641 | } 642 | } 643 | if (this.body.y < 0) { 644 | if (this.ymom < 0) { 645 | this.ymom *= -1 646 | } 647 | } 648 | } 649 | this.body.x += this.xmom 650 | this.body.y += this.ymom 651 | } 652 | draw() { 653 | this.nodes = [] 654 | this.angleIncrement = (Math.PI * 2) / this.sides 655 | this.body.radius = this.size - (this.size * .293) 656 | for (let t = 0; t < this.sides; t++) { 657 | let node = new Circle(this.body.x + (this.size * (Math.cos(this.angle))), this.body.y + (this.size * (Math.sin(this.angle))), 0, "transparent") 658 | this.nodes.push(node) 659 | this.angle += this.angleIncrement 660 | } 661 | canvas_context.strokeStyle = this.color 662 | canvas_context.fillStyle = this.color 663 | canvas_context.lineWidth = 0 664 | canvas_context.beginPath() 665 | canvas_context.moveTo(this.nodes[0].x, this.nodes[0].y) 666 | for (let t = 1; t < this.nodes.length; t++) { 667 | canvas_context.lineTo(this.nodes[t].x, this.nodes[t].y) 668 | } 669 | canvas_context.lineTo(this.nodes[0].x, this.nodes[0].y) 670 | canvas_context.fill() 671 | canvas_context.stroke() 672 | canvas_context.closePath() 673 | } 674 | } 675 | class Shape { 676 | constructor(shapes) { 677 | this.shapes = shapes 678 | } 679 | draw() { 680 | for (let t = 0; t < this.shapes.length; t++) { 681 | this.shapes[t].draw() 682 | } 683 | } 684 | isPointInside(point) { 685 | for (let t = 0; t < this.shapes.length; t++) { 686 | if (this.shapes[t].isPointInside(point)) { 687 | return true 688 | } 689 | } 690 | return false 691 | } 692 | doesPerimeterTouch(point) { 693 | for (let t = 0; t < this.shapes.length; t++) { 694 | if (this.shapes[t].doesPerimeterTouch(point)) { 695 | return true 696 | } 697 | } 698 | return false 699 | } 700 | innerShape(point) { 701 | for (let t = 0; t < this.shapes.length; t++) { 702 | if (this.shapes[t].doesPerimeterTouch(point)) { 703 | return this.shapes[t] 704 | } 705 | } 706 | return false 707 | } 708 | isInsideOf(box) { 709 | for (let t = 0; t < this.shapes.length; t++) { 710 | if (box.isPointInside(this.shapes[t])) { 711 | return true 712 | } 713 | } 714 | return false 715 | } 716 | adjustByFromDisplacement(x, y) { 717 | for (let t = 0; t < this.shapes.length; t++) { 718 | if (typeof this.shapes[t].fromRatio == "number") { 719 | this.shapes[t].x += x * this.shapes[t].fromRatio 720 | this.shapes[t].y += y * this.shapes[t].fromRatio 721 | } 722 | } 723 | } 724 | adjustByToDisplacement(x, y) { 725 | for (let t = 0; t < this.shapes.length; t++) { 726 | if (typeof this.shapes[t].toRatio == "number") { 727 | this.shapes[t].x += x * this.shapes[t].toRatio 728 | this.shapes[t].y += y * this.shapes[t].toRatio 729 | } 730 | } 731 | } 732 | mixIn(arr) { 733 | for (let t = 0; t < arr.length; t++) { 734 | for (let k = 0; k < arr[t].shapes.length; k++) { 735 | this.shapes.push(arr[t].shapes[k]) 736 | } 737 | } 738 | } 739 | push(object) { 740 | this.shapes.push(object) 741 | } 742 | } 743 | 744 | class Spring { 745 | constructor(x, y, radius, color, body = 0, length = 1, gravity = 0, width = 1) { 746 | if (body == 0) { 747 | this.body = new Circle(x, y, radius, color) 748 | this.anchor = new Circle(x, y, radius, color) 749 | this.beam = new Line(this.body.x, this.body.y, this.anchor.x, this.anchor.y, "yellow", width) 750 | this.length = length 751 | } else { 752 | this.body = body 753 | this.anchor = new Circle(x, y, radius, color) 754 | this.beam = new Line(this.body.x, this.body.y, this.anchor.x, this.anchor.y, "yellow", width) 755 | this.length = length 756 | } 757 | this.gravity = gravity 758 | this.width = width 759 | } 760 | balance() { 761 | this.beam = new Line(this.body.x, this.body.y, this.anchor.x, this.anchor.y, "yellow", this.width) 762 | if (this.beam.hypotenuse() < this.length) { 763 | this.body.xmom += (this.body.x - this.anchor.x) / this.length 764 | this.body.ymom += (this.body.y - this.anchor.y) / this.length 765 | this.anchor.xmom -= (this.body.x - this.anchor.x) / this.length 766 | this.anchor.ymom -= (this.body.y - this.anchor.y) / this.length 767 | } else { 768 | this.body.xmom -= (this.body.x - this.anchor.x) / this.length 769 | this.body.ymom -= (this.body.y - this.anchor.y) / this.length 770 | this.anchor.xmom += (this.body.x - this.anchor.x) / this.length 771 | this.anchor.ymom += (this.body.y - this.anchor.y) / this.length 772 | } 773 | let xmomentumaverage = (this.body.xmom + this.anchor.xmom) / 2 774 | let ymomentumaverage = (this.body.ymom + this.anchor.ymom) / 2 775 | this.body.xmom = (this.body.xmom + xmomentumaverage) / 2 776 | this.body.ymom = (this.body.ymom + ymomentumaverage) / 2 777 | this.anchor.xmom = (this.anchor.xmom + xmomentumaverage) / 2 778 | this.anchor.ymom = (this.anchor.ymom + ymomentumaverage) / 2 779 | } 780 | draw() { 781 | this.beam = new Line(this.body.x, this.body.y, this.anchor.x, this.anchor.y, "yellow", this.width) 782 | this.beam.draw() 783 | this.body.draw() 784 | this.anchor.draw() 785 | } 786 | move() { 787 | this.anchor.ymom += this.gravity 788 | this.anchor.move() 789 | } 790 | 791 | } 792 | class SpringOP { 793 | constructor(body, anchor, length, width = 3, color = body.color) { 794 | this.body = body 795 | this.anchor = anchor 796 | this.beam = new LineOP(body, anchor, color, width) 797 | this.length = length 798 | } 799 | balance() { 800 | if (this.beam.hypotenuse() < this.length) { 801 | this.body.xmom += ((this.body.x - this.anchor.x) / this.length) 802 | this.body.ymom += ((this.body.y - this.anchor.y) / this.length) 803 | this.anchor.xmom -= ((this.body.x - this.anchor.x) / this.length) 804 | this.anchor.ymom -= ((this.body.y - this.anchor.y) / this.length) 805 | } else if (this.beam.hypotenuse() > this.length) { 806 | this.body.xmom -= (this.body.x - this.anchor.x) / (this.length) 807 | this.body.ymom -= (this.body.y - this.anchor.y) / (this.length) 808 | this.anchor.xmom += (this.body.x - this.anchor.x) / (this.length) 809 | this.anchor.ymom += (this.body.y - this.anchor.y) / (this.length) 810 | } 811 | 812 | let xmomentumaverage = (this.body.xmom + this.anchor.xmom) / 2 813 | let ymomentumaverage = (this.body.ymom + this.anchor.ymom) / 2 814 | this.body.xmom = (this.body.xmom + xmomentumaverage) / 2 815 | this.body.ymom = (this.body.ymom + ymomentumaverage) / 2 816 | this.anchor.xmom = (this.anchor.xmom + xmomentumaverage) / 2 817 | this.anchor.ymom = (this.anchor.ymom + ymomentumaverage) / 2 818 | } 819 | draw() { 820 | this.beam.draw() 821 | } 822 | move() { 823 | //movement of SpringOP objects should be handled separate from their linkage, to allow for many connections, balance here with this object, move nodes independently 824 | } 825 | } 826 | 827 | class Color { 828 | constructor(baseColor, red = -1, green = -1, blue = -1, alpha = 1) { 829 | this.hue = baseColor 830 | if (red != -1 && green != -1 && blue != -1) { 831 | this.r = red 832 | this.g = green 833 | this.b = blue 834 | if (alpha != 1) { 835 | if (alpha < 1) { 836 | this.alpha = alpha 837 | } else { 838 | this.alpha = alpha / 255 839 | if (this.alpha > 1) { 840 | this.alpha = 1 841 | } 842 | } 843 | } 844 | if (this.r > 255) { 845 | this.r = 255 846 | } 847 | if (this.g > 255) { 848 | this.g = 255 849 | } 850 | if (this.b > 255) { 851 | this.b = 255 852 | } 853 | if (this.r < 0) { 854 | this.r = 0 855 | } 856 | if (this.g < 0) { 857 | this.g = 0 858 | } 859 | if (this.b < 0) { 860 | this.b = 0 861 | } 862 | } else { 863 | this.r = 0 864 | this.g = 0 865 | this.b = 0 866 | } 867 | } 868 | normalize() { 869 | if (this.r > 255) { 870 | this.r = 255 871 | } 872 | if (this.g > 255) { 873 | this.g = 255 874 | } 875 | if (this.b > 255) { 876 | this.b = 255 877 | } 878 | if (this.r < 0) { 879 | this.r = 0 880 | } 881 | if (this.g < 0) { 882 | this.g = 0 883 | } 884 | if (this.b < 0) { 885 | this.b = 0 886 | } 887 | } 888 | randomLight() { 889 | var letters = '0123456789ABCDEF'; 890 | var hash = '#'; 891 | for (var i = 0; i < 6; i++) { 892 | hash += letters[(Math.floor(Math.random() * 12) + 4)]; 893 | } 894 | var color = new Color(hash, 55 + Math.random() * 200, 55 + Math.random() * 200, 55 + Math.random() * 200) 895 | return color; 896 | } 897 | randomDark() { 898 | var letters = '0123456789ABCDEF'; 899 | var hash = '#'; 900 | for (var i = 0; i < 6; i++) { 901 | hash += letters[(Math.floor(Math.random() * 12))]; 902 | } 903 | var color = new Color(hash, Math.random() * 200, Math.random() * 200, Math.random() * 200) 904 | return color; 905 | } 906 | random() { 907 | var letters = '0123456789ABCDEF'; 908 | var hash = '#'; 909 | for (var i = 0; i < 6; i++) { 910 | hash += letters[(Math.floor(Math.random() * 16))]; 911 | } 912 | var color = new Color(hash, Math.random() * 255, Math.random() * 255, Math.random() * 255) 913 | return color; 914 | } 915 | } 916 | class Softbody { //buggy, spins in place 917 | constructor(x, y, radius, color, members = 10, memberLength = 5, force = 10, gravity = 0) { 918 | this.springs = [] 919 | this.pin = new Circle(x, y, radius, color) 920 | this.spring = new Spring(x, y, radius, color, this.pin, memberLength, gravity) 921 | this.springs.push(this.spring) 922 | for (let k = 0; k < members; k++) { 923 | this.spring = new Spring(x, y, radius, color, this.spring.anchor, memberLength, gravity) 924 | if (k < members - 1) { 925 | this.springs.push(this.spring) 926 | } else { 927 | this.spring.anchor = this.pin 928 | this.springs.push(this.spring) 929 | } 930 | } 931 | this.forceConstant = force 932 | this.centroid = new Point(0, 0) 933 | } 934 | circularize() { 935 | this.xpoint = 0 936 | this.ypoint = 0 937 | for (let s = 0; s < this.springs.length; s++) { 938 | this.xpoint += (this.springs[s].anchor.x / this.springs.length) 939 | this.ypoint += (this.springs[s].anchor.y / this.springs.length) 940 | } 941 | this.centroid.x = this.xpoint 942 | this.centroid.y = this.ypoint 943 | this.angle = 0 944 | this.angleIncrement = (Math.PI * 2) / this.springs.length 945 | for (let t = 0; t < this.springs.length; t++) { 946 | this.springs[t].body.x = this.centroid.x + (Math.cos(this.angle) * this.forceConstant) 947 | this.springs[t].body.y = this.centroid.y + (Math.sin(this.angle) * this.forceConstant) 948 | this.angle += this.angleIncrement 949 | } 950 | } 951 | balance() { 952 | for (let s = this.springs.length - 1; s >= 0; s--) { 953 | this.springs[s].balance() 954 | } 955 | this.xpoint = 0 956 | this.ypoint = 0 957 | for (let s = 0; s < this.springs.length; s++) { 958 | this.xpoint += (this.springs[s].anchor.x / this.springs.length) 959 | this.ypoint += (this.springs[s].anchor.y / this.springs.length) 960 | } 961 | this.centroid.x = this.xpoint 962 | this.centroid.y = this.ypoint 963 | for (let s = 0; s < this.springs.length; s++) { 964 | this.link = new Line(this.centroid.x, this.centroid.y, this.springs[s].anchor.x, this.springs[s].anchor.y, 0, "transparent") 965 | if (this.link.hypotenuse() != 0) { 966 | this.springs[s].anchor.xmom += (((this.springs[s].anchor.x - this.centroid.x) / (this.link.hypotenuse()))) * this.forceConstant 967 | this.springs[s].anchor.ymom += (((this.springs[s].anchor.y - this.centroid.y) / (this.link.hypotenuse()))) * this.forceConstant 968 | } 969 | } 970 | for (let s = 0; s < this.springs.length; s++) { 971 | this.springs[s].move() 972 | } 973 | for (let s = 0; s < this.springs.length; s++) { 974 | this.springs[s].draw() 975 | } 976 | } 977 | } 978 | class Observer { 979 | constructor(x, y, radius, color, range = 100, rays = 10, angle = (Math.PI * .125)) { 980 | this.body = new Circle(x, y, radius, color) 981 | this.color = color 982 | this.ray = [] 983 | this.rayrange = range 984 | this.globalangle = Math.PI 985 | this.gapangle = angle 986 | this.currentangle = 0 987 | this.obstacles = [] 988 | this.raymake = rays 989 | } 990 | beam() { 991 | this.currentangle = this.gapangle / 2 992 | for (let k = 0; k < this.raymake; k++) { 993 | this.currentangle += (this.gapangle / Math.ceil(this.raymake / 2)) 994 | let ray = new Circle(this.body.x, this.body.y, 1, "white", (((Math.cos(this.globalangle + this.currentangle)))), (((Math.sin(this.globalangle + this.currentangle))))) 995 | ray.collided = 0 996 | ray.lifespan = this.rayrange - 1 997 | this.ray.push(ray) 998 | } 999 | for (let f = 0; f < this.rayrange; f++) { 1000 | for (let t = 0; t < this.ray.length; t++) { 1001 | if (this.ray[t].collided < 1) { 1002 | this.ray[t].move() 1003 | for (let q = 0; q < this.obstacles.length; q++) { 1004 | if (this.obstacles[q].isPointInside(this.ray[t])) { 1005 | this.ray[t].collided = 1 1006 | } 1007 | } 1008 | } 1009 | } 1010 | } 1011 | } 1012 | draw() { 1013 | this.beam() 1014 | this.body.draw() 1015 | canvas_context.lineWidth = 1 1016 | canvas_context.fillStyle = this.color 1017 | canvas_context.strokeStyle = this.color 1018 | canvas_context.beginPath() 1019 | canvas_context.moveTo(this.body.x, this.body.y) 1020 | for (let y = 0; y < this.ray.length; y++) { 1021 | canvas_context.lineTo(this.ray[y].x, this.ray[y].y) 1022 | canvas_context.lineTo(this.body.x, this.body.y) 1023 | } 1024 | canvas_context.stroke() 1025 | canvas_context.fill() 1026 | this.ray = [] 1027 | } 1028 | } 1029 | function setUp(canvas_pass, style = "#000000") { 1030 | canvas = canvas_pass 1031 | video_recorder = new CanvasCaptureToWEBM(canvas, 4500000); 1032 | canvas_context = canvas.getContext('2d'); 1033 | canvas.style.background = style 1034 | window.setInterval(function () { 1035 | main() 1036 | }, 17) 1037 | document.addEventListener('keydown', (event) => { 1038 | keysPressed[event.key] = true; 1039 | }); 1040 | document.addEventListener('keyup', (event) => { 1041 | delete keysPressed[event.key]; 1042 | }); 1043 | window.addEventListener('pointerdown', e => { 1044 | FLEX_engine = canvas.getBoundingClientRect(); 1045 | XS_engine = e.clientX - FLEX_engine.left; 1046 | YS_engine = e.clientY - FLEX_engine.top; 1047 | TIP_engine.x = XS_engine 1048 | TIP_engine.y = YS_engine 1049 | TIP_engine.body = TIP_engine 1050 | // example usage: if(object.isPointInside(TIP_engine)){ take action } 1051 | window.addEventListener('pointermove', continued_stimuli); 1052 | }); 1053 | window.addEventListener('pointerup', e => { 1054 | window.removeEventListener("pointermove", continued_stimuli); 1055 | }) 1056 | function continued_stimuli(e) { 1057 | FLEX_engine = canvas.getBoundingClientRect(); 1058 | XS_engine = e.clientX - FLEX_engine.left; 1059 | YS_engine = e.clientY - FLEX_engine.top; 1060 | TIP_engine.x = XS_engine 1061 | TIP_engine.y = YS_engine 1062 | TIP_engine.body = TIP_engine 1063 | } 1064 | } 1065 | function gamepad_control(object, speed = 1) { // basic control for objects using the controler 1066 | // console.log(gamepadAPI.axesStatus[1]*gamepadAPI.axesStatus[0]) //debugging 1067 | if (typeof object.body != 'undefined') { 1068 | if (typeof (gamepadAPI.axesStatus[1]) != 'undefined') { 1069 | if (typeof (gamepadAPI.axesStatus[0]) != 'undefined') { 1070 | object.body.x += (gamepadAPI.axesStatus[0] * speed) 1071 | object.body.y += (gamepadAPI.axesStatus[1] * speed) 1072 | } 1073 | } 1074 | } else if (typeof object != 'undefined') { 1075 | if (typeof (gamepadAPI.axesStatus[1]) != 'undefined') { 1076 | if (typeof (gamepadAPI.axesStatus[0]) != 'undefined') { 1077 | object.x += (gamepadAPI.axesStatus[0] * speed) 1078 | object.y += (gamepadAPI.axesStatus[1] * speed) 1079 | } 1080 | } 1081 | } 1082 | } 1083 | function control(object, speed = 1) { // basic control for objects 1084 | if (typeof object.body != 'undefined') { 1085 | if (keysPressed['w']) { 1086 | object.body.y -= speed 1087 | } 1088 | if (keysPressed['d']) { 1089 | object.body.x += speed 1090 | } 1091 | if (keysPressed['s']) { 1092 | object.body.y += speed 1093 | } 1094 | if (keysPressed['a']) { 1095 | object.body.x -= speed 1096 | } 1097 | } else if (typeof object != 'undefined') { 1098 | if (keysPressed['w']) { 1099 | object.y -= speed 1100 | } 1101 | if (keysPressed['d']) { 1102 | object.x += speed 1103 | } 1104 | if (keysPressed['s']) { 1105 | object.y += speed 1106 | } 1107 | if (keysPressed['a']) { 1108 | object.x -= speed 1109 | } 1110 | } 1111 | } 1112 | function getRandomLightColor() { // random color that will be visible on black background 1113 | var letters = '0123456789ABCDEF'; 1114 | var color = '#'; 1115 | for (var i = 0; i < 6; i++) { 1116 | color += letters[(Math.floor(Math.random() * 12) + 4)]; 1117 | } 1118 | return color; 1119 | } 1120 | function getRandomColor() { // random color 1121 | var letters = '0123456789ABCDEF'; 1122 | var color = '#'; 1123 | for (var i = 0; i < 6; i++) { 1124 | color += letters[(Math.floor(Math.random() * 16) + 0)]; 1125 | } 1126 | return color; 1127 | } 1128 | function getRandomDarkColor() {// color that will be visible on a black background 1129 | var letters = '0123456789ABCDEF'; 1130 | var color = '#'; 1131 | for (var i = 0; i < 6; i++) { 1132 | color += letters[(Math.floor(Math.random() * 12))]; 1133 | } 1134 | return color; 1135 | } 1136 | function castBetween(from, to, granularity = 10, radius = 1) { //creates a sort of beam hitbox between two points, with a granularity (number of members over distance), with a radius defined as well 1137 | let limit = granularity 1138 | let shape_array = [] 1139 | for (let t = 0; t < limit; t++) { 1140 | let circ = new Circle((from.x * (t / limit)) + (to.x * ((limit - t) / limit)), (from.y * (t / limit)) + (to.y * ((limit - t) / limit)), radius, "red") 1141 | circ.toRatio = t / limit 1142 | circ.fromRatio = (limit - t) / limit 1143 | shape_array.push(circ) 1144 | } 1145 | return (new Shape(shape_array)) 1146 | } 1147 | 1148 | function castBetweenPoints(from, to, granularity = 10, radius = 1) { //creates a sort of beam hitbox between two points, with a granularity (number of members over distance), with a radius defined as well 1149 | let limit = granularity 1150 | let shape_array = [] 1151 | for (let t = 0; t < limit; t++) { 1152 | let circ = new Circle((from.x * (t / limit)) + (to.x * ((limit - t) / limit)), (from.y * (t / limit)) + (to.y * ((limit - t) / limit)), radius, "red") 1153 | circ.toRatio = t / limit 1154 | circ.fromRatio = (limit - t) / limit 1155 | shape_array.push(circ) 1156 | } 1157 | return shape_array 1158 | } 1159 | 1160 | class Disang { 1161 | constructor(dis, ang) { 1162 | this.dis = dis 1163 | this.angle = ang 1164 | } 1165 | } 1166 | 1167 | class BezierHitbox { 1168 | constructor(x, y, cx, cy, ex, ey, color = "red") { // this function takes a starting x,y, a control point x,y, and a end point x,y 1169 | this.color = color 1170 | this.x = x 1171 | this.y = y 1172 | this.cx = cx 1173 | this.cy = cy 1174 | this.ex = ex 1175 | this.ey = ey 1176 | this.metapoint = new Circle((x + cx + ex) / 3, (y + cy + ey) / 3, 3, "#FFFFFF") 1177 | this.granularity = 100 1178 | this.body = [...castBetweenPoints((new Point(this.x, this.y)), (new Point(this.ex, this.ey)), this.granularity, 0)] 1179 | 1180 | let angle = (new Line(this.x, this.y, this.ex, this.ey)).angle() 1181 | 1182 | this.angles = [] 1183 | for (let t = 0; t < this.granularity; t++) { 1184 | this.angles.push(angle) 1185 | } 1186 | for (let t = 0; t <= 1; t += 1 / this.granularity) { 1187 | this.body.push(this.getQuadraticXY(t)) 1188 | this.angles.push(this.getQuadraticAngle(t)) 1189 | } 1190 | this.hitbox = [] 1191 | for (let t = 0; t < this.body.length; t++) { 1192 | let link = new LineOP(this.body[t], this.metapoint) 1193 | let disang = new Disang(link.hypotenuse(), link.angle() + (Math.PI * 2)) 1194 | this.hitbox.push(disang) 1195 | } 1196 | this.constructed = 1 1197 | } 1198 | isPointInside(point) { 1199 | let link = new LineOP(point, this.metapoint) 1200 | let angle = (link.angle() + (Math.PI * 2)) 1201 | let dis = link.hypotenuse() 1202 | for (let t = 1; t < this.hitbox.length; t++) { 1203 | if (Math.abs(this.hitbox[t].angle - this.hitbox[t - 1].angle) > 1) { 1204 | continue 1205 | } 1206 | if (angle.between(this.hitbox[t].angle, this.hitbox[t - 1].angle)) { 1207 | if (dis < (this.hitbox[t].dis + this.hitbox[t - 1].dis) * .5) { 1208 | return true 1209 | } 1210 | } 1211 | } 1212 | return false 1213 | } 1214 | doesPerimeterTouch(point) { 1215 | let link = new LineOP(point, this.metapoint) 1216 | let angle = (link.angle() + (Math.PI * 2)) 1217 | let dis = link.hypotenuse() 1218 | for (let t = 1; t < this.hitbox.length; t++) { 1219 | if (Math.abs(this.hitbox[t].angle - this.hitbox[t - 1].angle) > 1) { 1220 | continue 1221 | } 1222 | if (angle.between(this.hitbox[t].angle, this.hitbox[t - 1].angle)) { 1223 | if (dis < ((this.hitbox[t].dis + this.hitbox[t - 1].dis) * .5) + point.radius) { 1224 | return this.angles[t] 1225 | } 1226 | } 1227 | } 1228 | return false 1229 | } 1230 | draw() { 1231 | this.metapoint.draw() 1232 | let tline = new Line(this.x, this.y, this.ex, this.ey, this.color, 3) 1233 | tline.draw() 1234 | canvas_context.beginPath() 1235 | this.median = new Point((this.x + this.ex) * .5, (this.y + this.ey) * .5) 1236 | let angle = (new LineOP(this.median, this.metapoint)).angle() 1237 | let dis = (new LineOP(this.median, this.metapoint)).hypotenuse() 1238 | canvas_context.bezierCurveTo(this.x, this.y, this.cx - (Math.cos(angle) * dis * .38), this.cy - (Math.sin(angle) * dis * .38), this.ex, this.ey) 1239 | 1240 | canvas_context.fillStyle = this.color 1241 | canvas_context.strokeStyle = this.color 1242 | canvas_context.lineWidth = 3 1243 | canvas_context.stroke() 1244 | } 1245 | getQuadraticXY(t) { 1246 | return new Point((((1 - t) * (1 - t)) * this.x) + (2 * (1 - t) * t * this.cx) + (t * t * this.ex), (((1 - t) * (1 - t)) * this.y) + (2 * (1 - t) * t * this.cy) + (t * t * this.ey)) 1247 | } 1248 | getQuadraticAngle(t) { 1249 | var dx = 2 * (1 - t) * (this.cx - this.x) + 2 * t * (this.ex - this.cx); 1250 | var dy = 2 * (1 - t) * (this.cy - this.y) + 2 * t * (this.ey - this.cy); 1251 | return -Math.atan2(dx, dy) + 0.5 * Math.PI; 1252 | } 1253 | } 1254 | Number.prototype.between = function (a, b, inclusive) { 1255 | var min = Math.min(a, b), 1256 | max = Math.max(a, b); 1257 | return inclusive ? this >= min && this <= max : this > min && this < max; 1258 | } 1259 | 1260 | let setup_canvas = document.getElementById('canvas') //getting canvas from document 1261 | 1262 | setUp(setup_canvas) // setting up canvas refrences, starting timer. 1263 | 1264 | // object instantiation and creation happens here 1265 | 1266 | function main() { 1267 | canvas_context.clearRect(0, 0, canvas.width, canvas.height) // refreshes the image 1268 | gamepadAPI.update() //checks for button presses/stick movement on the connected controller) 1269 | // game code goes here 1270 | } 1271 | 1272 | }) 1273 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright 2021 Cole James Ditzler 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Ditzbitz_Engine 2 | 3 | This engine is meant to help take some of the tedious setup out of making browser-based games and toys. 4 | 5 | In order to get started: simply instantiate some game objects in the commented area in Engine.js, and start adding logic to the main function. 6 | 7 | The main function is scheduled to execute every 17 milliseconds once the setUp function has been executed. Do not execute setUp twice, it will cause errors. 8 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 14 |
15 | 16 | 17 | 18 | 19 | --------------------------------------------------------------------------------