Found a strange behaviour that when I keep adding or toggle display sprite object. That makes my game screen shakes when toggle some of optional UIs .
Tried to reproduce this issue with simplified codes. Here is the experiment.
The red line shows the original position of first square.png
When I keep adding sprites on the same position, appears that pixels moved, the square not stack up in different positions
When hiding sprite except the first square, seems it back to correct position
var MyScene = cc.Scene.extend({
onEnterTransitionDidFinish: function(){
this._super();
this.initComponents();
},
initComponents: function () {
//create additional square container
var node = new cc.Node();
this.node = node;
node.setPosition(90, 90);
this.attach(node);
this.addChild(node);
//draw first square
var sprite = new cc.Sprite("square.png");
sprite.setPosition(50,50);
this.addChild(sprite);
//listen to keyboard, add square / toggle
if ('keyboard' in cc.sys.capabilities) {
cc.eventManager.addListener({
event: cc.EventListener.KEYBOARD,
onKeyPressed: function (keyCode, event) {
switch (keyCode) {
//toggle additional squares
case cc.KEY.q:
this.node.setVisible(!this.node.isVisible());
break;
//attach more squares
case cc.KEY.w:
this.attach(node);
break;
}
}.bind(this)
}, this);
}
//draw measure line
var line = new cc.DrawNode();
line.drawRect(cc.p(130,0), cc.p(132,150),cc.color(255,0,0,255),0);
this.addChild(line);
},
/**
* Attach more squares
* #param node
*/
attach: function (node) {
var xp = 0;
var yp = 0;
for (var i = 0; i < 5; i++) {
var sp = new cc.Sprite("square.png");
node.addChild(sp);
sp.setPosition(xp * 180, yp * 180);
xp++;
if (xp > 15) {
xp = 0;
yp++;
}
}
}
});
It's difficult to answer you without the context, what API do you use ? What is cc ?
Anyway, by comparing the screenshots you provided it seems that your squares effectively moved away. The strange corners appears because you don't clear the screen between each frame.
This produce a trail, it's not the pixels that moved, but the squares themselves.
Try those steps :
print their positions each time you add a new sprite
fix the length of view
try to print a square instead of using an image
Edit your question if you have more information, and then I will edit this answer according to your additional information.
Found that the issue can be improved / resolve by assign everything into negative z order
var children = this.getChildren();
var avicinarAka = -99999;
for (var k in children) {
if (children[k]) {
children[k].setLocalZOrder(avicinarAka++);
}
}
Related
http://40.117.122.212/
I want to add more images dynamically on scrolling the canvas, i don't wanna see any empty areas on the canvas.
Any ideas on how to get that done ?
I use paperjs, I create about 90 images and they are moving on the canvas randomly.
Each time you scroll, you can check if there is space for more images at the bottom of the screen (and maybe at the top too for a better effect?) and if this is true, add more images.
In order to get that working, you will certainly need to find a way to quickly get the topest/lowest items to check how far they are from view bounds.
To better understand the concept, I reduced the problem to a simple case involving only one column of circles.
Here is the sketch demonstrating the solution.
Code should be self-explainatory and should allow you to transpose it to your specific case.
// Set gris Size.
const gridSize = 100;
// Calculate and store several useful metrics.
const viewHeight = view.bounds.height;
const itemsCount = Math.floor(viewHeight / gridSize);
// For the simplicity of the demo, items are only drawn in one column so x
// coordinate is constant.
const x = view.center.x;
// Create original items to fill the screen.
let items = [];
for (let i = 0; i < itemsCount; i++) {
items.push(createItem(i * gridSize));
}
// Center them on the screen.
project.activeLayer.position = view.center;
// On scroll...
view.element.onmousewheel = function(event) {
// ...translate layer up or down.
// Using layer translation instead of view scroll cause items coordinates
// to be updated which will help us in later calculations.
const translation = event.deltaY > 0 ? new Point(0, 10) : new Point(0, -10);
project.activeLayer.translate(translation);
// Trigger items addition process.
addItemsIfNeeded();
};
// Simply create a random colored, horizontally centered circle, at given
// y position.
function createItem(y) {
return new Path.Circle({
center: new Point(x, y),
radius: gridSize / 4,
fillColor: Color.random()
});
}
// Check for empty space at the bottom or the top of the page and create as
// many items as needed to fill the empty space.
function addItemsIfNeeded() {
// Get extremas items y positions.
const lastItemY = items[items.length - 1].position.y;
const firstItemY = items[0].position.y;
const deltaBottom = viewHeight - lastItemY;
// If there is empty space at bottom...
if (deltaBottom > gridSize) {
// ...add items at bottom.
const itemsNeededCount = Math.floor(deltaBottom / gridSize);
addItems(itemsNeededCount, lastItemY);
// If there is empty space at top...
} else if (firstItemY > gridSize) {
// ...add items at top.
const itemsNeededCount = Math.floor(firstItemY / gridSize);
addItems(itemsNeededCount, firstItemY, true);
}
}
// Create given number of items and add them to the begining or the end of the
// stack.
function addItems(count, referenceItemY, before) {
// For each new item...
for (let i = 1; i <= count; i++) {
// ...calculate y position...
const y = before
? referenceItemY - i * gridSize
: referenceItemY + i * gridSize;
// ...create item...
const item = createItem(y);
// ...add it to the stack.
if (before) {
items.unshift(item);
} else {
items.push(item);
}
}
}
Does someone know how is this animation build, which js framework is used or something that can help me get to know to recreate something similar?
Banner BG animation ---> https://envylabs.com/
Thanks in advance!
I can't tell with what library this animation was build with, because it is hidden in React bundled code, but I can show you a way to do something similar with Paper.js.
By looking at the animation, it seems that rules are:
a circle is influenced by mouse pointer if it is under a certain distance from it
the closest to the mouse pointer a circle is:
the bigger it becomes
the farther from the window center it goes.
Here is a Sketch implementing this.
//
// CONSTANTS
//
// user defined
var ROWS_COUNT = 10; // number of rows in the grid
var COLUMNS_COUNT = 10; // number of columns in the grid
var MOUSE_INFLUENCE_RADIUS = 350; // maximal distance from mouse pointer to be influenced
var INFLUENCE_SCALE_FACTOR = 1; // maximal influence on point scale
var INFLUENCE_POSITION_FACTOR = 15; // maximal influence on point position
// computed
var STEP_X = view.bounds.width / COLUMNS_COUNT;
var STEP_Y = view.bounds.height / ROWS_COUNT;
var RADIUS = Math.min(STEP_X, STEP_Y) * 0.1;
//
// ITEMS
//
// create a circle for each points in the grid
var circles = [];
for (var i = 0; i < COLUMNS_COUNT; i++)
{
for (var j = 0; j < COLUMNS_COUNT; j++)
{
var gridPoint = new Point((i + 0.5) * STEP_X, (j + 0.5) * STEP_Y);
circles.push(new Path.Circle({
center : gridPoint,
radius : RADIUS,
fillColor : 'black',
// matrix application is disabled in order to be able to manipulate scaling property
applyMatrix: false,
// store original center point as item custom data property
data : {gridPoint: gridPoint}
}));
}
}
//
// EVENTS
//
function onMouseMove(event)
{
for (var i = 0; i < circles.length; i++)
{
var circle = circles[ i ];
var gridPoint = circle.data.gridPoint;
var distance = event.point.getDistance(gridPoint);
// only influence circles that are in mouse influence zone
if (distance <= MOUSE_INFLUENCE_RADIUS)
{
var influence = 1 - distance / MOUSE_INFLUENCE_RADIUS;
// the closest the circle is from the mouse pointer
// the bigger it is
circle.scaling = 1 + influence * INFLUENCE_SCALE_FACTOR;
// the farthest it is from view center
circle.position = gridPoint + (gridPoint - view.center).normalize(influence * INFLUENCE_POSITION_FACTOR);
}
else
{
// reset circle state
circle.scaling = 1;
circle.position = gridPoint;
}
}
}
Your question is too open.
But there are some libraries that will save you a lot of time:
D3.js
Processing.js
Paper.js
There are a lot more, but it depends on what you need.
Trying to add a Canvas layer on top of a Bing TileLayer using the extensions below. In addition to that, I would like to animate the canvas drawing using RequestAnimationFrame.
The issue is that it seems that when dragging, the point moves more than what it should (see video). However, at the end of the moving, it comes back to the right place.
I tried different methods, either inheriting CanvasLayer and overriding render() or setting a delegate, always same result.
Here is the relevant part of the code:
// layer creation (TypeScript)
this.mapCanvasLayer = new L.CanvasLayer();
this.mapCanvasLayer.delegate(this).addTo(map);
// L.canvasLayer()
// .delegate(this) // -- if we do not inherit from L.CanvasLayer we can setup a delegate to receive events from L.CanvasLayer
// .addTo(map);
// drawing and animation (TypeScript)
public onDrawLayer(info) {
// quick test, this just draws a red dot that blinks
this.info = info;
var data = [[0,0]];
var ctx = info.canvas.getContext('2d');
ctx.clearRect(0, 0, info.canvas.width, info.canvas.height);
ctx.fillStyle = "rgba(255,0,0," + this.i/10 + ")";
for (var i = 0; i < data.length; i++) {
var d = data[i];
if (info.bounds.contains([d[0], d[1]])) {
var dot = info.layer._map.latLngToContainerPoint([d[0], d[1]]);
ctx.beginPath();
ctx.arc(dot.x, dot.y, 3, 0, Math.PI * 2);
ctx.fill();
ctx.closePath();
}
}
};
public animate() {
// make the point blink
if (this.up) {
this.i++;
if (this.i >= 10) this.up = false;
}
else
{
this.i--;
if (this.i <= 1) this.up = true;
}
// animate:
this.mapCanvasLayer.drawLayer();
window.requestAnimationFrame(this.animate.bind(this));
}
Extensions tried:
gLayers.Leaflet // example is this one
Leaflet.CanvasLayer
Not tried yet:
Leaflet-Fullcanvas
I have the feeling it is due either to the dragging event or the coordinates translations (latLngToContainerPoint) not being properly handled, but have no idea why.
In the samples available for the Leaflet.CanvasLayer dragging an animated map seems to work fine.
Any idea what is wrong with this code? Thank you for your help!
Edit
See comments: replaced the call as below:
// var dot = info.layer._map.latLngToContainerPoint([d[0], d[1]]);
var dot = info.layer._map.latLngToLayerPoint([d[0], d[1]]);
Now, the point moves correctly. However, when I release the button, it now shifts to a position relative to the container, i.e. same distance of window borders, but wrong coordinates (wrong location on map).
If I now do this:
public onDrawLayer(info) {
this.info = info;
var ctx = info.canvas.getContext('2d');
ctx.clearRect(0, 0, info.canvas.width, info.canvas.height);
const fillStyleLayer = "rgba(255,0,0,1)"; // red: layer
const fillStyleContainer = "rgba(0,0,255,1)"; // blue: container
var layerPoint = info.layer._map.latLngToLayerPoint([0,0]);
var containerPoint = info.layer._map.latLngToContainerPoint([0,0]);
// this.dot = (this.dragging)
// ? info.layer._map.latLngToLayerPoint([0,0]);
// : info.layer._map.latLngToContainerPoint([0,0]);
ctx.fillStyle = fillStyleLayer;
ctx.beginPath();
ctx.arc(layerPoint.x, layerPoint.y, 3, 0, Math.PI * 2);
ctx.fill();
ctx.closePath();
ctx.fillStyle = fillStyleContainer;
ctx.beginPath();
ctx.arc(containerPoint.x, containerPoint.y, 3, 0, Math.PI * 2);
ctx.fill();
ctx.closePath();
};
public animate() {
this.mapCanvasLayer.drawLayer();
window.requestAnimationFrame(this.animate.bind(this));
}
Layer point (red) moves correctly when panning but then shifts to wrong location. Container point (blue) moves too much when panning but then shifts back to correct location... :(
A bit late to the game but switching to L.canvasOverlay() worked for me. Here's a great example of the library in action
http://bl.ocks.org/Sumbera/11114288
I am trying to imitate the control system in Soul Knight. If you are unfamiliar, whenever a player places their finger on the screen, the joystick appears underneath their finger, then if they drag their finger the joystick tracks to it. This way you dont have to be super precise and worry about putting your finger in the perfect place for the joystick.
Controls graphic
End Goal:
In the attached graphic i show what i would like to happen. Pretend the circles outside of the grey circle are the point where the user is touching with their finger. When the touch point moves as shown, i want the white circle within the gray circle to move as shown, in a circular arc to the left. I want this functionality but also want the circle to be able to move to anywhere within the gray circle if the user is touching there.
Movement system:
As is, the current system finds the position of the touch and finds the difference between that and the center circle in both the x and y axis, then it divides both of those numbers by 10, then adds both values to the x and y axis. This way, the circle moves directly towards the touch.
Constraint system:
I am using if statements and the Pythagorean theorem to ask the question "If your hypotenuse WOULD be greater than the radius of the big circle, then dont move." This effectively stops the circle, but once it is stopped it never moves again.
Other algorithms that would work better?
Any code-specific ideas?
Any content you can point me to that already works like the system i desire?
Context for the code- "base" is the grey circle
Trackme is a public var I set to tell the white circle what object to move towards.
#pragma strict
private var itemPos:Vector3;
private var basePos:Vector3;
private var moveCount = 0;
private var seed = 1;
private var xdif = 0.0f;
private var ydif = 0.0f;
private var xdifbase = 0.0f;
private var ydifbase = 0.0f;
private var radiuscircle = 13;
private var parental : GameObject;
private var base : GameObject;
var trackme : String;
function Update () {
parental = GameObject.Find(trackme);
base = GameObject.Find("joystickbase");
itemPos = parental.transform.position;
basePos = base.transform.position;
xdif = Mathf.Abs(itemPos[0] - transform.position[0])/10.0f;
ydif = Mathf.Abs(itemPos[1] - transform.position[1])/10.0f;
xdifbase = basePos[0] - transform.position[0];
ydifbase = basePos[1] - transform.position[1];
if (transform.position[0] < itemPos[0] )
{
if (Mathf.Sqrt((xdifbase+xdif)*(xdifbase+xdif) + ydifbase * ydifbase) < radiuscircle)
{
transform.position = Vector3(transform.position[0] +xdif, transform.position[1], transform.position[2]);
}
}
if (transform.position[0] > itemPos[0] )
{
if (Mathf.Sqrt((xdifbase-xdif)*(xdifbase-xdif) + ydifbase * ydifbase) < radiuscircle)
{
transform.position = Vector3(transform.position[0] -xdif, transform.position[1], transform.position[2]);
}
}
if (transform.position[1] < itemPos[1] )
{
if (Mathf.Sqrt(xdifbase * xdifbase + (ydifbase+ydif)*(ydifbase+ydif)) < radiuscircle)
{
transform.position = Vector3(transform.position[0] , transform.position[1] +ydif, transform.position[2]);
}
}
if (transform.position[1] > itemPos[1] )
{
if (Mathf.Sqrt(xdifbase * xdifbase + (ydifbase-ydif)*(ydifbase-ydif)) < radiuscircle)
{
transform.position = Vector3(transform.position[0] , transform.position[1] -ydif, transform.position[2]);
}
}
}
One way to solve this would be to instead use Mathf.Clamp on the transform's position to clamp it within the bounds of your circle. You could accomplish this by first normalizing the touch position from the center location of the circle, then multiply by your scalar, and clamp this value within your circle's bounds. You would then set your transform.position to the clamped values of this new vector. For example:
Vector2 normedVec = touch.position.normalized * 10;
transform.position = new Vector2(Mathf.Clamp(normedVec.x, -20, 20), Mathf.Clamp(normedVec.y, -20, 20);
I have a sphere (globe) with objects (pins) on the surface with DOM elements (labels) what are calculated from the pin position to 2d world.
My problem is that when the pins go behind the globe (with mouse dragging or animation) then I need to hide labels which are in DOM so that the text label isn’t visible without the pin.
My logic is that if I can get the pin which is in 3D world to tell me if it’s behind the globe then I can hide the label associated with the pin.
Codepen with whole the code.
The function that I have researched together:
function checkPinVisibility() {
var startPoint = camera.position.clone();
for (var i = 0; i < pins.length; i++) {
var direction = pins[i].position.clone();
var directionVector = direction.sub(startPoint);
raycaster.set(startPoint, directionVector.clone().normalize());
var intersects = raycaster.intersectObject(pins[i]);
if (intersects.length > 0) {
// ?
}
}
}
I have researched through many posts but can’t really get the result needed:
ThreeJS: How to detect if an object is rendered/visible
Three.js - How to check if an object is visible to the camera
http://soledadpenades.com/articles/three-js-tutorials/object-picking/
I have gotten it work by mouse XY position as a ray, but can’t really get a working solution with constant rendering for all the pins.
You want to know which points on the surface of a sphere are visible to the camera.
Imagine a line from the camera that is tangent to the sphere. Let L be the length of the line from the camera to the tangent point.
The camera can only see points on the sphere that are closer to the camera than L.
The formula for L is L = sqrt( D^2 - R^2 ), where D is the distance from the camera to the sphere center, and R is the sphere radius.
WestLangley's solution in code form. Please give him the accepted answer if you feel his answer the best.
function checkPinVisibility() {
var cameraToEarth = earth.position.clone().sub(camera.position);
var L = Math.sqrt(Math.pow(cameraToEarth.length(), 2) - Math.pow(earthGeometry.parameters.radius, 2));
for (var i = 0; i < pins.length; i++) {
var cameraToPin = pins[i].position.clone().sub(camera.position);
if(cameraToPin.length() > L) {
pins[i].domlabel.style.visibility = "hidden";
} else {
pins[i].domlabel.style.visibility = "visible";
}
}
}
Oddly enough it is still susceptible to that camera pan error. Very weird, but it's still better than my Projection-onto-LOOKAT solution.
MY OLD ANSWER:
I would have assumed its something like this, but this doesn't seem to work as expected.
if (intersects.length > 0) {
pins[i].domlabel.style.visibility = "visible";
} else {
pins[i].domlabel.style.visibility = "hidden";
}
I got close with this solution, but its still not perfect. What the code below does is it finds the distance along the LOOKAT direction of the camera to a pin (cameraToPinProjection) and compares it with the distance along the LOOKAT direction to the earth (cameraToEarthProjection).
If cameraToPinProjection > cameraToEarthProjection it means the pin is behind the centre of the earth along the LOOKAT direction (and then I hide the pin).
You will realise there's a "0.8" factor I multiply the cameraToEarth projection by. This is to make it slightly shorter. Experiment with it.
Its not perfect because as you rotate the Earth around you will notice that sometimes labels don't act the way you'd like them, I'm not sure how to fix.
I hope this helps.
function checkPinVisibility() {
var LOOKAT = new THREE.Vector3( 0, 0, -1 );
LOOKAT.applyQuaternion( camera.quaternion );
var cameraToEarth = earth.position.clone().sub(camera.position);
var angleToEarth = LOOKAT.angleTo(cameraToEarth);
var cameraToEarthProjection = LOOKAT.clone().normalize().multiplyScalar(0.8 * cameraToEarth.length() * Math.cos(angleToEarth));
var startPoint = camera.position.clone();
for (var i = 0; i < pins.length; i++) {
var cameraToPin = pins[i].position.clone().sub(camera.position);
var angleToPin = LOOKAT.angleTo(cameraToPin);
var cameraToPinProjection = LOOKAT.clone().normalize().multiplyScalar(cameraToPin.length() * Math.cos(angleToPin));
if(cameraToPinProjection.length() > cameraToEarthProjection.length()) {
pins[i].domlabel.style.visibility = "hidden";
} else {
pins[i].domlabel.style.visibility = "visible";
}
}
}