Pixijs attach element to another - javascript

I'm developing a tool to add various sprites to the stage. When I drag an element I'd like to display o bounding box ( a rectangle ) that need to move accordingly to the dragging item.
To handle the drag functionality I'm using a lib called draggable
This is the constructor of every single object I push on the stage:
function createElement(x, y, ass_id)
{
// create our little bunny friend..
bunny = new PIXI.Sprite(textures[ass_id]);
bunny.scale.x = bunny.scale.y = 0.2;
bunny.draggable({
snap: true,
snapTolerance:0,
grid: [ 50, 50 ],
alpha: 0.5,
mousedown: function(data) {
/*var fishBounds = new PIXI.Rectangle(
-fishBoundsPadding,
-fishBoundsPadding,
viewWidth + fishBoundsPadding * 2,
viewHeight + fishBoundsPadding * 2);*/
texture_w = (data.target.texture.width) * data.target.scale.x;
texture_h = (data.target.texture.height) * data.target.scale.y;
// scale = data.target.scale.x;
var box = new PIXI.Graphics();
box.lineStyle(2, 0x666666);
box.drawRect(data.target.position.x, data.target.position.y, texture_w, texture_h);
box.scale.x = box.scale.y = scale;
stage.addChild(box);
data.target.boundingBox = box;
console.log(data.target.boundingBox.position, data.target.position);
},
drag: function(data) {
offset_x = data.boundingBox.position.x;//data.position;
offset_y = data.boundingBox.position.y;
data.boundingBox.position.x = data.position.x;// * data.scale.x;// - offset_x;
data.boundingBox.position.y = data.position.y;// * data.scale.y;// - offset_y;
console.log(stage.children.length , data.boundingBox.position, data.position, data);
},
mouseup: function(data) {
console.log("drop");
stage.removeChild(data.target.boundingBox);
}
});
// move the sprite to its designated position
bunny.position.x = x;
bunny.position.y = y;
elements.push(bunny);
// add it to the stage
stage.addChild(elements[elements.length-1]);
}
now, this works like a charm: when I click the element a bounding box gets created in the correct location, the problem is that when I start drag it around the bounding box get away from the item. I thing that the reason for this might be due to the fact the one item is scaled, wether the other isn't, but since I'm a noob at pixi I really find myself stuck with it.

Ok, I discovered that you can easily and conveniently attach an object to another via the addChild, so it comes out like this:
function createElement(x, y, ass_id)
{
// create our little bunny friend..
bunny = new PIXI.Sprite(textures[ass_id]);
bunny.scale.x = bunny.scale.y = 0.2;
bunny.draggable({
snap: true,
snapTolerance:0,
grid: [ 50, 50 ],
alpha: 0.5,
mousedown: function(data) {
texture_w = (data.target.texture.width);
texture_h = (data.target.texture.height);
var box = new PIXI.Graphics();
box.lineStyle(5, 0x666666);
box.drawRect(0, 0, texture_w, texture_h);
data.target.type = "element";
data.target.addChild(box);
},
drag: function(data) {
},
mouseup: function(data) {
console.log("drop");
for (var i = stage.children.length - 1; i >= 0; i--) {
if((stage.children[i].type) && (stage.children[i].type == "element"))
for (var j = stage.children[i].length - 1; i >= 0; i--) {
console.log('remove boundingBox child here when needed');
}
};
}
});
// move the sprite to its designated position
bunny.position.x = x;
bunny.position.y = y;
elements.push(bunny);
// add it to the stage
stage.addChild(elements[elements.length-1]);
}

Related

How to collide a player with walls?

