danovo
Level 0
(Not an actual photograph)
|
|
« on: January 17, 2018, 01:53:50 AM » |
|
Hello there! I was making a game based on the idea of quadtrees and came up with a neat little idea that hopefully some of you will be able to use. The thing is to make a recursive skill tree: The idea is you can either choose to improve a general area, like "Movement", or something really specific, like "Movement > Run > Control". Each 'upgrade' has the same amount of points distributed over different area, so the more specific you get, the more points that go there. Also, the code is set to not allow overlaps, which leads to some interesting decisions, but it can be easily changed. I don't know how to attach files so here's the full code. Just copy paste it into a .html file to test it for yourself. (Beware, the implementation is barebones and sketchy, if you actually plan to use this in an actual game you'll probably want to rewrite it) <canvas id="gc" width="600" height="800"></canvas> <script> window.onload=function() { canvas=document.getElementById("gc"); ctx=canvas.getContext("2d"); if (document.addEventListener) { document.addEventListener("mousewheel", MouseWheelHandler, false); document.addEventListener("DOMMouseScroll", MouseWheelHandler, false); } else { document.attachEvent("onmousewheel", MouseWheelHandler); } canvas.oncontextmenu = function(e) { e.preventDefault(); } canvas.onmousedown = function (e) { window.focus(); mouse.button = e.which; mouse.px = mouse.x; mouse.py = mouse.y; var rect = canvas.getBoundingClientRect(); mouse.x = e.clientX - rect.left, mouse.y = e.clientY - rect.top, mouse.down = true; e.preventDefault(); e.stopPropagation(); e.target.style.cursor = 'default'; if (mouse.button == 1 && mouse.inboard) { if (ALLOW_OVERLAP || !overlaps(mousePoint)) { curpoints.push(mousePoint); } } else if (mouse.button == 3 && mouse.inboard) { if (overlaps(mousePoint)) { curpoints = curpoints.filter(function(el) { return !overlaps(el, [mousePoint]); }); } } };
canvas.onmouseup = function (e) { mouse.down = false; if (e) e.preventDefault(); };
canvas.onmousemove = function (e) { mouse.px = mouse.x; mouse.py = mouse.y; var rect = canvas.getBoundingClientRect(); mouse.x = e.clientX - rect.left, mouse.y = e.clientY - rect.top, mouse.inboard = mouse.x >= BOARD.x && mouse.x < BOARD.x + BOARD.w && mouse.y >= BOARD.y && mouse.y < BOARD.y + BOARD.h; e.preventDefault(); }; requestAnimationFrame(run); }
function MouseWheelHandler(e) { // cross-browser wheel delta var e = window.event || e; var delta = Math.max(-1, Math.min(1, (e.wheelDelta || -e.detail))); zoom += delta; zoom = Math.min(MAX_ZOOM, Math.max(zoom, 1)); /*e.preventDefault(); e.stopPropagation();*/ return false; }
var mouse = { down: false, button: 1, x: 0, y: 0, px: 0, py: 0, inboard: false }; var canvas; var ctx;
var MAX_ZOOM = 3; var BOARD = {x: 0, y: 0, w: 600, h:600}; var ALLOW_OVERLAP = false; var zoom = 3; var mousePoint = []; var curpoints = [];
var DESCRIPTIONS = { 0: { 0: { 0:"Duration", 1:"Radius", 2:"Cost", 3:"Damage", "name":"Grenades"}, 1: { 0:"Recharge", 1:"Range", 2:"Cost", 3:"Damage", "name":"Rifles"}, 2: { 0:"Spike Trap", 1:"Bait", 2:"Landmine", 3:"Shark attack!", "name":"Specials"}, 3: { 0:"SAMPLE_TEXT", 1:"SAMPLE_TEXT", 2:"SAMPLE_TEXT", 3:"SAMPLE_TEXT", "name":"SAMPLE_TEXT"}, "name":"Weapons"}, 1: { 0: { 0:"Speed", 1:"Duration", 2:"Stamina", 3:"Control", "name":"Run"}, 1: { 0:"Speed", 1:"Duration", 2:"Cost", 3:"Control", "name":"Jump"}, 2: { 0:"Speed", 1:"Recharge", 2:"Range", 3:"Damage", "name":"Teleport"}, 3: { 0:"SAMPLE_TEXT", 1:"SAMPLE_TEXT", 2:"SAMPLE_TEXT", 3:"SAMPLE_TEXT", "name":"SAMPLE_TEXT"}, "name":"Movement"}, 2: { 0: { 0:"More Health!", 1:"More Health!", 2:"More Health!", 3:"More Health!", "name":"Health"}, 1: { 0:"Cost", 1:"Regen", 2:"Effectivity", 3:"Amount", "name":"Armor"}, 2: { 0:"HP / s", 1:"Vampire", 2:"Find Potions", 3:"SAMPLE_TEXT", "name":"Regeneration"}, 3: { 0:"SAMPLE_TEXT", 1:"SAMPLE_TEXT", 2:"SAMPLE_TEXT", 3:"SAMPLE_TEXT", "name":"SAMPLE_TEXT"}, "name":"Life"}, 3: { 0: { 0:"SAMPLE_TEXT", 1:"SAMPLE_TEXT", 2:"SAMPLE_TEXT", 3:"SAMPLE_TEXT", "name":"SAMPLE_TEXT"}, 1: { 0:"SAMPLE_TEXT", 1:"SAMPLE_TEXT", 2:"SAMPLE_TEXT", 3:"SAMPLE_TEXT", "name":"SAMPLE_TEXT"}, 2: { 0:"SAMPLE_TEXT", 1:"SAMPLE_TEXT", 2:"SAMPLE_TEXT", 3:"SAMPLE_TEXT", "name":"SAMPLE_TEXT"}, 3: { 0:"SAMPLE_TEXT", 1:"SAMPLE_TEXT", 2:"SAMPLE_TEXT", 3:"SAMPLE_TEXT", "name":"SAMPLE_TEXT"}, "name":"SAMPLE_TEXT"}, }
var run = function(time) { ctx.beginPath(); ctx.fillStyle="white"; ctx.fillRect(0,0,canvas.width,canvas.height); ctx.fillStyle="black"; ctx.rect(BOARD.x, BOARD.y, BOARD.w, BOARD.h); ctx.moveTo(BOARD.x + BOARD.w/2, BOARD.y); ctx.lineTo(BOARD.x + BOARD.w/2, BOARD.y + BOARD.h); ctx.moveTo(BOARD.x, BOARD.y + BOARD.h/2); ctx.lineTo(BOARD.x + BOARD.w, BOARD.y + BOARD.h/2); ctx.stroke(); mousePoint = pointPath(mouse.x, mouse.y, zoom); curpoints.forEach(function(el) {drawQuad(el);}); if (mouse.inboard) { var col = 'rgba(0,0,0,' + Math.pow((mousePoint.length / MAX_ZOOM),1.6) + ')'; if (!ALLOW_OVERLAP && overlaps(mousePoint)) col = 'rgba(255,0,0,0.3)'; drawQuad(mousePoint, col); var text = ""; var desc = DESCRIPTIONS; for (var i = 0; i < mousePoint.length; i++) { text += " > " + (desc[mousePoint[i]].name || desc[mousePoint[i]]); desc = desc[mousePoint[i]]; } ctx.font = "30px Arial"; ctx.fillStyle = "black"; ctx.textBaseline="top"; ctx.fillText(text,BOARD.x, BOARD.y + BOARD.h); } requestAnimationFrame(run); }
// Returns the path to reach a given point function pointPath(px, py, d) { var x = BOARD.x; var y = BOARD.y; var w = BOARD.w; var h = BOARD.h; var z = 0; var path = []; while (z < d && px >= x && px < x+w && py >= y && py < y+h) { if (px < x+w/2) { if (py < y+h/2) { path.push(0); } else { path.push(2); y += h/2; } } else { if (py < y+h/2) { path.push(1); x += w/2; } else { path.push(3); x += w/2; y += h/2; } } w /= 2; h /= 2; z += 1; } return path; }
function drawQuad(point, color) { var x = BOARD.x; var y = BOARD.y; var w = BOARD.w; var h = BOARD.h; for (var i = 0; i < point.length; i++) { ctx.beginPath(); ctx.rect(x, y, w/2,h/2); ctx.rect(x+w/2,y, w/2,h/2); ctx.rect(x+w/2,y+h/2, w/2,h/2); ctx.rect(x, y+h/2, w/2,h/2); ctx.stroke(); if (point[i] == 1 || point[i] == 3) { x += w/2 } if (point[i] == 2 || point[i] == 3) { y += w/2 } w /= 2; h /= 2; } ctx.beginPath(); var col = color || 'rgba(0,0,0,' + Math.pow((point.length / MAX_ZOOM),1.6) + ')'; ctx.fillStyle = col; ctx.fillRect(x,y,w,h); ctx.closePath(); }
function overlaps(value, check) { check = check || curpoints; return check.reduce(function(cur, el) { var smaller = Math.min(el.length, value.length); return cur + (el.slice(0, smaller).toString() == value.slice(0, smaller).toString()); }, 0); }
if (!Array.prototype.hasOwnProperty("last")) { Object.defineProperty(Array.prototype, "last", { get: function() { return this[this.length - 1]; }, set: function(val) { this[this.length - 1] = val; } }); } </script>
|