// ============================================================== // =============================== // Dragon code // =============================== function createDragon(dragonLength) { // dragonLength has to be >= 0 dragonLength = Math.abs(dragonLength); var theDragon = []; for (var i = 0; i < dragonLength; i++) { // Create the head if (i == 0) { theDragon.push(createDragonSegment("HEAD")); } // Create the tail else if (i == dragonLength - 1) { theDragon.push(createDragonSegment("TAIL")); } // Create the body segments else { // Every 1 out of 3 segments will be red if(i % 3 == 0) { theDragon.push(createDragonSegment("BODY")); } // The other 2 out of 3 segments will be yellow else { theDragon.push(createDragonSegment("BODY2")); } } } return theDragon; } function createDragonSegment(segmentType) { var segmentImage = new Image(); if (segmentType == "HEAD") { segmentImage.src = "images/dragon/head.png"; } else if (segmentType == "TAIL") { segmentImage.src = "images/dragon/tail.png"; } else { if(segmentType == "BODY") segmentImage.src = "images/dragon/body.png"; else segmentImage.src = "images/dragon/body_gold.png"; } segmentImage.onload = draw; return { 'segmentType': segmentType, 'position': createVectorOfLength(2), 'followTarget': '', 'image': segmentImage }; } function updateDragonSegment(idx) { var dragonSegment = dragon[idx]; var angle; if (dragonSegment.segmentType == "HEAD") { // each update loop, only move 3% of the way towards the mouse position dragonSegment.position = getVectorPercentDistance(dragonSegment.position, mousePos, 0.03); angle = getVectorAngle(mousePos, dragonSegment.position); } else { var prevDragonSegment = dragon[idx - 1]; var distance = getVectorDistance(prevDragonSegment.position, dragonSegment.position); if(distance > minJointDistance) { dragonSegment.position = getVectorPercentDistance(dragonSegment.position, prevDragonSegment.position, 0.5 - (stretchiness / 200)); } angle = getVectorAngle(prevDragonSegment.position, dragonSegment.position); } // draw line to fill inbetween dragon segments if (idx > 0) { context.beginPath(); context.moveTo(prevDragonSegment.position[0], prevDragonSegment.position[1]); context.lineTo(dragonSegment.position[0], dragonSegment.position[1]); context.lineWidth = dragonSegmentSize * 0.4; context.strokeStyle = '#cc1a1a'; context.stroke(); } // save the context's current state before doing any transformations context.save(); // move the context to the dragonSegment's position context.translate(dragonSegment.position[0], dragonSegment.position[1]); context.rotate(angle); // flip if mouse is on right of dragon head if (mousePos[0] > dragonSegment.position[0]) context.scale(1, -1); context.drawImage(dragonSegment.image, -dragonSegmentSize / 2 * dragonSegment.image.width / dragonSegment.image.height, -dragonSegmentSize / 2, dragonSegmentSize * dragonSegment.image.width / dragonSegment.image.height, dragonSegmentSize); context.restore(); // restore the context to the saved state } // =============================== // ============================================================== // =============================== // Orb code // =============================== // Creates an array of orbs function createOrbs(numOrbs) { var temp = []; for(var i = 0; i < numOrbs; i++) { temp.push(createOrbItem()); } return temp; } // Creates a orb of random position, size, and color function createOrbItem() { var orb = {}; orb.position = getRandomScreenPosition(); orb.radius = Math.random() * 5 + 10; orb.color = 'rgba(244, 246, 164, ' + (Math.random() * 0.3 + 0.5) + ')'; orb.lineColor = 'rgba(232, 244, 243, 0.5)'; orb.remove = false; return orb; } function drawOrb(orb) { context.beginPath(); // use Math.random() to add slight variations to the orb radius, making it look like it is wiggling context.arc(orb.position[0], orb.position[1], orb.radius * (0.95 + Math.random() / 10), 0, 2 * Math.PI); context.fillStyle = orb.color; context.strokeStyle = orb.lineColor; context.lineWidth = 2; context.fill(); context.stroke(); } // Checks to see if the dragon's head (approximated as a circle) has collided with a specified orb function checkCollision(orb) { var val = Math.pow(orb.position[0] - dragon[0].position[0], 2) + Math.pow(orb.position[1] - dragon[0].position[1], 2); return Math.pow(orb.radius - dragonSegmentSize, 2) <= val && val <= Math.pow(orb.radius + dragonSegmentSize, 2); } // =============================== // ============================================================== // =============================== // Fireworks Code // =============================== function createFirework(position) { var firework = {}; firework.position = position; // Random lifetime to make the fireworks look more varied firework.lifetime = Math.random() * 300 + 400; firework.image = fireworkImages[Math.floor(Math.random() * fireworkImages.length)]; firework.imageSize = Math.random() * 50 + 40; firework.remove = false; fireworks.push(firework); // Use setTimeout() to mark the firework for deletion after its lifetime has passed var timeout = setTimeout(function() { firework.remove = true; }, firework.lifetime); } function drawFirework(firework) { // Every 4 frames, switch to a random firework image to make the firework look like it is flashing if(frame % 4 == 0) { firework.image = fireworkImages[Math.floor(Math.random() * 9)]; } // Special 'blend mode' to make the fireworks look more glowy context.globalCompositeOperation = "lighten"; context.drawImage(firework.image, firework.position[0] - firework.imageSize * 0.5, firework.position[1] - firework.imageSize * 0.5, firework.imageSize, firework.imageSize); // Return 'blend mode' to the normal one context.globalCompositeOperation = "source-over"; } // =============================== // ============================================================== // =============================== // Math Functions // =============================== function clamp(value, lo, hi) { return Math.max(Math.min(value, hi), lo); } function getPercentDistance(start, end, fraction) { return (1 - fraction) * start + fraction * end; } function getRandomScreenPosition() { return [ Math.floor(Math.random() * canvas.width), Math.floor(Math.random() * canvas.height) ]; } function getRandomColor(a) { var r = 255 * Math.random() | 0, g = 255 * Math.random() | 0, b = 255 * Math.random() | 0; return 'rgb(' + r + ',' + g + ',' + b + ',' + a + ')'; } function getColor(r, g, b, a) { return 'rgb(' + r + ',' + g + ',' + b + ',' + a + ')'; } // =============================== // ============================================================== // =============================== // Vector Functions // =============================== function createVectorOfLength(length) { var vec = []; for(var i = 0; i < length; i++) { vec.push(0); } return vec; } function getVectorPercentDistance(A, B, fraction) { var interpolated = []; for(var i = 0; i < A.length; i++) { interpolated.push(getPercentDistance(A[i], B[i], fraction)); } return interpolated; } function getVectorDistance(A, B) { var dist = 0; for(var i = 0; i < A.length; i++) { dist += (A[i] - B[i]) * (A[i] - B[i]); } return Math.max(Math.sqrt(dist), 0.00001); } function getVectorAngle(A, B) { return Math.atan2(B[1] - A[1], B[0] - A[0]); } // ===============================