I'm trying to create a top down shooter game and I am using Tiled to create my map. I've made my map and exported it as a .json file. I was finally able to make the map appear in my game, but I am having a hard time making the collision work.
I've been going through tutorials for hours and seem to have tried everything under the sun with no luck. I have an object layer in Tiled with the walls marked with the insert rectangle tool. I have every wall tile also marked with insert rectangle in the edit tileset menu. But I still cant get it to work. Walls are Tile Layer 1, ground is Tile Layer 2, object layer is called collision and the tile set name is tiles 48x48. Here's all my relevant code:
var game = new Phaser.Game(1440, 960, Phaser.man, 'phaser-example', { preload: preload, create: create, update: update, render: render });
var sprite
//sounds
var music
//movement
var controls
var cursors
//shooting
var fireRate = 200;
var nextFire = 0;
var Bullets
//map
var map
var walls
var ground
//var collision
function preload() {
game.load.audio('groove', ['sewer groove.mp3']);
game.load.audio('gunshot', 'pistol.mp3');
game.load.image('player', 'player lite.png');
game.load.image('bullet', 'bullet.png');
game.load.tilemap('map', 'sewermap.json', null, Phaser.Tilemap.TILED_JSON);
game.load.image('tiles 48x48','tiles 48x48.png')
}
function create() {
map = game.add.tilemap('map');
map.addTilesetImage('tiles 48x48');
//var tileset = map.addTilesetImage('map','tiles 48x48');
//map.physics.arcade.enable(sprite, Phaser.Physics.ARCADE);
ground = map.createLayer('Tile Layer 2');
walls = map.createLayer('Tile Layer 1');
//collision = map.createLayer('Object Layer 1')
map.setCollisionBetween(0, 65, true, 'Tile Layer 1');
//sprite.body.collideWorldbounds = true;
//layer.resizeWorld();
music = game.add.audio('groove',1,true);
music.play();
game.physics.startSystem(Phaser.Physics.ARCADE);
//game.physics.startSystem(Phaser.Physics.P2JS)
game.stage.backgroundColor = '#313131';
bullets = game.add.group();
bullets.enableBody = true;
bullets.physicsBodyType = Phaser.Physics.ARCADE;
bullets.createMultiple(50, 'bullet');
bullets.setAll('checkWorldBounds', true);
bullets.setAll('outOfBoundsKill', true);
sprite = game.add.sprite(620, 920, 'player');
sprite.anchor.set(0.5, 0.5);
//game.physics.p2.enable(sprite)
game.physics.arcade.enable(sprite, Phaser.Physics.ARCADE);
sprite.body.allowRotation = true;
cursors = game.input.keyboard.createCursorKeys();
}
function update() {
game.physics.arcade.collider(sprite, walls);
//console.log(sprite.rotation);
sprite.rotation = game.physics.arcade.angleToPointer(sprite);
if (game.input.activePointer.isDown)
{
fire();
}
//sprite.body.setZeroVelocity();
if (game.input.keyboard.isDown(Phaser.Keyboard.LEFT))
{
sprite.x -= 4;
}
else if (game.input.keyboard.isDown(Phaser.Keyboard.RIGHT))
{
sprite.x += 4;
}
if (game.input.keyboard.isDown(Phaser.Keyboard.UP))
{
sprite.y -= 4;
}
else if (game.input.keyboard.isDown(Phaser.Keyboard.DOWN))
{
sprite.y += 4;
}
}
function fire() {
if (game.time.now > nextFire && bullets.countDead() > 0)
{
nextFire = game.time.now + fireRate;
var bullet = bullets.getFirstDead();
bullet.reset(sprite.x - 8, sprite.y - 8);
game.physics.arcade.moveToPointer(bullet, 300);
}
}
function render() {
game.debug.text('Active Bullets: ' + bullets.countLiving() + ' / ' + bullets.total, 32, 32);
game.debug.spriteInfo(sprite, 32, 450);
//game.debug.spriteBounds(sprite);
//game.debug.spriteBounds(bullets);
//game.debug.body(sprite);
}
Alright, I've had the chance to take a look at this, the issue should solely lie in how you're moving the main player:
sprite.x -= 4;
Collisions only fire if the body has a velocity, the following table by samme should sum it up
You can apply acceleration, for the sake of example, to move the character towards the direction you're pointing at:
if (game.input.keyboard.isDown(Phaser.Keyboard.UP) || game.input.keyboard.isDown(Phaser.Keyboard.W)) {
game.physics.arcade.accelerationFromRotation(sprite.rotation, 200, sprite.body.acceleration);
}
In the image I'm also applying a certain drag and reducing acceleration when nothing is pressed but that's your call:
sprite.body.drag.x = 200;
sprite.body.drag.y = 200;
If you wanted to strafe an idea could be at dealing with multiple presses and applying a different accelerationFromRotation accordingly (with a variety of degrees converted with Phaser.Math.degToRad)
For debug's sake, if needed, you might want to use some of the following:
[...]
walls = map.createLayer("Tile Layer 1");
walls.debug = true;
[...]
function collisionHandler(obj1, obj2) {
console.log("Colliding!", obj1, obj2)
}
game.physics.arcade.collide(sprite, walls, collisionHandler, null, this);
game.debug.body(sprite);

Paint text on the mouse hover on the graphics in the position of cursor

