many very confusing problems with kinetic.js - javascript

i got some problems with understanding kinetic.js (the documentation is horrible for newbies...) i hope i can explain it with my bad english.
Problem 1: Everytime when i #reset my canvas it is not really resetting it. its more like its pushing another background image over the actual canvas and when i click on it it jumps back to the original...
function clearCanvas() {
context.clearRect(0, 0, 1000, 1000); //whole canvas
context.drawImage(buehneObj,0,0); //redraw the main background image
}
and call it with:
reset = document.getElementById('reset');
document.getElementById('reset').onclick =function(){clearCanvas();
}
Problem 2: the slider i build for scaling the image is not working at all but i dont see the problem... ...the variables are global and if i test alert it i see that values are existing...
standard jquery slider:
$('#scaleslider').slider({
animate: "fast",
step: 0.1,
value: 1,
min: 0.1,
max: 1,
slide: function(event,ui){groesse = ui.value} //global variable
});
i made it hidden(display:none) and on click "block"
var scaleslider = document.getElementById('scaleslider').style;
document.getElementById('resize').onclick =function(){ scaleslider.display ="block";}
and here's how kinetic parts look like (dragMotiv is my first start image) "groesse" is the variable for my x and y slider value(they can us the same so it scales correct):
var dragMotiv = new Kinetic.Image({
image: imageObj,
x: 250,
y: 300,
width: 330,
height: 263,
rotationDeg: 0,
scale: { x:groesse, y:groesse },
draggable: true,
dragBoundFunc: function(pos) {
var newY = pos.y < 290 ? 290 : pos.y > 305 ? 305 : pos.y;
var newX = pos.x < 250 ? 250 : pos.x > 390 ? 390 : pos.x;
return {
x: newX,
y: newY
};
}
});
Problem 3: Saving is not possible at all.
i uploaded it to my server to let you guys take a look at it. i know that there is one little thingy that i just dont see(i hope so).
http://manufaktur13.de/playground/canvas_kinetic.html

I think you should not clear the canvas, instead you should keep record what you have drown and remove those items, and redraw the layer.

Related

How to implement rotation of multiple images around an off-centre point in p5.js

