I have a javascript game that uses drag and drop of images to create words. Currently if the word has repeating letters, I have to name the letters differently:
Example word: Alphabet,
images: a.png, l.png, p.png, h.png, a1.png, b.png, e.png and t.png.
As you can imagine when you drag a.png to spell the word, it has to be on its own defined block or it wont lock in place.
How can i edit the script to use the same image more than once and be able to drag on any of the correct placements.
See this fiddle for a demo: http://jsfiddle.net/Q89Ck/
<script defer="defer">
function loadImages(sources, callback) {
var assetDir = 'http://kidnplay.co.uk/spelling/alphabet/';
var images = {};
var loadedImages = 0;
var numImages = 0;
for(var src in sources) {
numImages++;
}
for(var src in sources) {
images[src] = new Image();
images[src].onload = function() {
if(++loadedImages >= numImages) {
callback(images);
}
};
images[src].src = assetDir + sources[src];
}
}
function isNearOutline(animal, outline) {
var a = animal;
var o = outline;
var ax = a.getX();
var ay = a.getY();
if(ax > o.x - 20 && ax < o.x + 20 && ay > o.y - 20 && ay < o.y + 20) {
return true;
}
else {
return false;
}
}
function drawBackground(background, backImg, text) {
var canvas = background.getCanvas();
var context = background.getContext();
context.drawImage(backImg, 0, 0);
context.font = '18pt georgia,palatino';
context.textAlign = 'center';
context.fillStyle = 'white';
context.fillText(text, background.getStage().getWidth() / 2, 32);
}
function initStage(images) {
var stage = new Kinetic.Stage({
container: 'container',
width: 940,
height: 600
});
var background = new Kinetic.Layer();
var animalLayer = new Kinetic.Layer();
var animalShapes = [];
var score = 0;
// image positions
var animals = {
a: {
x: 50,
y: 70
},
e: {
x: 150,
y: 70
},
b: {
x: 250,
y: 70
},
t: {
x: 350,
y: 70
},
a2: {
x: 450,
y: 70
},
p: {
x: 550,
y: 70
},
l: {
x: 650,
y: 70
},
h: {
x: 750,
y: 70
},
};
var outlines = {
a_black: {
x: 30,
y: 300
},
l_black: {
x: 135,
y: 300
},
p_black: {
x: 240,
y: 300
},
h_black: {
x: 345,
y: 300
},
a2_black: {
x: 450,
y: 300
},
b_black: {
x: 555,
y: 300
},
e_black: {
x: 660,
y: 300
},
t_black: {
x: 765,
y: 300
},
};
// create draggable animals
for(var key in animals) {
// anonymous function to induce scope
(function() {
var privKey = key;
var anim = animals[key];
var animal = new Kinetic.Image({
image: images[key],
x: anim.x,
y: anim.y,
draggable: true
});
animal.createImageHitRegion();
animal.on('dragstart', function() {
this.moveToTop();
animalLayer.draw();
});
/*
* check if animal is in the right spot and
* snap into place if it is
*/
animal.on('dragend', function() {
var outline = outlines[privKey + '_black'];
if(!animal.inRightPlace && isNearOutline(animal, outline)) {
animal.setPosition(outline.x, outline.y);
animalLayer.draw();
animal.inRightPlace = true;
if(++score >= 8) {
var text = 'Well done! The correct word is alphabet!'
drawBackground(background, images.back, text);
}
// disable drag and drop
setTimeout(function() {
animal.setDraggable(false);
}, 50);
}
});
// make animal glow on mouseover
animal.on('mouseover', function() {
animal.setImage(images[privKey + '_glow']);
animalLayer.draw();
document.body.style.cursor = 'pointer';
});
// return animal on mouseout
animal.on('mouseout', function() {
animal.setImage(images[privKey]);
animalLayer.draw();
document.body.style.cursor = 'default';
});
animal.on('dragmove', function() {
document.body.style.cursor = 'pointer';
});
animalLayer.add(animal);
animalShapes.push(animal);
})();
}
// create animal outlines
for(var key in outlines) {
// anonymous function to induce scope
(function() {
var imageObj = images[key];
var out = outlines[key];
var outline = new Kinetic.Image({
image: imageObj,
x: out.x,
y: out.y
});
animalLayer.add(outline);
})();
}
stage.add(background);
stage.add(animalLayer);
drawBackground(background, images.back, 'Rearrange the letters to spell the word');
}
var sources = {
back: 'back.png',
a: 'a.png',
a_glow: 'a-glow.png',
a_black: 'a-black.png',
b: 'b.png',
b_glow: 'b-glow.png',
b_black: 'b-black.png',
e: 'e.png',
e_glow: 'e-glow.png',
e_black: 'e-black.png',
h: 'h.png',
h_glow: 'h-glow.png',
h_black: 'h-black.png',
l: 'l.png',
l_glow: 'l-glow.png',
l_black: 'l-black.png',
p: 'p.png',
p_glow: 'p-glow.png',
p_black: 'p-black.png',
t: 't.png',
t_glow: 't-glow.png',
t_black: 't-black.png',
a2: 'a2.png',
a2_glow: 'a2-glow.png',
a2_black: 'a2-black.png',
};
loadImages(sources, initStage);
</script>
For using same image for both As:
You need to separate out the dependency of image names with the key you use.
One possible way is to add another attribute in the arrays which have the value of actual alphabet and use that value to source from your images array. This basically solves your issue with using same images for 2 variables.
For snapping either A's in either of the possible positions:
You can use suggestion from Barmar in the comments :)
To allow fitting either “A” into an outline, assign both the animal and outline a “letter” property.
Add a “letter” property to each animal object:
animal.letter=”A”;
Add a “correct” letter property to each outline object:
outline.letter=”A”;
Then you can check if a correct letter is in a specified outline:
if( outline.letter == animal.letter ) {
// a valid animal is in the outline
}
This also allows you to use the same A.png in both the “A-animals”.
Related
I have a very strange behaviour of my script: only from time to time (seldom 3-4 times at one time right after each other, but more likely every 7th to 150th trial) the skript loads, but I only see a white canvas and get the error message:
Uncaught TypeError: Cannot read property 'getParent' of
undefinedKonva.Util.addMethods.add # konva.min.js:44draw #
floorplansurvey.php:950(anonymous function) #
floorplansurvey.php:985images.(anonymous function).onload #
floorplansurvey.php:390
On reload it often works again...
I just have no idea at all what is happening here, the bug can't be forced/reproduced, I thank you so much, if you have anything you can help me with. Even a strategy for a clearer analysis would be helpful, sorry for being that unspecific and the long code
edit: I've made a jsfiddle under:
https://jsfiddle.net/17548hmv/1/
run it several times, until the error occures
these are the code snippets at:
# floorplansurvey.php:390:
function loadImages(sources, draw) {
//window.location.reload(true);
var images = {};
var loadedImages = 0;
var numImages = 0;
// get num of sources
for(var src in sources) {
numImages++;
}
for(var src in sources) {
images[src] = new Image();
images[src].onload = function() {
if(++loadedImages >= numImages) {
draw(images);
}
};
images[src].src = sources[src];
}
delete (loadedImages);
delete (numImages);
};
# floorplansurvey.php:985images.(anonymous function).onload:
loadImages(sources, function(images) {
draw(images);
});
# floorplansurvey.php:950(anonymous function):
bglayer.add(plan);
# konva.min.js:44draw:
I dont understand this one myself
add:function(t)
{if(arguments.length>1)
{for(var e=0;e<arguments.length;e++)
this.add(arguments[e]);
return this}if(t.getParent())return t.moveTo(this),this;
var n=this.children;
return
Var sources is defined like:
var sources = {
Cd: './graphics/Cd.png',
Cu: './graphics/Cu.png',
Ca: './graphics/Ca.png',
Cs: './graphics/Cs.png',
Cc: './graphics/Cc.png',
Ed: './graphics/Ed.png',
Eu: './graphics/Eu.png',
Ea: './graphics/Ea.png',
Es: './graphics/Es.png',
Ec: './graphics/Ec.png',
Hd: './graphics/Hd.png',
Hu: './graphics/Hu.png',
...and so on
and this is the function draw:
function draw(images) {
for (i=0, len=showdatax.length; i<=len-1; i++)
{
//window.location.reload(true);
var gridcell = new Konva.Rect({
x: parseInt((imagesizeX - showdatax[i])*scalar-(gridcellsize/2)),
y: parseInt((imagesizeY - showdatay[i])*scalar-(gridcellsize/2)),
offset: [0, 0],
width: gridcellsize,
height: gridcellsize,
//fill: 'white',
//stroke: 'grey',
//strokeWidth: 2,
draggable: false,
id: showdatav[i]
});
gridlayer.add(gridcell);
}
//defaultsettiongs
var init = new Array();
init['x'] = new Array();
init['y'] = new Array();
init['x']['c'] = 0*scalar;
init['y']['c'] = 170*scalar;
init['x']['e'] = 0*scalar;
init['y']['e'] = 320*scalar;
init['x']['h'] = 0*scalar;
init['y']['h'] = 470*scalar;
init['x']['l'] = 0*scalar;
init['y']['l'] = 620*scalar;
init['x']['s'] = 0*scalar;
init['y']['s'] = 770*scalar;
init['x']['w'] = 0*scalar;
init['y']['w'] = 920*scalar; var step = 0;
var count = new Array (
'c','e','h','l','s','w');
count['c'] = 0;
count['e'] = 0;
count['h'] = 0;
count['l'] = 0;
count['s'] = 0;
count['w'] = 0;
var starttime = new Date();
var loghistory = '';
//drag event functions
function mouseoverbox (box,active)
{
writeMessage('Click and hold the left mouse button and pull this activity icon to the floorplan.');
box.setFillPatternImage(active);
box.shadowColor('blue');
box.moveTo(templayer);
badgelayer.draw();
templayer.draw();
}
function dragstarttouchstartbox (box,pos,kind)
{
//count[kind]++;
writeMessage('dragstart' + count[kind]);
var boxx = box.x;
box.x(pos.x-1.5*gridcellsize);
var boxy = box.y;
box.y(pos.y-1.5*gridcellsize);
var boxrshadowoffsetx = box.shadowOffset();
box.shadowOffset({x:0.25*gridcellsize,y:0.25*gridcellsize});
box.moveTo(templayer);
badgelayer.draw();
templayer.draw();
}
function dragmovebox (box,pos,kind,success,active,caution)
{
writeMessage('Your outside of the floorplan. Dropping the activity icon will reset it to its initial position.');
box.moveTo(templayer);
var boxx = box.x;
box.x(pos.x-1.5*gridcellsize);
var boxy = box.y;
box.y(pos.y-1.5*gridcellsize);
var shape = gridlayer.getIntersection(pos);
if (shape)
{
if (!badgelayer.getIntersection(pos))
{
writeMessage('Release the mouse button to place this activity icon on position (' + shape.x() + '|' + shape.y() + ')');
box.x(shape.x()-gridcellsize);
box.y(shape.y()-gridcellsize);
box.setFillPatternImage(success);
box.shadowColor('green');
badgelayer.draw();
}
else
{
writeMessage('Position (' + shape.x() + '|' + shape.y() + ') is in use!!! Can\'t allocate second activiy icon here.');
var boxx = box.x;
box.x(pos.x-1.5*gridcellsize);
var boxy = box.y;
box.y(pos.y-1.5*gridcellsize);
box.setFillPatternImage(caution);
box.shadowColor('red');
badgelayer.draw();
}
}
else
{
box.setFillPatternImage(active);
box.shadowColor('blue');
templayer.draw();
badgelayer.draw();
}
}
function dragendtouchendbox (box,pos,kind,caution,defaultimage)
{
var shape = gridlayer.getIntersection(pos);
box.moveTo(badgelayer);
templayer.draw();
if (shape && !(badgelayer.getIntersection(pos)))
{
writeMessage('Activity icon successfully placed at position (' + shape.x() + '|' + shape.y() + ').');
box.shadowOffset({x:0,y:0});
box.shadowColor('green');
}
else
{
box.shadowColor('red');
box.setFillPatternImage(caution);
badgelayer.draw();
var fromouttween = new Konva.Tween
({
node: box,
x: init['x'][kind]+imagesizeX*scalar+ gridcellsize,
y: init['y'][kind],
easing: Konva.Easings['EaseOut'],
duration: 0.3
});
if (!shape)
{
writeMessage('Please drop the activity icons inside the floorplan.');
}
else if (badgelayer.getIntersection(pos))
{
writeMessage('Please don\'t drop the activity icons onto a used place.');
}
fromouttween.play();
box.shadowColor('black');
box.setFillPatternImage(defaultimage);
box.shadowOffset({x:0,y:0});
badgelayer.draw();
pos.x=-100;
pos.y=-100;
}
count['kind']++;
step++;
writeResultToForm(pos,count,kind,step,loghistory,starttime);
badgelayer.draw();
templayer.draw();
//writeMessage('dragend');
}
function mouseoutbox (box,defaultimage)
{
box.setFillPatternImage(defaultimage);
box.moveTo(badgelayer);
box.shadowColor('black');
if (!validateForm(false))
{
writeMessage('There are still activity icons left to place.');
}
else
{
writeMessage('All activity icons are placed successfully. You can click "continue" now or change your placements.');
}
badgelayer.draw();
templayer.draw();
}
function alertbox (box,caution)
{
box.setFillPatternImage(caution);
box.shadowcolor('red');
badgelayer.draw;
}
//cbox and text
var textc = new Konva.Text({
x: init['x']['c']+imagesizeX*scalar+gridcellsize*5,
y: init['y']['c']+gridcellsize,
text: 'Cooking',
align: 'left',
width: badgetextwidth
});
var boxc = new Konva.Rect({
x: init['x']['c']+imagesizeX*scalar+gridcellsize,
y: init['y']['c'],
offset: [0, 0],
width: 3*gridcellsize,
height: 3*gridcellsize,
fillPatternImage: images.Cd,
fillPatternScaleX: scalar,
fillPatternScaleY: scalar,
stroke: 'black',
strokeWidth: 4,
draggable: true,
cornerRadius: gridcellsize/2,
shadowColor: 'black',
shadowBlur: 10,
shadowOffset: {x : 0, y : 0},
shadowOpacity: 0.5
});
var boxcd = new Konva.Rect({
x: init['x']['c']+imagesizeX*scalar+gridcellsize,
y: init['y']['c'],
offset: [0, 0],
width: 3*gridcellsize,
height: 3*gridcellsize,
fillPatternImage: images.Cu,
fillPatternScaleX: scalar,
fillPatternScaleY: scalar,
stroke: 'grey',
strokeWidth: 2,
draggable: false,
cornerRadius: gridcellsize/2,
});
boxc.on('mouseover ', function() {
mouseoverbox (this,images.Ca);
});
boxc.on('dragstart', function() {
var pos = stage.getPointerPosition();
dragstarttouchstartbox (this,pos,'c');
});
boxc.on('dragmove', function () {
var pos = stage.getPointerPosition();
dragmovebox(this,pos,'c',images.Cs,images.Ca,images.Cc);
});
boxc.on('dragend', function() {
var pos = stage.getPointerPosition();
dragendtouchendbox (this,pos,'c',images.Cc,images.Cd);
});
boxc.on('mouseout ', function() {
mouseoutbox (this,images.Cd)
});
boxc.on('foo', function() {
alertbox (this,images.Cd)
});
//ebox and text
var texte = new Konva.Text({
x: init['x']['e']+imagesizeX*scalar+gridcellsize*5,
...and so on for all the boxes addes here (5 times as long):
defaultlayer.add(boxcd);
badgelayer.add(boxc);
defaultlayer.add(textc);
defaultlayer.add(boxed);
badgelayer.add(boxe);
defaultlayer.add(texte);
defaultlayer.add(boxhd);
badgelayer.add(boxh);
defaultlayer.add(texth);
defaultlayer.add(boxld);
badgelayer.add(boxl);
defaultlayer.add(textl);
defaultlayer.add(boxsd);
badgelayer.add(boxs);
defaultlayer.add(texts);
defaultlayer.add(boxwd);
badgelayer.add(boxw);
defaultlayer.add(textw);
stage.add(bglayer);
stage.add(gridlayer);
stage.add(defaultlayer);
stage.add(badgelayer);
stage.add(templayer);
}
OK, sorry that it took me so long:
the solution wasn't that easy to find. I found that the script was loaded asynchronously and the png wasn't yet available by using chromes timeline analysis. so i went to my code and had to distinguish between the things, that really should be in the draw function and which not. i added the plan to the array of images (sources) that is loaded (src= ...) before executing draw() and then added
sources.onload= loadImages(sources, function(images) {
draw(images);
});
at the end of my file... no it works without any problem. konva.js had nothing to do with it and is up to now (I'm almost ready) like designed for my project
thanks for the tip #lavrton, it took me on the right way
and you can just put like this:
var imageObj = new Image();
imageObj.src = 'http://localhost:8000/plugins/kamiyar/logo.png';
imageObj.onload = function() {
var img = new Konva.Image({
image: imageObj,
x: stage.getWidth() / 2 - 200 / 2,
y: stage.getHeight() / 2 - 137 / 2,
width: 200,
height: 137,
draggable: true,
stroke: 'blue',
strokeWidth: 1,
dash: [1,5],
strokeEnabled: false
});
layer.add(img);
layer.draw();
};
sorry for my bad English ;)
I am developing canvas to create hotel floor view. I am drawing images on canvas from database. I am taking x,y co-ordinates from database and drawing image on that points. But i want to give touch event to those images. I want to replace image on touch or click event. I want to create same functionality as that of book my show .
this is my code.
<!DOCTYPE HTML>
<html>
<head>
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<script src="http://d3lp1msu2r81bx.cloudfront.net/kjs/js/lib/kinetic-v4.7.2.min.js"></script>
<script src="http://code.jquery.com/ui/1.9.2/jquery-ui.min.js"></script>
<style>
#container{
border:solid 1px #ccc;
margin-top: 10px;
width:100%;
height:100%;
}
html,body,kineticjs-content {
width:100%;
height:100%;
margin: 0px;
}
</style>
</head>
<body>
<div id="container"></div>
<script src="http://localhost/zoilo_admin/public/kinetic-v5.1.0.js"></script>
<script defer="defer">
function writeMessage(message) {
text.setText(message);
layer.draw();
}
function loadImages(sources, position, callback) {
var assetDir = '';
var images = {};
var loadedImages = 0;
var numImages = 0;
for (i = 0; i < sources.length; i++)
{
numImages++;
}
for (i = 0; i < sources.length; i++)
{
images[i] = new Image();
images[i].onload = function () {
if (loadedImages == (sources.length - 1)) {
callback(images, position);
}
loadedImages++;
};
images[i].src = assetDir + sources[i];
}
}
function buildStage(images, position) {
var positionIndex = 0;
var tableActual = {};
console.log(images);
for (var i = 0; i < sources.length; i++)
{
console.log("Here");
tableActual[i] = new Kinetic.Image({
image: images[i],
x: position[i].x,
y: position[i].y
});
// var tableName = src;
// var table1 = new Kinetic.Image({
// image: images[src],
// x: position[positionIndex].x,
// y: position[positionIndex].y
// });
tableActual[i].on('click', function () {
console.log(this.index);
var image = new Kinetic.Image({
image: '4top.png',
x: position[this.index].x,
y: position[this.index].y
});
drawImage(image);
switch (this.index)
{
case 0:
writeMessage('Click on Table ' + 0);
tableActual[positionIndex] = new Kinetic.Image({
image: images[positionIndex],
x: position[positionIndex].x,
y: position[positionIndex].y
});
this.setIm = "4top.png";
break;
case 1:
writeMessage('Click on Table ' + 1);
break;
case 2:
writeMessage('Click on Table ' + 2);
break;
case 3:
writeMessage('Click on Table ' + 3);
break;
case 4:
writeMessage('Click on Table ' + 4);
break;
}
writeMessage('mouseover ' + this[src]);
});
drawImage(tableActual[i]);
positionIndex++;
}
// finally, we need to redraw the layer hit graph
layer.drawHit();
}
var stage = new Kinetic.Stage({
container: 'container',
width: $(window).width(),
height: $(window).height()
});
var layer = new Kinetic.Layer();
var text = new Kinetic.Text({
x: 10,
y: 10,
fontFamily: 'Calibri',
fontSize: 24,
text: '',
fill: 'black'
});
var sources = [
'house204-2.jpg',
'house204-1.jpg',
'4top.png',
'house204-1.jpg',
'4top.png'
];
var position = [
{
x: 380,
y: 60
},
{
x: 180,
y: 60
}
,
{
x: 90,
y: 60
},
{
x: 260,
y: 60
},
{
x: 50,
y: 60
}
];
loadImages(sources, position, buildStage);
function drawImage(Image)
{
layer.add(Image);
layer.add(text);
stage.add(layer);
// in order to ignore transparent pixels in an image when detecting
// events, we first need to cache the image
Image.cache();
// next, we need to redraw the hit graph using the cached image
Image.drawHitFromCache();
}
</script>
</body>
</html>
Yes! you can change it on touch/click event by changing source of that java script image.
<div id="container"></div>
<script src="http://d3lp1msu2r81bx.cloudfront.net/kjs/js/lib/kinetic-v4.4.3.min.js"></script>
<script defer="defer">
var stage = new Kinetic.Stage({
container: 'container',
width: 578,
height: 200
});
var layer = new Kinetic.Layer();
var imageObj = new Image();
imageObj.onload = function() {
var yoda = new Kinetic.Image({
x: 140,
y: stage.getHeight() / 2 - 59,
image: imageObj,
width: 106,
height: 118
});
var filteredYoda = new Kinetic.Image({
x: 320,
y: stage.getHeight() / 2 - 59,
image: imageObj,
width: 106,
height: 118
});
// add the shape to the layer
layer.add(yoda);
layer.add(filteredYoda);
// add the layer to the stage
stage.add(layer);
stage.on('click',function(){
imageObj.src = 'http://crushlabs.com/wp-content/uploads/2013/01/jacee-terry-hello-card-business-card-design-back.jpg';
});
// apply grayscale filter to second image
filteredYoda.applyFilter(Kinetic.Filters.Grayscale, null, function() {
layer.draw();
});
};
imageObj.src = 'http://www.html5canvastutorials.com/demos/assets/yoda.jpg';
</script>
I found this code on the internet. I pasted into my notepad++ and then changed these two files to match the ones that I created on my desktop.
<script src='C:/Users/home-1/Desktop/Box2dWeb-2.1.a.3.js'></script>
<script src='C:/Users/home-1/Desktop/example5.js'></script>
I have the script tag in the html file but I have tried it in the code and in the file and neither of them seem to work.
For some reason the page does not work. I would like to know what is different with this page and why it does not work.
Box2dWeb-2.1.a.3.js
and then created the example5.js file and have it also on my desktop. This should show a canvas along with several objects that you can drop and drag on the screen.
<!DOCTYPE HTML>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Mouse Joint</title>
<script src='C:/Users/home-1/Desktop/Box2dWeb-2.1.a.3.js'></script>
<script src='C:/Users/home-1/Desktop/example5.js'></script>
<style>
canvas
{
background-color:black;
}
</style>
</head>
<body>
<canvas id='b2dCanvas' width='1024' height='500'>Broswer does not
support Canvas Tag</canvas>
<script>
(function() {
var b2Vec2 = Box2D.Common.Math.b2Vec2;
var b2BodyDef = Box2D.Dynamics.b2BodyDef;
var b2Body = Box2D.Dynamics.b2Body;
var b2FixtureDef = Box2D.Dynamics.b2FixtureDef;
var b2Fixture = Box2D.Dynamics.b2Fixture;
var b2World = Box2D.Dynamics.b2World;
var b2MassData = Box2D.Collision.Shapes.b2MassData;
var b2PolygonShape = Box2D.Collision.Shapes.b2PolygonShape;
var b2CircleShape = Box2D.Collision.Shapes.b2CircleShape;
var b2DebugDraw = Box2D.Dynamics.b2DebugDraw;
var Physics = window.Physics = function(element,scale) {
var gravity = new b2Vec2(0,9.8);
this.world = new b2World(gravity, true);
this.element = element;
this.context = element.getContext("2d");
this.scale = scale || 20;
this.dtRemaining = 0;
this.stepAmount = 1/60;
};
Physics.prototype.debug = function() {
this.debugDraw = new b2DebugDraw();
this.debugDraw.SetSprite(this.context);
this.debugDraw.SetDrawScale(this.scale);
this.debugDraw.SetFillAlpha(0.3);
this.debugDraw.SetLineThickness(1.0);
this.debugDraw.SetFlags(b2DebugDraw.e_shapeBit | b2DebugDraw.e_jointBit);
this.world.SetDebugDraw(this.debugDraw);
};
Physics.prototype.step = function(dt) {
this.dtRemaining += dt;
while(this.dtRemaining > this.stepAmount) {
this.dtRemaining -= this.stepAmount;
this.world.Step(this.stepAmount,
10, // velocity iterations
10);// position iterations
}
if(this.debugDraw) {
this.world.DrawDebugData();
} else {
var obj = this.world.GetBodyList();
this.context.clearRect(0,0,this.element.width,this.element.height);
this.context.save();
this.context.scale(this.scale,this.scale);
while(obj) {
var body = obj.GetUserData();
if(body)
{
body.draw(this.context);
}
obj = obj.GetNext();
}
this.context.restore();
}
};
Physics.prototype.click = function(callback) {
var self = this;
function handleClick(e) {
e.preventDefault();
var point = {
x: (e.offsetX || e.layerX) / self.scale,
y: (e.offsetY || e.layerY) / self.scale
};
self.world.QueryPoint(function(fixture) {
callback(fixture.GetBody(),
fixture,
point);
},point);
}
this.element.addEventListener("mousedown",handleClick);
this.element.addEventListener("touchstart",handleClick);
};
Physics.prototype.dragNDrop = function() {
var self = this;
var obj = null;
var joint = null;
function calculateWorldPosition(e) {
return point = {
x: (e.offsetX || e.layerX) / self.scale,
y: (e.offsetY || e.layerY) / self.scale
};
}
this.element.addEventListener("mousedown",function(e) {
e.preventDefault();
var point = calculateWorldPosition(e);
self.world.QueryPoint(function(fixture) {
obj = fixture.GetBody().GetUserData();
},point);
});
this.element.addEventListener("mousemove",function(e) {
if(!obj) { return; }
var point = calculateWorldPosition(e);
if(!joint) {
var jointDefinition = new Box2D.Dynamics.Joints.b2MouseJointDef();
jointDefinition.bodyA = self.world.GetGroundBody();
jointDefinition.bodyB = obj.body;
jointDefinition.target.Set(point.x,point.y);
jointDefinition.maxForce = 100000;
jointDefinition.timeStep = self.stepAmount;
joint = self.world.CreateJoint(jointDefinition);
}
joint.SetTarget(new b2Vec2(point.x,point.y));
});
this.element.addEventListener("mouseup",function(e) {
obj = null;
if(joint) {
self.world.DestroyJoint(joint);
joint = null;
}
});
};
Physics.prototype.collision = function() {
this.listener = new Box2D.Dynamics.b2ContactListener();
this.listener.PostSolve = function(contact,impulse) {
var bodyA = contact.GetFixtureA().GetBody().GetUserData(),
bodyB = contact.GetFixtureB().GetBody().GetUserData();
if(bodyA.contact) { bodyA.contact(contact,impulse,true) }
if(bodyB.contact) { bodyB.contact(contact,impulse,false) }
};
this.world.SetContactListener(this.listener);
};
var Body = window.Body = function(physics,details) {
this.details = details = details || {};
// Create the definition
this.definition = new b2BodyDef();
// Set up the definition
for(var k in this.definitionDefaults) {
this.definition[k] = details[k] || this.definitionDefaults[k];
}
this.definition.position = new b2Vec2(details.x || 0, details.y || 0);
this.definition.linearVelocity = new b2Vec2(details.vx || 0, details.vy || 0);
this.definition.userData = this;
this.definition.type = details.type == "static" ? b2Body.b2_staticBody :
b2Body.b2_dynamicBody;
// Create the Body
this.body = physics.world.CreateBody(this.definition);
// Create the fixture
this.fixtureDef = new b2FixtureDef();
for(var l in this.fixtureDefaults) {
this.fixtureDef[l] = details[l] || this.fixtureDefaults[l];
}
details.shape = details.shape || this.defaults.shape;
switch(details.shape) {
case "circle":
details.radius = details.radius || this.defaults.radius;
this.fixtureDef.shape = new b2CircleShape(details.radius);
break;
case "polygon":
this.fixtureDef.shape = new b2PolygonShape();
this.fixtureDef.shape.SetAsArray(details.points,details.points.length);
break;
case "block":
default:
details.width = details.width || this.defaults.width;
details.height = details.height || this.defaults.height;
this.fixtureDef.shape = new b2PolygonShape();
this.fixtureDef.shape.SetAsBox(details.width/2,
details.height/2);
break;
}
this.body.CreateFixture(this.fixtureDef);
};
Body.prototype.defaults = {
shape: "block",
width: 4,
height: 4,
radius: 1
};
Body.prototype.fixtureDefaults = {
density: 2,
friction: 1,
restitution: 0.2
};
Body.prototype.definitionDefaults = {
active: true,
allowSleep: true,
angle: 0,
angularVelocity: 0,
awake: true,
bullet: false,
fixedRotation: false
};
Body.prototype.draw = function(context) {
var pos = this.body.GetPosition(),
angle = this.body.GetAngle();
context.save();
context.translate(pos.x,pos.y);
context.rotate(angle);
if(this.details.color) {
context.fillStyle = this.details.color;
switch(this.details.shape) {
case "circle":
context.beginPath();
context.arc(0,0,this.details.radius,0,Math.PI*2);
context.fill();
break;
case "polygon":
var points = this.details.points;
context.beginPath();
context.moveTo(points[0].x,points[0].y);
for(var i=1;i<points.length;i++) {
context.lineTo(points[i].x,points[i].y);
}
context.fill();
break;
case "block":
context.fillRect(-this.details.width/2,
-this.details.height/2,
this.details.width,
this.details.height);
default:
break;
}
}
if(this.details.image) {
context.drawImage(this.details.image,
-this.details.width/2,
-this.details.height/2,
this.details.width,
this.details.height);
}
context.restore();
}
var physics,
lastFrame = new Date().getTime();
window.gameLoop = function() {
var tm = new Date().getTime();
requestAnimationFrame(gameLoop);
var dt = (tm - lastFrame) / 1000;
if(dt > 1/15) { dt = 1/15; }
physics.step(dt);
lastFrame = tm;
};
function init() {
var img = new Image();
// Wait for the image to load
img.addEventListener("load", function() {
physics = window.physics = new Physics(document.getElementById("b2dCanvas"));
physics.collision();
// Create some walls
new Body(physics, { color: "red", type: "static", x: 0, y: 0, height: 50, width: 0.5 });
new Body(physics, { color: "red", type: "static", x:51, y: 0, height: 50, width: 0.5});
new Body(physics, { color: "red", type: "static", x: 0, y: 0, height: 0.5, width: 120 });
new Body(physics, { color: "red", type: "static", x: 0, y:25, height: 0.5, width: 120 });
new Body(physics, { image: img, x: 5, y: 8 });
new Body(physics, { image: img, x: 13, y: 8 });
new Body(physics, { color: "blue", x: 8, y: 3 });
new Body(physics, { color: "gray", shape: "circle", radius: 4, x: 5, y: 20 });
new Body(physics, { color: "pink", shape: "polygon",
points: [ { x: 0, y: 0 }, { x: 0, y: 4 },{ x: -10, y: 0 } ],
x: 20, y: 5 });
physics.dragNDrop();
requestAnimationFrame(gameLoop);
});
img.src = "images/bricks.jpg";
}
window.addEventListener("load",init);
}());
// Lastly, add in the `requestAnimationFrame` shim, if necessary. Does nothing
// if `requestAnimationFrame` is already on the `window` object.
(function() {
var lastTime = 0;
var vendors = ['ms', 'moz', 'webkit', 'o'];
for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
window.requestAnimationFrame = window[vendors[x]+'RequestAnimationFrame'];
window.cancelAnimationFrame =
window[vendors[x]+'CancelAnimationFrame'] || window[vendors[x]+'CancelRequestAnimationFrame'];
}
if (!window.requestAnimationFrame) {
window.requestAnimationFrame = function(callback, element) {
var currTime = new Date().getTime();
var timeToCall = Math.max(0, 16 - (currTime - lastTime));
var id = window.setTimeout(function() { callback(currTime + timeToCall); },
timeToCall);
lastTime = currTime + timeToCall;
return id;
};
}
if (!window.cancelAnimationFrame) {
window.cancelAnimationFrame = function(id) {
clearTimeout(id);
};
}
}());
</script>
</body>
</html>
Below is what the code is supposed to produce on the screen. I was wanting to use this one as an example but have not been able to get it to work.
This is how I have the files currently:
<script src='Box2dWeb-2.1.a.3.js'></script>
<script src='example5.js'></script>
You need a file:/// prefix for both of them, e.g. file:///C:\Users\home-1\Desktop\example5.js; I’d just use a relative path, though.
Assuming the file is on your desktop too,
<script src="Box2dWeb-2.1.a.3.js"></script>
<script src="example5.js"></script>
Much more portable.
I am trying to recreate the game http://www.sinuousgame.com/ and started studying html5 canvas and kineticJS.
Recently i came across the getIntersection function and coudnt find much details regarding it.But with what i had ,i did make a code to get the Collision detection done using getIntersection() function.
But it doesnt seem to be working.
As you can see, My Fiddle: http://jsfiddle.net/p9fnq/8/
//The working player code
var LimitedArray = function(upperLimit) {
var storage = [];
// default limit on length if none/invalid supplied;
upperLimit = +upperLimit > 0 ? upperLimit : 100;
this.push = function(item) {
storage.push(item);
if (storage.length > upperLimit) {
storage.shift();
}
return storage.length;
};
this.get = function(flag) {
return storage[flag];
};
this.iterateItems = function(iterator) {
var flag, l = storage.length;
if (typeof iterator !== 'function') {
return;
}
for (flag = 0; flag < l; flag++) {
iterator(storage[flag]);
}
};
};
var tail = new LimitedArray(50);
var flag = 0, jincr = 0;
var stage = new Kinetic.Stage({
container: 'container',
width: window.innerWidth,
height: window.innerHeight,
listening: true
});
var layer = new Kinetic.Layer({
listening: true
});
stage.add(layer);
var player = new Kinetic.Circle({
x: 20,
y: 20,
radius: 6,
fill: 'cyan',
stroke: 'black',
draggable: true
});
var line = new Kinetic.Line({
points: [],
stroke: 'cyan',
strokeWidth: 2,
lineCap: 'round',
lineJoin: 'round'
});
layer.add(line);
layer.add(player);
// move the circle with the mouse
stage.getContent().addEventListener('mousemove', function() {
player.position(stage.getPointerPosition());
var obj = {
x: stage.getPointerPosition().x,
y: stage.getPointerPosition().y
};
tail.push(obj);
var arr = [];
tail.iterateItems(function(p) {
arr.push(p.x, p.y);
});
line.points(arr);
});
var x = 0;
var y = 0;
var noOfEnemies = 200;
var enemyArmada = new Array();
createEnemy();
function createEnemy() {
for (var i = 0; i < noOfEnemies; i++) {
var enemy = new Kinetic.Circle({
x: Math.random() * window.innerWidth,
y: Math.random() * window.innerHeight,
radius: 4.5 + 1.5 * Math.random(),
fill: 'red',
stroke: 'black'
});
enemy.speedX = enemy.speedY = (0.5 + Math.random() * 50);
enemyArmada.push(enemy);
layer.add(enemy);
}
}
var checkCollide = function() {
var position = stage.getPointerPosition();
if(position == null)
position = player.position();
if(position == null)
position = {x:0,y:0};
var collided = stage.getIntersection(position);
console.log(position);
if (typeof collided !== 'Kinetic.Shape') {
console.log("not shape");
}
else {
console.log("BOOOM!!!");
}
};
var anim = new Kinetic.Animation(function(frame) {
checkCollide();
for (var i = 0; i < noOfEnemies; i++) {
var e = enemyArmada[i];
e.position({
x: e.position().x - e.speedX * (frame.timeDiff / 400),
y: e.position().y + e.speedY * (frame.timeDiff / 400)
});
if (e.position().y < 0 || e.position().x < 0) {
e.position({
x: (Math.random() * (window.innerWidth + 600)),
y: -(Math.random() * window.innerHeight)
});
}
}
}, layer);
anim.start();
I need the collision to be detected. The function i have written here is checkCollide and its called within the kinetic.Animation function.
Can anyone help me out with this??
(If you don't know the solution,please do like the post,i need the solution badly)
The source of the problem
getIntersection(point) means "is any object at this point".
Since the point you're using is the player's position, getIntersection will always return true because player is always at its own position !
One solution
Put your player on one layer and all enemies on a separate layer.
That way you can hit test the enemy layer without the interference of the player object.
Code and a Demo: http://jsfiddle.net/m1erickson/JCfW8/
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Prototype</title>
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<script src="http://d3lp1msu2r81bx.cloudfront.net/kjs/js/lib/kinetic-v5.0.1.min.js"></script>
<style>
body{padding:20px;}
#container{
border:solid 1px #ccc;
margin-top: 10px;
width:350px;
height:350px;
}
</style>
<script>
$(function(){
var stage = new Kinetic.Stage({
container: 'container',
width: 350,
height: 350
});
var enemyLayer = new Kinetic.Layer();
stage.add(enemyLayer);
var playerLayer = new Kinetic.Layer();
stage.add(playerLayer);
var player = new Kinetic.Circle({
x:100,
y:100,
radius: 10,
fill: 'green',
draggable: true
});
player.on("dragmove",function(){
if(enemyLayer.getIntersection(player.position())){
this.fill("red");
playerLayer.draw();
}
});
playerLayer.add(player);
playerLayer.draw();
var enemy = new Kinetic.Circle({
x:200,
y:100,
radius: 20,
fill: 'blue',
draggable: true
});
enemyLayer.add(enemy);
enemyLayer.draw();
}); // end $(function(){});
</script>
</head>
<body>
<h4>Drag the green player<br>Player will turn red if it collides<br>with the blue enemy</h4>
<div id="container"></div>
</body>
</html>
Another solution
Mathematically test the player against every enemy:
Warning: untested code--some tweaking might be required
function playerEnemyCollide(){
var playerX=player.x();
var playerY=player.y();
var playerRadius=player.radius();
for(var i=0;i<enemyArmada.length;i++){
var e=enemyArmada[i];
if(circlesColliding(playerX,playerY,playerRadius,e.x,e.y,e.radius)){
return(true);
}
}
return(false);
}
function circlesColliding(cx1,cy1,radius1,cx2,cy2,radius2){
var dx=cx2-cx1;
var dy=cy2-cy1;
return(dx*dx+dy*dy<(radius1*2+radius2*2);
}
I am using HTML 5 for the first time, and playing around with this HTML5 canvas tutorial.
I have changed the example to include 4 images and I want to be able to detect which image was clicked on before doing a redirect on the click event.
Here is my code as it currently is, can somebody tell me how I could detect which image has been clicked in my click event? Also, the mouseout event seems to not always resize the image, any ideas why?
<!DOCTYPE HTML>
<html>
<head>
<style>
body {
margin: 0px;
padding: 0px;
}
#myCanvas {
border: 0px;
}
</style>
<script src="http://www.html5canvastutorials.com/libraries/kinetic2d-v1.0.4.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js" type="text/javascript"></script>
<script>
function initRectangles(rectangles){
// initialize an array of rectangles that provide
// rectangular paths and properties for the images
return [{
name: "buffalo",
image: null,
x: 40,
y: 45,
width: 80,
height: 80,
scale: 1
}, {
name: "indianapolis",
image: null,
x: 125,
y: 45,
width: 80,
height: 80,
scale: 1
}, {
name: "miami",
image: null,
x: 210,
y: 45,
width: 80,
height: 80,
scale: 1
}, {
name: "nyjets",
image: null,
x: 295,
y: 45,
width: 80,
height: 80,
scale: 1
}];
}
function loadImages(sources, callback){
var images = {};
var loadedImages = 0;
var numImages = 0;
for (var src in sources) {
numImages++;
}
for (var src in sources) {
images[src] = new Image();
images[src].onload = function(){
if (++loadedImages >= numImages) {
callback(images);
}
};
images[src].src = sources[src];
}
}
function mapImages(rectangles, images){
// map images to rectangles
var counter = 0;
for (var img in images) {
rectangles[counter++].image = images[img];
}
}
function initStage(images){
var rectangles = initRectangles(rectangles);
mapImages(rectangles, images);
kin = new Kinetic_2d("myCanvas");
var context = kin.getContext();
kin.setDrawStage(function () {
this.clear();
var mousePos = kin.getMousePos();
for (var n = 0; n < rectangles.length; n++) {
var rect = rectangles[n];
context.save();
context.translate(rect.x, rect.y);
context.scale(rect.scale, rect.scale);
kin.beginRegion();
var rectX = -1 * rect.width / 2;
var rectY = -1 * rect.height / 2;
context.drawImage(rect.image, rectX, rectY, rect.width, rect.height);
context.beginPath();
context.rect(rectX, rectY, rect.width, rect.height);
context.closePath();
this.addRegionEventListener("mouseover", function () {
document.body.style.cursor = "pointer";
rectangles[n].scale = 1.07;
});
this.addRegionEventListener("mouseout", function () {
document.body.style.cursor = "default";
rectangles[n].scale = 1;
});
this.closeRegion();
context.restore();
}
});
}
window.onload = function(){
var sources = {
buffalo: "buffalo.png",
indianapolis: "indianapolis.png",
miami: "miami.png",
nyjets: "nyjets.png"
};
loadImages(sources, initStage);
$("#myCanvas").click(function (e) {
});
};
</script>
</head>
<body>
<canvas id="myCanvas" width="400" height="90">
</canvas>
</body>
</html>
Try using event mouseup:
this.addRegionEventListener("mouseup", function() {
alert("mouse up");
});