I have a problem when I go to paint the PIXI.Text in the cursor position.
This is the simple demo to reproduce the problem, when you go over the node with the cursor I paint the text, in this case, "#author vincenzopalazzo" but I want the position on the node, so I think for resolving the problem I have got the solution I must set the position of the mouse.
But I don't have an idea got get this position, so this is an example to reproduce the problem with PIXI
//setup Pixi renderer
var renderer = PIXI.autoDetectRenderer(600, 400, {
backgroundColor: 0x000000
});
document.body.appendChild(renderer.view);
// create new stage
var stage = new PIXI.Container();
// create helpful message
var style = {
font: '18px Courier, monospace',
fill: '#ffffff'
};
// create graphic object called circle then draw a circle on it
var circle = new PIXI.Graphics();
circle.lineStyle(5, 0xFFFFFF, 1);
circle.beginFill(0x0000FF, 1);
circle.drawCircle(150, 150, 100);
circle.endFill();
circle.alpha = 0.5;
stage.addChild(circle);
// designate circle as being interactive so it handles events
circle.interactive = true;
// create hit area, needed for interactivity
circle.hitArea = new PIXI.Circle(150, 150, 100);
// make circle non-transparent when mouse is over it
circle.mouseover = function(events) {
var message = new PIXI.Text('Hover your mouse over the circle to see the effect.', style);
message.x = events.clientX;
message.y = events.clientY;
circle.message = message;
circle.addChild(message);
}
// make circle half-transparent when mouse leaves
circle.mouseout = function(mouseData) {
this.alpha = 0.5;
circle.removeChild(circle.message);
delete circle.message;
}
// start animating
animate();
function animate() {
requestAnimationFrame(animate);
// render the root container
renderer.render(stage);
};
<script src="https://cdnjs.cloudflare.com/ajax/libs/pixi.js/5.1.4/pixi.js"></script>
This is my real code
module.exports = function (animatedNode, ctx) {
ctx.on('hover', function(animatedNode, ctx){
let x = animatedNode.pos.x;
let y = - animatedNode.pos.y / 2;
if(animatedNode.label === undefined){
animatedNode.label = new PIXI.Text('#author vincenzopalazzo', { fontFamily: "Arial", fontSize: "20px" , fill: 0x000000} );
animatedNode.label.x = x;
animatedNode.label.y = y + animatedNode.width/2;
ctx.addChild(animatedNode.label);
}else{
animatedNode.label.x = x;
animatedNode.label.y = y + animatedNode.width/2;
}
});
ctx.on('unhover', function(animatedNode, ctx){
ctx.removeChild(animatedNode.label);
delete animatedNode.label;
});
ctx.mouseover = function() {
console.debug('I\'call the hover events');
this.fire('hover', animatedNode, ctx);
}
ctx.mouseout = function() {
console.debug('I\'call the unhover events');
this.fire('unhover', animatedNode, ctx);
}
}
I'm using the ngraph.events on the ctx (it is the PIXI graphics) object, the method on and fire is the module nghraph.events
In your example code (first snippet) the "moseover" handler should be changed from:
// make circle non-transparent when mouse is over it
circle.mouseover = function(events) {
var message = new PIXI.Text('Hover your mouse over the circle to see the effect.', style);
message.x = events.clientX;
message.y = events.clientY;
circle.message = message;
circle.addChild(message);
}
to:
// make circle non-transparent when mouse is over it
circle.on('mouseover', function(event) {
// console.log('mouse is over the circle');
// console.log(event); // see in (for example in Chrome Devtools console) what is inside this variable
var message = new PIXI.Text('Hover your mouse over the circle to see the effect.', style);
// By looking at what "console.log(event)" shows we can see that instead of:
// message.x = events.clientX;
// message.y = events.clientY;
// should be:
message.x = event.data.global.x;
message.y = event.data.global.y;
circle.message = message;
circle.addChild(message);
});
To understand it more you can uncomment the "console.log" lines to observe it in your browser devtools console.
Then we also need to handle 'mouseover' event like this:
circle.on('mousemove',function (event) {
if (!circle.message) {
return;
}
var newPosition = event.data.getLocalPosition(this.parent);
circle.message.x = newPosition.x;
circle.message.y = newPosition.y;
});
so whole runnable example will be like this:
//setup Pixi renderer
var renderer = PIXI.autoDetectRenderer(600, 400, {
backgroundColor: 0x000000
});
document.body.appendChild(renderer.view);
// create new stage
var stage = new PIXI.Container();
// create helpful message
var style = {
font: '18px Courier, monospace',
fill: '#ffffff'
};
// create graphic object called circle then draw a circle on it
var circle = new PIXI.Graphics();
circle.lineStyle(5, 0xFFFFFF, 1);
circle.beginFill(0x0000FF, 1);
circle.drawCircle(150, 150, 100);
circle.endFill();
circle.alpha = 0.5;
stage.addChild(circle);
// designate circle as being interactive so it handles events
circle.interactive = true;
// create hit area, needed for interactivity
circle.hitArea = new PIXI.Circle(150, 150, 100);
// make circle non-transparent when mouse is over it
circle.on('mouseover', function(event) {
// console.log('mouse is over the circle');
// console.log(event); // see in (for example in Chrome Devtools console) what is inside this variable
var message = new PIXI.Text('Hover your mouse over the circle to see the effect.', style);
// By looking at what "console.log(event)" shows we can see that instead of:
// message.x = events.clientX;
// message.y = events.clientY;
// should be:
message.x = event.data.global.x;
message.y = event.data.global.y;
circle.message = message;
circle.addChild(message);
});
circle.on('mousemove',function (event) {
if (!circle.message) {
return;
}
var newPosition = event.data.getLocalPosition(this.parent);
circle.message.x = newPosition.x;
circle.message.y = newPosition.y;
});
// make circle half-transparent when mouse leaves
circle.mouseout = function(mouseData) {
this.alpha = 0.5;
circle.removeChild(circle.message);
delete circle.message;
}
// start animating
animate();
function animate() {
requestAnimationFrame(animate);
// render the root container
renderer.render(stage);
};
<script src="https://cdnjs.cloudflare.com/ajax/libs/pixi.js/5.1.4/pixi.js"></script>
Please also see:
"Interaction/Dragging" Pixi.js demo (with source code): https://pixijs.io/examples/#/interaction/dragging.js
tutorial "Rotate towards mouse and shoot in that direction" by Igor Neuhold : http://proclive.io/shooting-tutorial/
Pixi.js API reference:
https://pixijs.download/dev/docs/PIXI.DisplayObject.html#event:mousemove
https://pixijs.download/dev/docs/PIXI.interaction.InteractionEvent.html
https://pixijs.download/dev/docs/PIXI.interaction.InteractionData.html

unlimited stack of tile(object/sprite) in que after dragging the first to toppest one in phaser