I'm making a tower defense game using JavaScript and p5.js library. I have 2 images a base and a gun. The gun is drawn on top of the base to make it appear as a single unit. I need my gun to point towards the enemy(which follows a path). I need help to make the gun rotate on a point(not centre), keeping in mind that there can be several of these towers. I have tried translating(to change centre) and rotating but this doesn't work for many objects and obviously can't keep track of many objects.
I haven't seen any other question regarding this matter either, is there a better solution/alternative to what I'm trying to accomplish?
Required Code
Some Important Variables
var isFireTowerPressed = false; // checks if tower is placed
var FireTowerPos = []; // location of every tower => [] - 2d array
Preloaded Stuff
function preload() {
backgroundImg = loadImage("http://127.0.0.1:8080/img/extra/map1.png");
[...]
firetowerbaseImg = loadImage("http://127.0.0.1:8080/img/towers/firetowerbase.png");
firetowerturretImg = loadImage("http://127.0.0.1:8080/img/towers/firetowergun.png");
}
Draw Every Frame
function draw()
{
background(60, 238, 161);
[...]
if (isFireTowerPressed == true) //checks if I have pressed the button to place the tower
{
image(firetowerbaseImg, mouseX - 28, mouseY - 28);
// show range circle
noFill();
stroke(0,0,0);
strokeWeight(1);
circle(mouseX, mouseY, 300);
}
for (var i = 0; i < FireTowerPos.length; i++)
{
image(firetowerbaseImg, FireTowerPos[i][0], FireTowerPos[i][1]);
image(firetowerturretImg, FireTowerPos[i][0], FireTowerPos[i][1]-20);
}
}
Mouse Click Event
function mouseClicked()
{
if (isFireTowerPressed==true && mouseX+28 <= 750) // place-able area
{
FireTowerPos.push([mouseX-28, mouseY-28]);
isFireTowerPressed = false;
}
}
The picture shows the 2 pictures I'm using(base & gun). I need to be able to rotate the gun towards the enemy
Any help is appreciated, thank you
Translating and rotating works for several objects if you also use the push() and pop() methods, from the p5 library, which allow you to store the current settings.
To rotate towards a given point the function atan2(y2 - y1, x2 - x1) is the commonly used method.
To illustrate, I wrote this quick snippet in which the guns will rotate towards the mouse only if the mouse is within range of the gun.
let gunSprite
function preload(){
gunSprite = loadImage("https://i.imgur.com/ayvg9J2.jpg", ()=>{
gunSprite.resize(20, 40)
})
}
let guns = [
{ x: 160, y: 80, angle: 0, range: 100 },
{ x: 300, y: 200, angle: 0, range: 150 },
{ x: 100, y: 240, angle: 0, range: 120 }
]
function setup(){
createCanvas(600, 400)
noFill()
}
function draw(){
background(200)
for(let gun of guns)
drawGun(gun)
}
function drawGun(gun){
const isWithinRange = dist(mouseX, mouseY, gun.x, gun.y) < gun.range
if(isWithinRange)
gun.angle = atan2(mouseY - gun.y, mouseX - gun.x) + radians(90)
push()
translate(gun.x, gun.y)
rect(-25, -20, 50, 40) // Draw the gun base
ellipse(0, 0, gun.range*2) // display the gun range
rotate(gun.angle)
image(gunSprite, -10, -40) // Set the offset of the gun sprite and draw the gun
pop()
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.1.9/p5.min.js"></script>

Three.js and gsap scale animation

So I'm trying to do a mousemove event in three.js where the user would hover over a geometry and then it would scale.
So for the animations I am using GSAP as tween doesn't seem to be working for me. However, I keep getting this error when I want to scale my geometry:
I don't know why because in the official gsap documentation they use scale, without a plugin I believe. Here is an example from their website
gsap.to(".box", 1, {
scale: 0.1,
y: 60,
yoyo: true,
repeat: -1,
ease: "power1.inOut",
delay:1,
stagger: {
amount: 1.5,
grid: "auto",
from: "center"
}
});
Here is my code:
function init () {
/*------Bunch of three.js code and initialsation*/
window.addEventListener('mousemove',onMouseMove);
}
function onMouseMove(event) {
event.preventDefault();
mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1;
mouse.y = - ( event.clientY / window.innerHeight ) * 2 + 1;
raycaster.setFromCamera(mouse,camera);
var intersects = raycaster.intersectObjects(scene.children, true);
for(var i = 0; i < intersects.length; i++) {
gsap.to(intersects[i].object.scale, {duration: 1, scale: 0.8});
}
}
So I figured the answer. It seems that in three.js, the gsap scale property doesn't work so you need to make sure you're referring to scale before adding transformations, and then use x and y (or maybe z - I haven't tried) to increase or decrease the size.
This is the code that worked for me:
gsap.to(intersects[i].object.scale, {duration: .7, x: 1.2, y:1.2});

Change Color of Shape Mid Tween

I'm trying to make an event that changes my shapes stroke color for 5 seconds when a button is clicked, and then the shape returns to original color after the duration.
I am able to do this with clearing the entire stage and redrawing new shapes (which resets their position), but I can't figure it out with the current shapes.
Q. What's the best way to approach making a change to a shapes color, during a Tween?
I was also curious if there's a better way to handling tweening the shapes width? Currently I am relying on ScaleX and ScaleY - but this also changes the stroke's size - which is not desired.
JS Fiddle
HTML
<button id="change">Click to Change Color</button>
<canvas id="demoCanvas" width="500" height="500"></canvas>
JS
var stage,
circle;
function init() {
stage = new createjs.Stage("demoCanvas");
createjs.Ticker.setFPS(60);
createjs.Ticker.addEventListener("tick", stage);
}
function createCircle(){
circle = new createjs.Shape().set({name:"circle"});
circle.graphics.setStrokeStyle(1).beginStroke("#000").beginFill( "#FFF" ).drawCircle(0, 0, 20);
circle.x = 100;
circle.y = 100;
stage.addChild(circle);
createjs.Tween.get(circle, {loop: true})
.to({x: 225, y: 225}, 1000, createjs.Ease.getPowInOut(1))
.to({x: 100, y: 100}, 1000, createjs.Ease.getPowInOut(1));
circle2 = new createjs.Shape().set({name:"circle"});
circle2.graphics.setStrokeStyle(1).beginStroke("#000").beginFill( "#FFF" ).drawCircle(0, 0, 20);
circle2.x = 400;
circle2.y = 400;
stage.addChild(circle2);
createjs.Tween.get(circle2, {loop: true})
.to({scaleX: 2, scaleY: 2, x: 425, y: 125}, 1000, createjs.Ease.getPowInOut(1))
.to({scaleX: 1, scaleY: 1, x: 400, y: 400}, 1000, createjs.Ease.getPowInOut(1));
stage.update();
}
$( "#change" ).click(function() {
// change color
});
$(document).ready(function() {
init();
createCircle();
});
There are a few questions in this post, so I will try to answer them all:
First, a solution to most of your issues is Graphic commands. Commands provide a simple way to store graphic instructions, and change them later. Here is a simple example:
var shape = new createjs.Shape();
var colorCmd = shape.graphics.beginFill("red").command;
var rectCmd = shape.graphics.drawRect(0,0,100,100).command;
// Later
colorCmd.style = "blue";
rectCmd.w = 200;
stage.update(); // Remember to update the stage after changing properties
You can read more about commands on the createjs blog. All commands and their properties are documented in the EaselJS docs.
Change a color: I outlined this in the example above, but the short answer is to adjust the style property of a fill command. If you want to change it instantly, you can just set up a Tween.call:
Example:
createjs.Tween.get(circle, {loop: true})
.to({x: 225, y: 225}, 1000, createjs.Ease.getPowInOut(1))
.call(function(tween) {
colorCmd.style = "rgba(0, 0, 255, 0.5)"; // Change to 50% blue
})
.to({x: 100, y: 100}, 1000, createjs.Ease.getPowInOut(1));
If you want to tween the color, then you could check out the ColorPlugin, which is currently in a "Plugins" branch of TweenJS: https://github.com/CreateJS/TweenJS/tree/Plugins/extras/plugins
// Tween the color from its current value to blue.
// Note that only hex, short hex, HSL, and RGB formats are supported.
createjs.Tween.get(colorCmd).to({style:"#0000ff"});
Change the size: The example above also shows how to modify the values of a drawRect call. You can do the same with any other draw command (including moveTo, lineTo, polyStar, etc).
Scaling also works, and if you want to not scale the stroke, just set the ignoreScale parameter on the stroke style.
shape.graphics.setStrokeStyle(1, null, null, null, true);

Dragging image out of frame removes it from the kineticjs stage

Could someone please provide me with the a jsfiddle of a simple and clean way to remove an image from the canvas by dragging the image out of the canvas frame.
Here is what I could come up with http://jsfiddle.net/n4w44/50/ :
I make the stage 400px and put the frame in the center at 200px by 200px dimensions by implementing the dragBoundFunc.
var image = new Kinetic.Image({
draggable : true,
x: 175,
y:175,
width: 50,
height: 50,
draggable: true,
dragBoundFunc: function(pos) {
var stage_width = stage.getWidth();
if (pos.x > 300 || pos.x < 100 || pos.y > 300 || pos.y < 100)
{
this.hide();
}
return {
x: pos.x,
y: pos.y
};
}
});
But it would be nice to see alternative solutions which:
Make it look cleaner as the image is exiting
Allow me to avoid having to do some ugly offsetting of the container (which I would need to do when I embed it in the page).
Is there any reason you're using an older version of KineticJS (4.4.3)? The reason I ask is because as of KineticJS 4.5.1 (and now currently we're on 4.6.0 which you can get on the KineticJS Website) the Tween class was added in favor of the Transition class.
KineticJS 4.5.1 Changelog
Anyways, I solved your problem by adding some code to the dragBoundFunc
var image = new Kinetic.Image({
draggable: true,
x: 175,
y: 175,
width: 50,
height: 50,
draggable: true,
dragBoundFunc: function (pos) {
var thisImg = this;
if (pos.x > (frame.getWidth() + frame.getX() - thisImg.getWidth()) || pos.x < frame.getX() || pos.y > (frame.getHeight() + frame.getY() - thisImg.getHeight()) || pos.y < frame.getY()) {
var tween = new Kinetic.Tween({
node: thisImg,
duration: 0.1,
opacity: 0,
onFinish: function () {
thisImg.hide();
thisImg.setOpacity(1);
}
});
this.stopDrag();
tween.play();
}
return {
x: pos.x,
y: pos.y
};
}
});
To make the image exit smoother, I used a Tween to tween the opacity to 0, making it look like a quick fade effect. When the tween finishes, I hide the image and set the opacity back to 1 so you can show the image later without any complications. .stopDrag() is used to the stop the image from dragging while the Tween is played.
To make the dragBoundFunc more dynamic, instead of using static numbers we use the x,y position of the frame along with the width & height to calculate the boundaries, and we also need the width and height of the image to subtract from the boundaries so that the dragBoundFunc takes into consideration the offset of the image (which is by default the top left).
JSFIDDLE Note: In the fiddle I replaced the KineticJS 4.4.3 version with KineticJS 4.6.0 (see the HTML code)
It's up to you if you can upgrade your KineticJS version to use Tweens, or stick with the version you have now and use Transitions (which you'll have to find documentation for, I'm not sure how they work).

THREE.js & the order of transformations

I'm learning THREE.js right now, and I stucked with a probably noob problem.
I've a JSON object width dynamic update, it contains some data of 4 walls. The JSON struct:
{
...
walls: [{
start: {
x : 0,
y : 0,
z : 0
},
length: 1200,
rotation: 0
}, {
start: {
x : 0,
y : 0,
z : 0
},
length: 1200,
rotation: -(Math.PI/2)
}, {
start: {
x : 0,
y : 0,
z : 1200
},
length: 1200,
rotation: 0
}, {
start: {
x : 1200,
y : 0,
z : 0
},
length: 1200,
rotation: (Math.PI/2)
}],
...
}
I'm trying to position walls on canvas, It's OK when the wall has just a translation OR rotation, but there's a problem when the wall has both of them.
Here's my code (this._container is an instance of THREE.Mesh):
this._container.matrixAutoUpdate = false;
this._container.add(new THREE.AxisHelper(1000));
if(rotation) {
this._container.rotation.y = rotation;
this._container.updateMatrix();
}
if(translation) {
this._container.translateX((translation.x + (width/2)));
this._container.translateY((translation.y + (height/2)));
this._container.translateZ((translation.z));
this._container.updateMatrix();
}
If I apply rotation first then translate, it rotates the object's local axes too, and the translation will have wrong directions (http://robber.hu/webgl/1.png). If I apply translation first, than rotate, the Y axis moves to other position, and the rotation will be around wrong point (http://robber.hu/webgl/2.png).
I think there are two ways to solve this problem, but can't find the solutions:
Somehow using a "global translation", so the object translates on the scene's axis, and then use the first method
Change the object's "pivot" to left or right edge, and than use the second method
How can I implement it, or where can I find some docs/tutorial for this?
Solved.
The solution was that: Use three transformations insted of two. First, translate object to final position, second, rotate it, and finally, translate again via local X and y axis. Third translation moving the local axis from object's center to the corner.
R

Categories

Resources