505 lines
10 KiB
HTML
505 lines
10 KiB
HTML
<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
|
<style>
|
|
canvas {
|
|
border:1px solid #d3d3d3;
|
|
background-color: #f1f1f1;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body onload="startGame()">
|
|
<script>
|
|
|
|
var myGamePiece;
|
|
var things = [];
|
|
var myScore;
|
|
|
|
var curpath = [];
|
|
var pathvalid = false;
|
|
|
|
var MAXDIRS = 4;
|
|
var DIRXMOD = [ 0, 1, 0, -1 ];
|
|
var DIRYMOD = [ -1, 0, 1, 0 ];
|
|
|
|
var GRAVITY = 0.5;
|
|
var GRIDSIZE = 80;
|
|
var THINGSIZE = 64;
|
|
|
|
var GRIDW = 5;
|
|
var GRIDH = 5;
|
|
|
|
function getgridthing(gridx, gridy) {
|
|
var i;
|
|
for (i = 0; i < things.length; i += 1) {
|
|
if ((things[i].gridx == gridx) && (things[i].gridy == gridy)) {
|
|
return things[i];
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
function getthingxy(x, y) {
|
|
var i;
|
|
for (i = 0; i < things.length; i += 1) {
|
|
if ((x >= things[i].x) && (x <= things[i].x + THINGSIZE-1) &&
|
|
(y >= things[i].y) && (y <= things[i].y + THINGSIZE-1)) {
|
|
return things[i];
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
function clearpath() {
|
|
curpath = [];
|
|
pathvalid = false;
|
|
}
|
|
|
|
function addtopath(what) {
|
|
console.log("addpath() " + what.name);
|
|
|
|
dumppath("addpath pre: ", curpath);
|
|
|
|
curpath.push(what);
|
|
|
|
pathvalid = true;
|
|
if (curpath.length == 1) {
|
|
console.log("Starting path with " + what.name);
|
|
} else {
|
|
dumppath("Cur path is: ",curpath);
|
|
}
|
|
}
|
|
|
|
function pathcontains(what) {
|
|
var i;
|
|
if (curpath == undefined) return false;
|
|
|
|
for (i = 0; i < curpath.length; i += 1) {
|
|
if (curpath[i] == what) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
function isvalidpath(mypath) {
|
|
var valid = true;
|
|
|
|
for (i = 0; i < mypath.length - 1; i++) {
|
|
var thisone,nextone;
|
|
thisone = mypath[i];
|
|
/*
|
|
if (i == mypath.length - 1) { // last one
|
|
nextone = null;
|
|
} else {
|
|
nextone = mypath[i+1];
|
|
}
|
|
*/
|
|
nextone = mypath[i+1];
|
|
|
|
if ((thisone.type == "cat") && nextone.type == "cat") {
|
|
// lines of cats are ok
|
|
} else if ((i == 0) && (thisone.type == "cat") && (nextone.type == "food")) {
|
|
// first cat -> food is ok
|
|
} else {
|
|
// not ok
|
|
valid = false;
|
|
break;
|
|
}
|
|
}
|
|
//var pr = "isvalidpath()? " + valid + " ";
|
|
//dumppath(pr, mypath);
|
|
return valid;
|
|
}
|
|
|
|
// would adding 'overthing' to our existing path result in a valid path?
|
|
function canextendpath(overthing) {
|
|
if (!overthing) return false;
|
|
|
|
if (overthing &&
|
|
isadjacent(overthing, curpath[curpath.length-1]) && // adjacent to last thing in path?
|
|
!pathcontains(overthing) ) { // path doesn't already contain this?
|
|
// create a fake new path containing this.
|
|
var fakepath = curpath.slice();
|
|
fakepath.push(overthing);
|
|
if (isvalidpath(fakepath)) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
function isadjacent(thing1, thing2) {
|
|
// is thing1 adjacent to thing2?
|
|
var newgridx,newgridy;
|
|
|
|
if (thing1 == thing2) return false;
|
|
|
|
for (i = 0; i < MAXDIRS; i++) {
|
|
newgridx = thing1.gridx + DIRXMOD[i];
|
|
newgridy = thing1.gridy + DIRYMOD[i];
|
|
if ((thing2.gridx == newgridx) && (thing2.gridy == newgridy)) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
function startGame() {
|
|
var x,y;
|
|
for (y = 0; y < GRIDH; y++) {
|
|
for (x = 0; x < GRIDW; x++) {
|
|
things.push(new thing(x, y, "random"));
|
|
}
|
|
}
|
|
|
|
myGameArea.start();
|
|
}
|
|
|
|
function dumppath(prefix,arr) {
|
|
var str;
|
|
str = "";
|
|
for (i = 0; i < arr.length; i++) {
|
|
str = str + " " + arr[i].name;
|
|
}
|
|
console.log(prefix + str);
|
|
}
|
|
|
|
function thingsmoving() {
|
|
for (i = 0; i < things.length; i += 1) {
|
|
if (things[i].state != "stop") {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
var myGameArea = {
|
|
canvas : document.createElement("canvas"),
|
|
start : function() {
|
|
this.canvas.width = 480;
|
|
this.canvas.height = 640;
|
|
this.context = this.canvas.getContext("2d");
|
|
document.body.insertBefore(this.canvas, document.body.childNodes[0]);
|
|
this.frameNo = 0;
|
|
this.interval = setInterval(updateGameArea, 20);
|
|
|
|
this.canvas.addEventListener('click', this.handleclick, false);
|
|
this.canvas.addEventListener('mousedown', this.handlemousedown, false);
|
|
this.canvas.addEventListener('mouseup', this.handlemouseup, false);
|
|
this.canvas.addEventListener('mousemove', this.handlemousemove, false);
|
|
},
|
|
|
|
clear : function() {
|
|
this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
|
|
},
|
|
|
|
draw : function() {
|
|
this.context.strokeStyle = "black";
|
|
this.context.beginPath();
|
|
for (y = 0; y < GRIDH*GRIDSIZE; y += GRIDSIZE) {
|
|
for (x = 0; x < GRIDW*GRIDSIZE; x += GRIDSIZE) {
|
|
this.context.rect(x, y, GRIDSIZE-1, GRIDSIZE-1);
|
|
}
|
|
}
|
|
|
|
this.context.stroke();
|
|
},
|
|
|
|
/*
|
|
handleclick : function(event) {
|
|
// make sure nothing is moving
|
|
if (thingsmoving()) return;
|
|
|
|
// did you click on an object?
|
|
var clickedthing = getthingxy(event.pageX,event.pageY);
|
|
if (clickedthing) {
|
|
clickedthing.kill();
|
|
}
|
|
},
|
|
*/
|
|
|
|
handlemousedown : function(event) {
|
|
// make sure nothing is moving
|
|
if (thingsmoving()) return;
|
|
|
|
// clear existing path
|
|
clearpath();
|
|
|
|
// did you click on an object?
|
|
var onthing = getthingxy(event.pageX,event.pageY);
|
|
if (onthing) {
|
|
console.log("Initial click on " + onthing.name);
|
|
addtopath(onthing);
|
|
}
|
|
},
|
|
|
|
handlemousemove : function(event) {
|
|
// make sure nothing is moving
|
|
if (thingsmoving()) return;
|
|
|
|
// existing path?
|
|
if (curpath != undefined && curpath.length > 0) {
|
|
var overthing = getthingxy(event.pageX,event.pageY);
|
|
var lastinpath;
|
|
if (curpath == undefined) {
|
|
lastinpath = null;
|
|
} else {
|
|
lastinpath = curpath[curpath.length-1];
|
|
}
|
|
|
|
if (canextendpath(overthing)) {
|
|
// add it to the path
|
|
addtopath(overthing);
|
|
} else if (pathcontains(overthing)) {
|
|
pathvalid = true;
|
|
} else {
|
|
pathvalid = false;
|
|
}
|
|
}
|
|
},
|
|
|
|
handlemouseup : function(event) {
|
|
var ok = true;
|
|
var overthing = getthingxy(event.pageX,event.pageY);
|
|
if (thingsmoving()) {
|
|
console.log("mouseup() - things are moving");
|
|
ok = false;
|
|
} else if (!isvalidpath(curpath)) {
|
|
console.log("mouseup() - path isn't valid");
|
|
ok = false;
|
|
} else if ((overthing == undefined) || !pathcontains(overthing)) {
|
|
console.log("mouseup() - not over something in path");
|
|
ok = false;
|
|
}
|
|
|
|
if (!ok) {
|
|
clearpath();
|
|
return;
|
|
}
|
|
|
|
// kill all in path
|
|
while (curpath != undefined && curpath.length > 0) {
|
|
curpath[0].kill();
|
|
curpath.splice(0, 1);
|
|
}
|
|
clearpath();
|
|
},
|
|
}
|
|
|
|
|
|
function getrandomcolour() {
|
|
var letters = '0123456789ABCDEF';
|
|
var col = '#';
|
|
for (var i = 0; i < 6; i++ ) {
|
|
col += letters[Math.floor(Math.random() * 16)];
|
|
}
|
|
return col;
|
|
}
|
|
|
|
function getrandomname() {
|
|
var letters = '0123456789';
|
|
var name = "";
|
|
for (var i = 0; i < 3; i++ ) {
|
|
name += letters[Math.floor(Math.random() * 10)];
|
|
}
|
|
return name;
|
|
}
|
|
|
|
function getrandomtype() {
|
|
var pct,type;
|
|
pct = Math.random() * 100;
|
|
if ( pct < 50) {
|
|
type = "cat";
|
|
} else {
|
|
type = "food";
|
|
}
|
|
return type;
|
|
}
|
|
|
|
function thing(gridx, gridy, type) {
|
|
this.width = THINGSIZE;
|
|
this.height = THINGSIZE;
|
|
|
|
if (type == "random") {
|
|
type = getrandomtype();
|
|
}
|
|
|
|
this.type = type;
|
|
if (this.type == "cat") {
|
|
this.color = "#b5dea8";
|
|
} else if (type == "food") {
|
|
this.color = "#d8db03";
|
|
} else {
|
|
this.color = getrandomcolour();
|
|
}
|
|
|
|
this.name = type + "-" + getrandomname();
|
|
|
|
this.gridx = gridx;
|
|
if (gridy == "top") {
|
|
highest = 999;
|
|
// find highest
|
|
for (i = 0; i < things.length; i += 1) {
|
|
if ((things[i].gridx == gridx) &&
|
|
(things[i].gridy <= highest)) {
|
|
highest = things[i].gridy-1;
|
|
}
|
|
}
|
|
gridy = highest;
|
|
//console.log("adding thing at gridy = " + gridy);
|
|
}
|
|
this.gridy = gridy;
|
|
this.yspeed = 0;
|
|
this.state = "stop";
|
|
this.x = gridx * GRIDSIZE;
|
|
this.y = gridy * GRIDSIZE;
|
|
|
|
this.draw = function() {
|
|
var yoff;
|
|
var inpath = false;
|
|
|
|
ctx = myGameArea.context;
|
|
ctx.fillStyle = this.color;
|
|
|
|
// draw myself
|
|
ctx.fillRect(this.x, this.y, this.width, this.height);
|
|
|
|
// highlight?
|
|
if (pathcontains(this)) {
|
|
inpath = true;
|
|
}
|
|
|
|
|
|
// draw text
|
|
ctx.fillStyle = "black";
|
|
ctx.fillText(this.name, this.x + 10, this.y + (THINGSIZE/2));
|
|
ctx.fillText(this.state, this.x + 10, this.y + (THINGSIZE/2) + 10);
|
|
|
|
if (inpath) {
|
|
ctx.beginPath();
|
|
ctx.fillText("PATH", this.x + 10, this.y + (THINGSIZE/2) + 20);
|
|
if (pathvalid) {
|
|
ctx.strokeStyle = "green";
|
|
} else {
|
|
ctx.strokeStyle = "red";
|
|
}
|
|
ctx.rect(this.x, this.y, this.width, this.height);
|
|
ctx.stroke();
|
|
}
|
|
|
|
}
|
|
|
|
this.issametype = function(otherthing) {
|
|
if (otherthing == undefined) return false;
|
|
if (otherthing.type == this.type) return true;
|
|
return false;
|
|
}
|
|
|
|
this.snaptogrid = function() {
|
|
if (this.y % GRIDSIZE != 0) {
|
|
this.y = this.gridy * GRIDSIZE;
|
|
}
|
|
}
|
|
|
|
this.getstoppedbelowthing = function() {
|
|
var bt;
|
|
bt = getgridthing(this.gridx, this.gridy + 1);
|
|
if (bt && bt.state != "fall") {
|
|
return bt;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
|
|
this.kill = function() {
|
|
// add a new cat above us
|
|
things.push(new thing(this.gridx, "top", "random"));
|
|
|
|
// kill ourselves
|
|
var idx = things.indexOf(this);
|
|
things.splice(idx, 1);
|
|
}
|
|
|
|
this.move = function() {
|
|
// not at bottom and nothing fixed below us?
|
|
var dofall = false;
|
|
var belowthing = null,atbottom = false;
|
|
if ((this.gridy >= GRIDH-1)) {
|
|
atbottom = true;
|
|
}
|
|
if (!atbottom && !this.getstoppedbelowthing()) {
|
|
// accelerate
|
|
this.yspeed += GRAVITY;
|
|
|
|
// move
|
|
this.y += this.yspeed;
|
|
|
|
// don't go below bottom of screen
|
|
this.hitBottom();
|
|
|
|
// calc new gridx / gridy
|
|
this.gridx = Math.floor(this.x / GRIDSIZE);
|
|
this.gridy = Math.floor(this.y / GRIDSIZE);
|
|
|
|
this.state = "fall";
|
|
}
|
|
|
|
// hit something?
|
|
if (atbottom || this.getstoppedbelowthing()) {
|
|
// something below us.
|
|
|
|
// stop
|
|
this.yspeed = 0;
|
|
|
|
// snap to grid
|
|
this.snaptogrid();
|
|
|
|
this.state = "stop";
|
|
}
|
|
|
|
}
|
|
|
|
this.hitBottom = function() {
|
|
var rockbottom = GRIDSIZE * GRIDH;
|
|
if (this.y > rockbottom) {
|
|
this.y = rockbottom;
|
|
this.yspeed = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
function updateGameArea() {
|
|
var x, height, gap, minHeight, maxHeight, minGap, maxGap;
|
|
|
|
myGameArea.clear();
|
|
myGameArea.draw();
|
|
myGameArea.frameNo += 1;
|
|
for (i = 0; i < things.length; i += 1) {
|
|
things[i].draw();
|
|
things[i].move();
|
|
}
|
|
//myScore.text="SCORE: " + myGameArea.frameNo;
|
|
//myScore.draw();
|
|
//myGamePiece.move();
|
|
//myGamePiece.update();
|
|
}
|
|
|
|
function everyinterval(n) {
|
|
if ((myGameArea.frameNo / n) % 1 == 0) {return true;}
|
|
return false;
|
|
}
|
|
|
|
//<button onmousedown="accelerate(-0.2)" onmouseup="accelerate(0.05)">ACCELERATE</button>
|
|
</script>
|
|
<br>
|
|
<p>Test game</p>
|
|
</body>
|
|
</html>
|
|
|
|
|