i am making a game using phaser and i want to make unlimited no of tiles can think like stacked tiles. When the user drags the topmost tile and places it in the drop area, the same tile below it should appear and should be draggable.
My present code:- `
var greenTile = this.add.sprite(250,500,'greenTile');
greenTile.inputEnabled=true;
greenTile.input.enableDrag();
greenTile.events.onDragStart.add(onDragStart, this);
greenTile.events.onDragStop.add(onDragStop, this);`
the total code is of my game state is :-
`
var patternsRatio = patternsRatio || {};
var x = 50;
var y = 100;
var canvas;
var canvasBG;
var canvasGrid;
var canvasSprite;
var canvasZoom = 32;
var spriteWidth = 8;
var spriteHeight = 8;
patternsRatio.game1 = function () {};
patternsRatio.game1.prototype = {
preload: function () {
this.load.image('greenTile','assets/images/greentile.png')
this.load.image('redTile','assets/images/redtile.png')
},
create: function () {
this.game.stage.setBackgroundColor(0x2d2d2d);
var question_l1 = "Puzzle 1: Enlarge this pattern by a factor of 2."
var style_l1 = {font: "25px Comic Sans MS Bold", fill: "#fff", align:"center"};
var quet_l1=this.game.add.text(this.game.world.centerX,this.game.height-600, question_l1, style_l1)
quet_l1.anchor.setTo(0.5)
this.placetiles()
var greenTile = this.add.sprite(250,500,'greenTile');
greenTile.inputEnabled=true;
greenTile.input.enableDrag();
greenTile.events.onDragStart.add(onDragStart, this);
greenTile.events.onDragStop.add(onDragStop, this);
var redTile = this.add.sprite(100,500,'redTile');
redTile.inputEnabled=true;
redTile.input.enableDrag();
redTile.events.onDragStart.add(onDragStart, this);
redTile.events.onDragStop.add(onDragStop, this);
},
update: function () {
},
placetiles: function () {
this.game.create.grid('drawingGrid', 16 * canvasZoom, 16 * canvasZoom, canvasZoom, canvasZoom, 'rgba(0,191,243,0.8)');
canvas = this.game.make.bitmapData(spriteWidth * canvasZoom, spriteHeight * canvasZoom);
canvasBG = this.game.make.bitmapData(canvas.width + 2, canvas.height + 2);
canvasBG.rect(0, 0, canvasBG.width, canvasBG.height, '#fff');
canvasBG.rect(1, 1, canvasBG.width - 2, canvasBG.height - 2, '#3f5c67');
var x = 80;
var y = 64;
canvasBG.addToWorld(x, y);
canvasSprite = canvas.addToWorld( x + 1, y + 1); canvasZoom,canvasZoom
canvasGrid = this.game.add.sprite(x + 1, y + 1, 'drawingGrid');
canvasGrid.crop(new Phaser.Rectangle(0, 0, spriteWidth * canvasZoom, spriteHeight * canvasZoom));
}
};
`
I am also facing problem when i am adding a input.enable code below the "greenTile" variable then the redTile vanishes of can any tell why this happens.
In the image below as we can see both red and green tile are appearing.
In this image as we can i had added input enable and the red Tile stopped appearing, Secondly as have dragged the green tile to the grid, i want on the original place their should be again the greenTile should come.(this is in reference to the stack able unlimited tile question)
I could figure this out by just adding a function and calling it on the drag start event as below:-
The function that i added is :-
addGreenTiles: function(){
this.greenTile1 = this.add.sprite(250,500,'greenTile');
this.greenTile1.inputEnabled=true;
this.greenTile1.input.enableSnap(canvasZoom, canvasZoom, false, true);
this.greenTile1.input.enableDrag();
this.greenTile1.originalPosition = this.greenTile1.position.clone();
this.greenTile1.events.onDragStart.add(this.addGreenTiles, this);
this.greenTile1.events.onDragStop.add(function(currentSprite){
this.stopDrag(currentSprite, this.greenTile1);
}, this);
Then i called this function at :
this.greenTile1.events.onDragStart.add(this.addGreenTiles, this);

Cocos2D-JS Chipmunk PhysicsSprite Move action not working in Android phone

I am trying to develop a simple cross-platform game, and trying to move a PhysicsSprite with a Body to the position I touched/clicked, using Cocos2D-JS.
Here is the code that I have:
var TAG_SPRITE = 1;
var AnimationLayer = cc.Layer.extend({
space:null,
ctor:function (space) {
this._super();
this.space = space;
this.init();
},
init:function () {
this._super();
var winsize = cc.director.getWinSize();
//init physics sprite
var spriteHead = new cc.PhysicsSprite(res.Head_png);
var headContentSize = spriteHead.getContentSize();
//init body
var headBody = new cp.Body(1, cp.momentForBox(1, headContentSize.width, headContentSize.height));
headBody.p = cc.p(winsize.width / 2, winsize.height / 3);
this.space.addBody(headBody);
//init shape
var headShape = new cp.CircleShape(headBody, headContentSize.width / 2, cp.v(0, 0));
headShape.setFriction(0.3);
headShape.setElasticity(0.8);
this.space.addShape(headShape);
spriteHead.setBody(headBody);
this.addChild(spriteHead, 0, TAG_SPRITE);
//for mobile
if('touches' in cc.sys.capabilities ){
cc.eventManager.addListener({
event: cc.EventListener.TOUCH_ONE_BY_ONE,
swallowTouches: true,
onTouchBegan:function (touch, event) {
cc.log('touch began');
event.getCurrentTarget().moveSprite(touch.getLocation());
return true;
},
onTouchMoved: function (touch, event) {
},
onTouchEnded: function (touch, event) {
},
onTouchCancelled: function (touch, event) {
}
}, this);
}
//for desktop
else if ('mouse' in cc.sys.capabilities ) {
cc.eventManager.addListener({
event: cc.EventListener.MOUSE,
onMouseUp: function (event) {
event.getCurrentTarget().moveSprite(event.getLocation());
}
}, this);
}
},
moveSprite:function(position) {
cc.log('move to: ' + position.x + ',' + position.y);
var sprite = this.getChildByTag(TAG_SPRITE);
var moveAction = new cc.moveTo(1, position);
sprite.runAction(moveAction);
}
});
As I see the logs from the logcat, it can handle touch events but cannot move the sprite. When I convert the PhysicsSprite to just Sprite object and remove all other Body and Shape stuff, it can be moved to the location that I touch.
The problem is that I can move the PhysicsSprite in the browser whereas I cannot do that in my Android phone.
Note: I use Chipmunk physics engine
I don't know this is the real solution or should be considered as a workaround but the code below works fine for both web and Android. But still don't know why the code in the question doesn't work for Android while it does for the web. (It would make more sense if it didn't work for both...)
I tried to move body of the sprite instead of itself. The new moveSprite method is like that:
moveSprite: function(sprite){
cc.log('move to: ' + position.x + ',' + position.y);
var sprite = this.getChildByTag(TAG_SPRITE);
var body = sprite.getBody();
var velocity = 300;
this.moveWithVelocity(body, position, velocitiy);
}
moveWithVelocity is the custom function that I created in the same Layer, moving the Body to the destination point with a particular velocity:
moveWithVelocity: function(body, destination, velocity){
var deltaX = destination.x - body.p.x;
var deltaY = destination.y - body.p.y;
var distance = Math.sqrt(Math.pow(deltaX,2) + Math.pow(deltaY,2));
var time = distance / velocity;
var velocityX = deltaX / time;
var velocityY = deltaY / time;
//start the action with the calculated velocity in the calculated direction
body.applyImpulse(cc.v(velocityX, velocityY), cc.v(0,0));
//stop the sprite (or body here) when duration of movement is time out (or when the sprite/body arrives its destination)
setTimeout(function(){
body.setVel(cc.v(0,0));
}, time*1000);
}
Hope this helps anyone encountered the same problem.

