I want to make "camera follow" effect on feature while its moves along path.
The feature is moved using requestAnimationFrame, here is the example code:
var lastFrame = +new Date;
var updateSlider = function () {
var now = +new Date, deltaTime = now - lastFrame;
trackValue += deltaTime;
self.move(trackValue);
lastFrame = now;
self.Timer = requestAnimationFrame(updateSlider);
};
updateSlider();
.move = function (timestamp) {
var point = LineString.getCoordinateAtM(timestamp);
if(point) Feature.setCoordinate(point);
this.followCamera();
};
I tried a few options of centering the view. And it works, but the problem is that the map jitters. Need help on getting rid of the jitter.
See this OL example - http://openlayers.org/en/latest/examples/geolocation-orientation.html, to see map jitters, press "Simulate"
.followCamera = function() {
var extent = Feature.getGeometry().getExtent();
A) view.set('center', ol.extent.getCenter(extent);
B) view.setCenter(ol.extent.getCenter(extent);
C) view.animate({center: ol.extent.getCenter(extent)});
D) view.fit(extent) <- Not usable in my case, because i want to zoom in/out manually
};
Also you can try this example (taken from ol examples) - https://jsfiddle.net/32z45kLo/5/ - try with and without setCenter part at moveFeature function (line 152)
Here is the video - https://youtu.be/L96HgWZi6Lo
I think the problem is that you are creating and drawing a new feature to vectorContext at each frame animation.
Instead you should create a feature and add it into a vectorLayer once, and then modify its geometry at each frame animation.
//here you define the pinpoint feature and add it to the vectorLayer
var feature = new ol.Feature();
feature.setStyle(styles.geoMarker);
vectorLayer.getSource().addFeature(feature);
var moveFeature = function(event) {
var vectorContext = event.vectorContext;
var frameState = event.frameState;
if (animating) {
var elapsedTime = frameState.time - now;
// here the trick to increase speed is to jump some indexes
// on lineString coordinates
var index = Math.round(speed * elapsedTime / 1000);
if (index >= routeLength) {
stopAnimation(true);
return;
}
var currentPoint = new ol.geom.Point(routeCoords[index]);
//here you modify the feature geometry instead of creating a new feature
feature.setGeometry(currentPoint);
map.getView().setCenter(routeCoords[index]);
}
// tell OpenLayers to continue the postcompose animation
map.render();
};
working demo without jitter:
https://jsfiddle.net/32z45kLo/80/
The problem is that points on the lines are not equidistant thus the position jump from one to another but nothing inbeetween.
Look at this example to calculate points on the line: http://viglino.github.io/ol-ext/examples/animation/map.featureanimation.path.html
Using a ol.featureAnimation.Path, if you have to move the map on position change, just listen to the change event on the animated feature to get its current position:
geoMarker.on('change', function() {
map.getView().setCenter(geoMarker.getGeometry().getCoordinates());
});
You can see a working example with your code here: https://jsfiddle.net/Viglino/nhrwynzs/
Related
I am almost done my game, I just need to add bullets that fire when you press space
I do have some code so far that I used from a tutorial, however it points towards the mouse. I know that I have to move it into the key-handler, but I don't know how.
I also don't know how to get rid of the wade part, I know it comes from a .json file but I want not to
Heres the code:
var nextFireTime = lastFireTime + 1 / fireRate;
var time = wade.getAppTime();
if (wade.isMouseDown() && time >= nextFireTime)
{
lastFireTime = time;
// create bullet...
}
wade.setMainLoopCallback(function()
{
// code to execute several times per second
}, 'fire');
if (wade.isMouseDown())
{
var spacemanPosition = spacemanImage.getPosition();
var spacemanSize = spacemanImage.getSize();
var sprite = new Sprite('images/alien.png');
var bullet = new SceneObject(sprite, 0, shipPosition.x, shipPosition.y - shipSize.y / 2);
wade.addSceneObject(bullet);
bullet.moveTo(shipPosition.x, -500, 600);
}
bullet.onMoveComplete = function()
{
wade.removeSceneObject(this);
};
var lastFireTime = 0;
var fireRate = 5;
To use the spacebar instead of a mousepress you have to change
wade.isMouseDown()
to
wade.isKeyDown('space')
I am struggling with camera functionality that (I think) would provide a way to force my polygon to stick to the top of my house on zoom-out, zoom-in, and rotation (or camera move).
This question follows an earlier question that was resolved. Now I need a little help resolving my next issue.
The sample code I am trying to follow is located in the gold standard that appears to be baked into the existing camera controller here.
pickGlobe is executed with the parameters of the viewer, the correct mousePosition in world coordinates and a result parameter, which I don't care about right now. scene.pickPosition takes the c2position (Cartesian2) and should return the scratchDepthIntersection (Cartesian3). Instead, the returned value is undefined.
Here is my code:
function clickAction(click) {
var cartesian = scene.camera.pickEllipsoid(click.position, ellipsoid);
if (cartesian) {
var setCartographic = ellipsoid.cartesianToCartographic(cartesian);
collection.latlonalt.push(
Cesium.Math.toDegrees(setCartographic.latitude).toFixed(15),
Cesium.Math.toDegrees(setCartographic.longitude).toFixed(15),
Cesium.Math.toDegrees(setCartographic.height).toFixed(15)
);
lla.push(Cesium.Math.toDegrees(setCartographic.longitude), Cesium.Math.toDegrees(setCartographic.latitude));
if (lla.length >= 4) {
console.log((lla.length / 2) + ' Points Added');
}
enableDoubleClick();
enableDraw();
testMe(click.position); <--------------------- straight from the mouse click
}
}
var pickedPosition;
var scratchZoomPickRay = new Cesium.Ray();
var scratchPickCartesian = new Cesium.Cartesian3();
function testMe(c2MousePosition) { <--------------------- straight from the mouse click
if (Cesium.defined(scene.globe)) {
if(scene.mode !== Cesium.SceneMode.SCENE2D) {
pickedPosition = pickGlobe(viewer, c2MousePosition, scratchPickCartesian);
} else {
pickedPosition = camera.getPickRay(c2MousePosition, scratchZoomPickRay).origin;
}
}
}
var pickGlobeScratchRay = new Cesium.Ray();
var scratchRayIntersection = new Cesium.Cartesian3();
var c2position = new Cesium.Cartesian2();
function pickGlobe(viewer, c2MousePosition, result) { <--------------------- straight from the mouse click
c2position = c2MousePosition; <--------------------- setting to Cartesian2
var scratchDepthIntersection = new Cesium.Cartesian3();
if (scene.pickPositionSupported) {
scratchDepthIntersection = scene.pickPosition(c2MousePosition); <--------------------- neither works!
}
}
Here are my variables:
Here is the result:
Here are my questions to get this code working:
1. Why is scratchDepthIntersection not getting set? c2position is a Cartesian2 and c2MousePosition is straight from the mouse.click.position and scratchDepthIntersection is a new Cartesian3.
The correct value for mousePosition is a Cartesian2 containing window coordinates, not a Cartesian3. Such mouse coordinates usually come from a callback from Cesium.ScreenSpaceEventHandler, but can also be constructed from native JavaScript mouse/touch events.
If you inspect the contents of mousePosition, you should find x and y values in window pixel coordinates.
I see you edited the question to include the contents of mousePosition, and it looks like the mouse coordinates have already been converted into ellipsoid Cartesian3 coordinates, which will prevent this code from working. You want original mouse coordinates going directly into scene.pickPosition for this to work.
I am adding "n" number of circles on the scene.
var radius = 1;
var segments = 32;
var circleGeometry = new THREE.CircleGeometry( radius, segments);
function generateCircles(){
//scene.remove(circle);
var count=0;
while (1000> count) {
circle = new THREE.Mesh (circleGeometry, material);
scene.add (circle);
count ++;
}
}
It is effective to do it this way ?.
in my code I call this function. and every time you call it, it all goes back slower, I guess it's because there are more objects in the scene. what can I do?
Each time the function is called I need erased completely from the memory stage and the circles that were generated.
with "slower", I mean that I want my application to run faster. every time I run the function add more and more circles. so I want to be removed earlier. to add new ones. if there are many circles in the scene it slows execution.
http://jsfiddle.net/v8oxsxtc/
You can remove the old circles from the scene by calling the scene.remove method on each of the circles you previously added. Here is a simple example using your code:
var lastCircles = null;
function generateCircles(){
var count=0;
if(lastCircles) { // remove old circles if they exist
lastCircles.forEach(function(c) {
scene.remove(c);
});
}
lastCircles = []; // clear cache
while (1000 > count) {
circle = new THREE.Mesh (circleGeometry, material);
lastCircles.push(circle); // add each circle to cache
scene.add (circle);
circle.position.set(count,count,count)
count ++;
}
}
I'm trying to animate between two complex paths using Paper.js and Tween.js. I've gotten pretty close, I can move all of the points in the path to the correct final positions, but I'm having problems with the handleIn and handleOut for each segment. It doesn't seem to be updating them.
Here's my code: http://codepen.io/anon/pen/rVBaZV?editors=101
var endPathData = 'M740,342.9c-32,...etc...';
var endPath = new Path(endPathData);
endPath.fillColor = '#4CC7A4';
beginPathData = 'M762.8,262.8c-48,...etc...';
var beginPath = new Path(beginPathData);
beginPath.fillColor = '#FFC1D1';
var numberOfSegments = beginPath.segments.length;
for (var i = 0; i < numberOfSegments; i++) {
var tween = new TWEEN.Tween(beginPath.segments[i].point)
.to({
x: endPath.segments[i].point.x,
y: endPath.segments[i].point.y
}, 3000)
.easing(TWEEN.Easing.Linear.None)
.start();
}
view.draw();
view.onFrame = function (event) {
TWEEN.update();
};
I'd like the pink path to end up exactly like the green one, but now I'm stuck. Is there anyway to achieve this?
You need to tween the handles too.
Each segment has two handles: segment.handleIn and segment.handleOut
in your example code you tween the segment.point (the segments position) resulting in the right location of the segments.
I don't know your Tween library, so it is up to you to implement it.
But It looks like you can add to more new tween one for the
beginPath.segments[i].handleIn
and one for the
beginPath.segments[i].handleOut
You can easily check that your code is right by letting paperjs smooth your path and taking care of the handles. By updating the onFrame function like this:
view.onFrame = function (event) {
TWEEN.update();
beginPath.smooth();
endPath.smooth();
};
and this results in the same shaped path.
In three.js I have a space ship at xyz, And id like it to fly towards a mesh object of a planet at xyz.
I cannot for the life of me figure this out.
Needs to travel in a straight line, at a speed constant towards the planet.
updateFcts.push(function(delta, now){
if (shipArr[0]===undefined){
}else{
//create two vector objects
var xd = new THREE.Vector3(marsMesh.position.x,marsMesh.position.y,marsMesh.position.z);
var yd = new THREE.Vector3(shipArr[0].position.x,shipArr[0].position.y,shipArr[0].position.z);
//find the distance / hypotnuse to the xyz location
var dicks = shipArr[0].position.distanceTo(marsMesh.position);
var subvec = new THREE.Vector3();
subvec = subvec.subVectors(xd,yd);
//sub subtrac the 3 vectors.
var hypotenuse = dicks;
console.log(hypotenuse);
//1.5 stops it at 1.5 distance from the target planet
if(hypotenuse > 1.5){
//console.log(hypotenuse);
shipArr[0].position.y += .0001*200*(subvec.y/hypotenuse);
shipArr[0].position.x += .0001*200*(subvec.x/hypotenuse);
shipArr[0].position.z += .0001*200*(subvec.z/hypotenuse);
}else{
//within fire range
alert ("FIIIIIRE");
}
}
})
I tried tween.js and was unhappy so i coded a function myself.
You could use https://github.com/sole/tween.js which is focused on that.
A very basic example http://jsfiddle.net/qASPe (square will fly towards sphere after 5s) with mainly this code:
new TWEEN.Tween(ship.position)
.to(planet.position, 700) // destination, duration
.start();
Later, you might want to use a THREE.Curve, or other Path mechanism, as a "flying" path like here http://jsfiddle.net/aevdJ/12
// create a path
var path = new THREE.SplineCurve3([
ship.position,
// some other points maybe? representing your landing/takeoff trajectory
planet.position
]);
new TWEEN.Tween({ distance:0 })
.to({ distance:1 }, 3000) // destination, duration
.onUpdate(function(){
var pathPosition = path.getPointAt(this.distance);
ship.position.set(pathPosition.x, pathPosition.y, pathPosition.z);
})
.start();
In all cases, do not forget to add this line in your update function
TWEEN.update();