drawImage with Canvas is sending image to the back of the canvas [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 8 years ago.
Improve this question
I have been doing a little experimenting with canvas, creating drawings using lines shapes text etc, and inserting .png files. The inserting .png files is the bit that I cannot get to work.
Edit:
Undesired behaviour of this code: I load shapes to the graphics context, then load an image file to the graphics context, however when the graphics context is drawn, the image is at behind the shapes, despite being drawn last.
I wanted the image file to be at the top, in front of the shapes.
Desired behaviour: To bring image file to the front of the canvas, so it is not hidden by shapes drawn in the graphics context.
function loadImage(name) {
images[name] = new Image();
images[name].src = "DogWalking/" + name + ".png";
images[name].onload = function() {
graphics.drawImage(this, 0, 300);
canvas.bringToFront(this);
};
}
the function for drawing is called here:
function draw() {
graphics.save(); // to make sure changes don't carry over from one call to the next
graphics.fillStyle = "transparent"; // background color
graphics.fillRect(0,0,wWidth, wHeight);
graphics.fillStyle = "black";
applyLimits(graphics,xleft,xright,ytop,ybottom,true);
graphics.lineWidth = pixelSize;
world.draw(graphics);
graphics.drawImage(images["dog-walking11"],200,200);
graphics.restore();
}
code for the whole page is
<!DOCTYPE html>
<html>
<meta charset="UTF-8">
<head>
<title>Hierarchical Modeling 2D</title>
<style>
#messagediv {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
z-index: 0;
background-color: indigo;
}
#canvasdiv {
position: absolute;
left: 0;
top: 0;
z-index: 10;
background-color: transparent;
}
</style>
<script type="text/javascript" src="rgbcolor.js"></script>
<script type="text/javascript">
"use strict";
var totalResources = 17;
var numResourcesLoaded = 0;
var images = {};
function loadImage(name) {
images[name] = new Image();
images[name].src = "DogWalking/" + name + ".png";
images[name].onload = function() {
//
graphics.drawImage(this, 0, 300);
canvas.bringToFront(this);
}
}
var canvas; // DOM object corresponding to the canvas
var graphics; // 2D graphics context for drawing on the canvas
var ctx; // 2D graphics context for drawing on the canvas
var myNumber = 0, myNumber2 = 0, myInterval, myInterval2, myelement, thisdiv, printx;
var mycoords = new Array();
var pcoords = new Array(); //coordinates of the portal.
//var pcoords = [[0,0], [50,300], [250,150]]; //coordinates of the portal.
var nocoords = 2;
var frameNumber = 0; // Current frame number.
var frameNumber2 = 0;
var sun;
var sun2;
var ground;
var world;
var pixelSize;
var wWidth;
var wHeight;
var portals = new Array("calendar1","alternativsearch","art1", "directory1");
var portalsval = new Array();
var portalsobj;
var leftj = new Array(3,1,4,2);
var forwards = "http://www.alternativworld.com";
// ---------------- Set Page Layout ----------------
// function to set size of canvas and location of portals
function pageLayout() {
var w = window, d = document, e = d.documentElement, g = d.getElementsByTagName('body')[0];
wWidth = w.innerWidth || e.clientWidth || g.clientWidth;
wHeight = w.innerHeight|| e.clientHeight|| g.clientHeight;
// Adjust wWidth and wHeight if ratio does not match scenary 7 by 5.
if (wWidth/wHeight != 7/5)
if (wWidth/wHeight > 7/5) {
var widthPortion = 5 * wWidth/wHeight;
wWidth = wWidth * 7 / widthPortion;
} else {
var heightPortion = 7 * wHeight/wWidth;
wHeight = wHeight * 5 / heightPortion;
}
var widthheight, localerror = false;
widthheight = Math.min(wWidth, wHeight);
if(widthheight < 400){
var localerror = true;
}
if (localerror == true)
alert("Warning, the page size of your browser or your screen resolution may be too small to correctly view this web page.");
var theCanvas = d.getElementById("theCanvas");
theCanvas.height = wHeight;
theCanvas.width = wWidth;
}
//Function to listen to the mouse events and see if a link is selected.
function doMouseDown(evt) {
var r = canvas.getBoundingClientRect();
var x = Math.round(evt.clientX - r.left);
var y = Math.round(evt.clientY - r.top);
alert(evt.clientX+ " " + evt.clientY);
for (var i = portals.length+1; i >= 0; i--) {
var p = pcoords[i];
if (Math.abs(p[0] - x) <= 50 && Math.abs(p[1] - y) <= 50) {
document.location.href = forwards;
return;
} else if (Math.abs(0 - x) <= 50 && Math.abs(0 - y) <= 50){
document.location.href = "http://www.alternativeuk.co.uk";
return;
}
}
}
// ---------------- The object-oriented scene graph API ------------------
/**
* The base class for all nodes in the scene graph data structure.
*/
function SceneGraphNode() {
this.fillColor = null; // If non-null, the default fillStyle for this node.
this.strokeColor = null; // If non-null, the default strokeStyle for this node.
}
SceneGraphNode.prototype.doDraw = function(g) {
// This method is meant to be abstract and must be
// OVERRIDDEN in any actual object in the scene graph.
// It is not meant to be called; it is called by draw().
throw "doDraw not implemented in SceneGraphNode"
}
SceneGraphNode.prototype.draw = function(g) {
// This method should be CALLED to draw the object
// represented by this SceneGraphNode. It should NOT
// ordinarily be overridden in subclasses.
graphics.save();
if (this.fillColor) {
g.fillStyle = this.fillColor;
}
if (this.strokeColor) {
g.strokeStyle = this.strokeColor;
}
this.doDraw(g);
graphics.restore();
}
SceneGraphNode.prototype.setFillColor = function(color) {
// Sets fillColor for this node to color.
// Color should be a legal CSS color string, or null.
this.fillColor = color;
return this;
}
SceneGraphNode.prototype.setStrokeColor = function(color) {
// Sets strokeColor for this node to color.
// Color should be a legal CSS color string, or null.
this.strokeColor = color;
return this;
}
SceneGraphNode.prototype.setColor = function(color) {
// Sets both the fillColor and strokeColor to color.
// Color should be a legal CSS color string, or null.
this.fillColor = color;
this.strokeColor = color;
return this;
}
/**
* Defines a subclass, CompoundObject, of SceneGraphNode to represent
* an object that is made up of sub-objects. Initially, there are no
* sub-objects.
*/
function CompoundObject() {
SceneGraphNode.call(this); // do superclass initialization
this.subobjects = []; // the list of sub-objects of this object
}
CompoundObject.prototype = new SceneGraphNode(); // (makes it a subclass!)
CompoundObject.prototype.add = function(node) {
// Add node a subobject of this object. Note that the
// return value is a reference to this node, to allow chaining
// of method calls.
this.subobjects.push(node);
return this;
}
CompoundObject.prototype.doDraw = function(g) {
// Just call the sub-objects' draw() methods.
for (var i = 0; i < this.subobjects.length; i++)
this.subobjects[i].draw(g);
}
/**
* Define a subclass, TransformedObject, of SceneGraphNode that
* represents an object along with a modeling transformation to
* be applied to that object. The object must be specified in
* the constructor. The transformation is specified by calling
* the setScale(), setRotate() and setTranslate() methods. Note that
* each of these methods returns a reference to the TransformedObject
* as its return value, to allow for chaining of method calls.
* The modeling transformations are always applied to the object
* in the order scale, then rotate, then translate.
*/
function TransformedObject(object) {
SceneGraphNode.call(this); // do superclass initialization
this.object = object;
this.rotationInDegrees = 0;
this.scaleX = 1;
this.scaleY = 1;
this.translateX = 0;
this.translateY = 0;
}
TransformedObject.prototype = new SceneGraphNode(); // (makes it a subclass!)
TransformedObject.prototype.setRotation = function(angle) {
// Set the angle of rotation, measured in DEGREES. The rotation
// is always about the origin.
this.rotationInDegrees = angle;
return this;
}
TransformedObject.prototype.setScale = function(sx, sy) {
// Sets scaling factors.
this.scaleX = sx;
this.scaleY = sy;
return this;
}
TransformedObject.prototype.setTranslation = function(dx,dy) {
// Set translation mounts.
this.translateX = dx;
this.translateY = dy;
return this;
}
TransformedObject.prototype.doDraw = function(g) {
// Draws the object, with its modeling transformation.
g.save();
if (this.translateX != 0 || this.translateY != 0) {
g.translate(this.translateX, this.translateY);
}
if (this.rotationInDegrees != 0) {
g.rotate(this.rotationInDegrees/180*Math.PI);
}
if (this.scaleX != 1 || this.scaleY != 1) {
g.scale(this.scaleX, this.scaleY);
}
this.object.draw(g);
g.restore();
}
/**
* A subclass of SceneGraphNode representing filled triangles.
* The constructor specifies the vertices of the triangle:
* (x1,y1), (x2,y2), and (x3,y3).
*/
function Triangle(x1,y1,x2,y2,x3,y3) {
SceneGraphNode.call(this);
this.x1 = x1;
this.y1 = y1;
this.x2 = x2;
this.y2 = y2;
this.x3 = x3;
this.y3 = y3;
}
Triangle.prototype = new SceneGraphNode();
Triangle.prototype.doDraw = function(g) {
g.beginPath();
g.moveTo(this.x1,this.y1);
g.lineTo(this.x2,this.y2);
g.lineTo(this.x3,this.y3);
g.closePath();
g.fill();
}
/**
* Directly create a line object as a SceneGraphNode with a
* custom doDraw() method. line is of length 1 and
* extends along the x-axis from (0,0) to (1,0).
*/
var line = new SceneGraphNode();
line.doDraw = function(g) {
g.beginPath();
g.moveTo(0,0);
g.lineTo(1,0);
g.stroke();
}
/**
* Directly create a filled rectangle object as a SceneGraphNode with a
* custom doDraw() method. filledRect is a square with side 1, centered
* at (0,0), with corners at (-0.5,-0.5) and (0.5,0.5).
*/
var filledRect = new SceneGraphNode();
filledRect.doDraw = function(g) {
g.fillRect(-0.5,-0.5,1,1);
}
/**
* Directly create a rectangle object as a SceneGraphNode with a
* custom doDraw() method. rect is a square with side 1, centered
* at (0,0), with corners at (-0.5,-0.5) and (0.5,0.5). Only the
* outline of the square is drawn.
*/
var rect = new SceneGraphNode();
rect.doDraw = function(g) {
g.strokeRect(-0.5,-0.5,1,1);
}
/**
* Directly create a filled circle object as a SceneGraphNode with a
* custom doDraw() method. filledCircle is a circle with radius 0.5
* (diameter 1), centered at (0,0).
*/
var filledCircle = new SceneGraphNode();
filledCircle.doDraw = function(g) {
g.beginPath();
g.arc(0,0,0.5,0,2*Math.PI);
g.fill();
}
var clickHere = new SceneGraphNode();
clickHere.doDraw = function(g) {
g.fillText("click here :)",0,0)
}
/**
* Directly create a circle object as a SceneGraphNode with a
* custom doDraw() method. filledCircle is a circle with radius 0.5
* (diameter 1), centered at (0,0). Only the outline of the circle
* is drawn.
*/
var circle = new SceneGraphNode();
circle.doDraw = function(g) {
g.beginPath();
g.arc(0,0,0.5,0,2*Math.PI);
g.stroke();
}
var dog = new SceneGraphNode();
dog.doDraw = function(g) {
g.drawImage(images["dog-walking11"],-2, 2);
alert(images["dog-walking11"].name);
}
// -------------------- Specific to this application ----------------------------
/*
* Define two extra basic objects as SceneGraphNodes with custom doDraw() methods.
* One represents the ground, the other a vane for a windmill.
*/
var ground = new SceneGraphNode();
ground.doDraw = function(g) {
g.beginPath();
g.moveTo(0,-1);
g.lineTo(0,0.8);
g.lineTo(1.5,1.65);
g.lineTo(1.8,1.3);
g.lineTo(3,2.1);
g.lineTo(4.7,0.7);
g.lineTo(6.1,1.2);
g.lineTo(7,0.8);
g.lineTo(7,-1);
g.closePath();
g.fill();
}
var windmillVane = new SceneGraphNode();
windmillVane.doDraw = function(g) {
g.beginPath();
g.moveTo(0,0);
g.lineTo(0.5,0.1);
g.lineTo(1.5,0);
g.lineTo(0.5,-0.1);
g.closePath();
g.fill();
}
var world; // A SceneGraphNode representing the entire picture. This should
// be created in the createWorld() method.
var pixelSize; // The size of one pixel, in the transformed coordinates.
// This is used as the default width of a stroke.
var background = "#C8C8FF"; // A CSS color string giving the background color.
// the draw() function fills the canvas with this color.
var xleft = 0; // The requested xy-limits on the canvas, after the
var xright = 7; // coordinate transformation has been applied.
var ybottom = -1; // The transformation is applied in the draw() function.
var ytop = 4;
var frameNumber = 0; // Current frame number.
var cart; // TransformedObjects that are animated.
var wheel;
var sun;
var clickText1;
var clickText2;
var rotor;
/**
* Create the scene graph data structure. The global variable world must
* refer to the root node of the scene graph. This function is called in
* the init() function.
*/
function createWorld() {
pageLayout();
var i;
var sunTemp = new CompoundObject();
sunTemp.setColor("yellow"); // color for filled circle and light rays
for (i = 0; i < 12; i++) { // add the 12 light rays, with different rotations
sunTemp.add( new TransformedObject(line).setScale(0.75,0.75).setRotation(i*30) );
}
sunTemp.add( filledCircle ); // the face of the sun
sunTemp.add( new TransformedObject(circle).setColor("#B40000") ); // outlines the face
sun = new TransformedObject(sunTemp);
clickText1 = new TransformedObject(clickHere).setColor("#B40000").setScale(0.01,-0.01);
var wheelTemp = new CompoundObject();
wheelTemp.setColor("black"); // color for all but one of the subobjects
wheelTemp.add( new TransformedObject(filledCircle).setScale(2,2) );
wheelTemp.add( new TransformedObject(filledCircle).setScale(1.6,1.6).setColor("#CCCCCC") );
wheelTemp.add( new TransformedObject(filledCircle).setScale(0.4,0.4) );
for (i = 0; i < 12; i++) { // add the 12 spokes
wheelTemp.add( new TransformedObject(line).setRotation(i*30) );
}
wheel = new TransformedObject(wheelTemp);
var cartTemp = new CompoundObject();
cartTemp.setColor("red"); // color for the rectangular body of the cart
cartTemp.add( new TransformedObject(wheel).setScale(0.8,0.8).setTranslation(1.5,-0.1) );
cartTemp.add( new TransformedObject(wheel).setScale(0.8,0.8).setTranslation(-1.5,-0.1) );
cartTemp.add( new TransformedObject(filledRect).setScale(5,2).setTranslation(0,1) ); // the body of the cart
cart = new TransformedObject(cartTemp).setScale(0.3,0.3);
clickText2 = new TransformedObject(clickHere).setColor("yellow").setScale(0.01,-0.01);
var rotorTemp = new CompoundObject(); // a "rotor" consisting of three vanes
rotorTemp.setColor( "#C86464" ); // color for all of the vanes
rotorTemp.add( windmillVane );
rotorTemp.add( new TransformedObject(windmillVane).setRotation(120) );
rotorTemp.add( new TransformedObject(windmillVane).setRotation(240) );
rotor = new TransformedObject(rotorTemp);
var windmill = new CompoundObject();
windmill.setColor("#E0C8C8"); // color for the pole
windmill.add( new TransformedObject(filledRect).setScale(0.1,3).setTranslation(0,1.5) ); // the pole
windmill.add( new TransformedObject(rotor).setTranslation(0,3) ); // the rotating vanes
world = new CompoundObject();
world.setColor("#00961E"); // color used for the ground only
world.add(ground);
//world.add( new TransformedObject(filledRect).setScale(7,0.8).setTranslation(3.5,0).setColor("#646496") ); // road
//world.add( new TransformedObject(filledRect).setScale(7,0.06).setTranslation(3.5,0).setColor("white") ); // line in road
world.add( new TransformedObject(windmill).setScale(0.6,0.6).setTranslation(0.75,1) );
world.add( new TransformedObject(windmill).setScale(0.4,0.4).setTranslation(2.2,1.3) );
world.add( new TransformedObject(windmill).setScale(0.7,0.7).setTranslation(3.7,0.8) );
world.add( new TransformedObject(sun).setTranslation(5.5,3.3) );
world.add( new TransformedObject(clickText1).setTranslation(5.25,3.3) );
world.add( cart );
world.add( clickText2 );
//alert(2);
}
/**
* This will be called before each frame is drawn.
*/
function updateFrame() {
frameNumber++;
if (frameNumber>= 312){
frameNumber = 0;
frameNumber2 = 1;
}
cart.setTranslation(-3 + 13*(frameNumber % 300) / 300.0, 0);
clickText2.setTranslation(-3.3 + 13*(frameNumber % 300) / 300.0, 0.25);
if (typeof(pcoords[5]) != 'undefined') {
pcoords[5][0] = (-3.3 + 13*(frameNumber % 300) / 300.0-xleft)*canvas.width / (xright-xleft);
pcoords[5][1] = (0.25-ytop)*canvas.height / (ybottom-ytop);
}
wheel.setRotation(-frameNumber*3.1);
sun.setRotation(-frameNumber);
rotor.setRotation(frameNumber * 2.7);
}
// ------------------------------- graphics support functions --------------------------
/**
* Draw one frame of the animation. Probably doesn't need to be changed,
* except maybe to change the setting of preserveAspect in applyLimits().
*/
function draw() {
graphics.save(); // to make sure changes don't carry over from one call to the next
graphics.fillStyle = "transparent"; // background color
graphics.fillRect(0,0,wWidth, wHeight);
graphics.fillStyle = "black";
applyLimits(graphics,xleft,xright,ytop,ybottom,true);
graphics.lineWidth = pixelSize;
world.draw(graphics);
graphics.drawImage(images["dog-walking11"],200,200);
graphics.restore();
}
/**
* Applies a coordinate transformation to the graphics context, to map
* xleft,xright,ytop,ybottom to the edges of the canvas. This is called
* by draw(). This does not need to be changed.
*/
//pcoords[0][0] =
//pcoords[0][1]=
function applyLimits(g, xleft, xright, ytop, ybottom, preserveAspect) {
var width = canvas.width; // The width of this drawing area, in pixels.
var height = canvas.height; // The height of this drawing area, in pixels.
var k = portals.length;
var j;
var i = 0, widthheight, myradius;
var localerror = false;
if (pcoords.length < k) {
while (portals[i]){
j = i + 1;
if (width > 100){
var rWidth = width/(k + 1);
rWidth= Math.floor(rWidth);
} else {
var lWidth = 0;
var rWidth = 0;
}
if (height > 100){
var bHeight = height/(k + 1);
bHeight= Math.floor(bHeight);
} else {
var tHeight = 0;
var bHeight = 0;
}
var myleft = leftj[i] * rWidth - 50;
var mytop = j * bHeight - 50;
pcoords[i]= new Array;
pcoords[i][0] = myleft;
pcoords[i][1] = mytop;
i = i + 1;
}
}
if (preserveAspect) {
// Adjust the limits to match the aspect ratio of the drawing area.
var displayAspect = Math.abs(height / width);
var requestedAspect = Math.abs(( ybottom-ytop ) / ( xright-xleft ));
var excess;
if (displayAspect > requestedAspect) {
excess = (ybottom-ytop) * (displayAspect/requestedAspect - 1);
ybottom += excess/2;
ytop -= excess/2;
}
else if (displayAspect < requestedAspect) {
excess = (xright-xleft) * (requestedAspect/displayAspect - 1);
xright += excess/2;
xleft -= excess/2;
}
}
var pixelWidth = Math.abs(( xright - xleft ) / width);
var pixelHeight = Math.abs(( ybottom - ytop ) / height);
pixelSize = Math.min(pixelWidth,pixelHeight);
if (frameNumber == 4 || frameNumber == 5){
pcoords.push([(5.25-xleft)*width / (xright-xleft),(3.3-ytop)*height / (ybottom-ytop)]);
pcoords.push([(-3.3 + 13*(frameNumber % 300) / 300.0-xleft)*width / (xright-xleft), (0.25-ytop)*height / (ybottom-ytop)]);
}
g.scale( width / (xright-xleft), height / (ybottom-ytop) );
g.translate( -xleft, -ytop );
// if (frameNumber < 3)
}
//------------------ Animation framework ------------------------------
var animationTimeout = null; // A null value means the animation is off.
// Otherwise, this is the timeout ID.
function frame() {
// Draw one frame of the animation, and schedule the next frame.
updateFrame();
draw();
canvas.addEventListener("mousedown", doMouseDown, false);
animationTimeout = setTimeout(frame, 33);
}
function setAnimationRunning(run) {
if ( run ) {
if (animationTimeout == null) {
// If the animation is not already running, start
// it by scheduling a call to frame().
animationTimeout = setTimeout(frame, 33);
}
}
else {
if (animationTimeout != null) {
// If the animation is running, stop it by
// canceling the next scheduled call to frame().
clearTimeout(animationTimeout);
}
animationTimeout = null; // Indicates that animation is off.
}
}
//----------------------- initialization -------------------------------
function init() {
try {
canvas = document.getElementById("theCanvas");
if(typeof G_vmlCanvasManager != 'undefined') {
canvas = G_vmlCanvasManager.initElement(canvas);
}
graphics = canvas.getContext("2d");
}
catch (e) {
document.getElementById("message").innerHTML =
"Sorry, this page requires canvas graphics, but<br>" +
"it looks like your browser does not support it<br>" +
"Reported error: " + e;
return;
}
// add any other necessary initialization
document.getElementById("animateCheck").checked = true; // Make sure box is checked!
loadImage("dog-walking11");
createWorld();
setAnimationRunning(true); // start the animation
}
</script>
</head>
<body onload="init()" style="background-color: rgb(220,220,220)">
<div id="messagediv">
<h2>Hierarchical Modeling Example</h2>
<!-- For error reporting: the contents of the noscript tag are
shown only if JavaScript is not available. The paragraph with
id="message" is for reporting errors using JavaScript.-->
<noscript><b>This page requires JavaScript, which is<br>
not enabled in your browser.</b></noscript>
<p id="message" style="color:red"></p>
<p><input type="checkbox" id="animateCheck" onchange="setAnimationRunning(this.checked)">
<label for="animateCheck">Run Animation</label>
</p>
</div>
<div id="canvasdiv">
<canvas id="theCanvas" width= "400" height= "300"
style="background-color: transparent"></canvas>
</div>
</body>
</html>
It seems that I had to use graphics.drawImage() after using graphics.restore().
Though I was trying to draw the image in the correct order (after), compared to drawing the rectangles, circles etc, the shapes did not come out of the buffer onto the page until after the restore function().
When I was calling drawImage, I assumed that it was loading it onto the buffered canvas with the rest of the things, ready to be drawn in the correct order, when in fact it was putting it straight onto the page.
It seems strange since it was being called with the graphics context, so I thought it would be added to the rest of the canvas graphics, but i appear to be wrong.

Categories