I have a CesiumJS function that I want to be executed after and only after having performed a zoomTo(), which makes me sure the terrain has been fully loaded (as stated in the doc)!
It's because this function should actually compute the intersection between a ray and the terrain, so the terrain has to be fully loaded for its execution to be successful.
In the current state, the following code returns: null super quickly (it doesn't wait at all for the terrain):
e.g.:
var viewer = new Cesium.Viewer('cesiumContainer', {
imageryProvider : new Cesium.BingMapsImageryProvider({
url : 'https://dev.virtualearth.net',
key : $(BING_KEY),
mapStyle : Cesium.BingMapsStyle.AERIAL
}),
terrainProvider: new Cesium.CesiumTerrainProvider({
url : 'https://api.maptiler.com/tiles/terrain-quantized-mesh/?key$(MKEY)'
});
baseLayerPicker : false,
infoBox : false,
});
var p0 = [10.7465, 48.3147, 1500];
var p1 = [10.7475, 48.3127, 1000];
var start = new Cesium.Cartesian3.fromDegrees(...p0);
var end = new Cesium.Cartesian3.fromDegrees(...p1);
var entity = viewer.entities.add({
polyline : {
positions : Cesium.Cartesian3.fromDegreesArrayHeights([
...(p0.concat(p1))
]),
width : 4,
material : new Cesium.PolylineGlowMaterialProperty({
glowPower : 1,
color : Cesium.Color.GREEN
})
}
});
viewer.zoomTo(viewer.entities);
// then run this function:
function pickGlobeIntersection(viewer, p0, p1) {
var direction = new Cesium.Cartesian3();
Cesium.Cartesian3.subtract(p1, p0, direction);
console.log("direction: ", direction);
Cesium.Cartesian3.normalize(direction, direction);
var ray = new Cesium.Ray(p0, direction);
var hitPos = viewer.scene.globe.pick(ray, viewer.scene);
if ((hitPos !== undefined) && (hitPos !== null)) {
console.log("hitPos: ", hitPos);
return hitPos;
} else {
console.log("hitPos is null!");
return null;
}
}
pickGlobeIntersection(viewer, start, end);
(replace the viewer by the default one if code is used in the sandcastle)
How can I make sure the function is executed only after the terrain has been fully loaded?
Related
When I create a sprite, OrbitControls works perfectly.
But when I switch to FirstPersonControls, everything freezes and the console gives this error:
Uncaught TypeError: Cannot read property 'matrixWorld' of undefined
at Sprite.raycast (three.js:26051)
at intersectObject (three.js:44583)
at Raycaster.intersectObjects (three.js:44658)
at animate (mainview.php?project_id=46&tipo=1:936)
Raycasting code:
if (firstorbit) {
if (l % 5 == 0) {
var vector = new THREE.Vector3(0, -1, 0);
vector = camera.localToWorld(vector);
vector.sub(camera.position);
var raycasterGround = new THREE.Raycaster(camera.position, vector);
var intersectsGround = raycasterGround.intersectObjects(scene.children, true);
if (intersectsGround.length > 0) {
if (intersectsGround[0].distance < 1.21) {
camera.position.y = (camera.position.y + (1.21 - intersectsGround[0].distance));
}
if (intersectsGround[0].distance > 1.36 && intersectsGround[0].distance < 1.45) {
camera.position.y = (camera.position.y - (intersectsGround[0].distance - 1.215));
}
}
}
if (l % 3 == 0) {
var vector1 = new THREE.Vector3(0, 0, -1);
vector1 = camera.localToWorld(vector1);
vector1.sub(camera.position);
var raycasterFront = new THREE.Raycaster(camera.position, vector1);
var intersectsFront = raycasterFront.intersectObjects(scene.children, true);
if (intersectsFront.length > 0) {
if (intersectsFront[0].distance < 0.3) {
controls.moveForward = false;
controls.w = false;
} else {
controls.w = true;
}
} else controls.w = true;
}
}
Raycasting code that I use on mouse click to measure something:
function getIntersections( event ) {
var vectorMouse = new THREE.Vector2();
vectorMouse.set(
mouse.x,
mouse.y );
var raycasterClick = new THREE.Raycaster();
raycasterClick.setFromCamera( vectorMouse, camera );
var intersectsClick = raycasterClick.intersectObjects( scene.children,true );
return intersectsClick;
}
I am not sure if the problem is with the sprite or with my raycasting code. But when I remove the sprite, everything works perfectly. And when I remove the Raycasting code, everything also works perfectly.
I have animated a sprite using a sprite sheet and the update function,
like so:
Note: I have dragged the plist into the atlas field of the sprite node (the same node the monster.js script is attached to) in the Ccos Creator UI.
//monster.js
onLoad: function(){
// change monsters face
this.faces['1'] = 'monster1';
this.faces['2'] = 'monster2';
this.faces['3'] = 'Rmonster1';
this.faces['4'] = 'Rmonster2';
}
update: function (dt) {
this.timekeep += dt;
if(this.timekeep > 0.1){
var self = this;
cc.loader.loadRes('monsters', cc.SpriteAtlas, function (err, atlas) {
self.getComponent(cc.Sprite).spriteFrame = atlas.getSpriteFrame(self.faces[self.monstersN]);
});
this.timekeep = 0;
this.monstersN++;
if(this.monstersN > 4){
this.monstersN = 1;
}
}
It actually works fine. I have already thought I should export the cc.loader.loaderRes into the onLoad function and save the atlas as a global var instead of loading every time the update is called.
However…seeing that there are built in animation functions, this can’t be the correct solution. So I tried this:
onLoad: function () {
// change monster face
this.faces['1'] = 'monster1';
this.faces['2'] = 'monster2';
this.faces['3'] = 'Rmonster1';
this.faces['4'] = 'Rmonster2';
var self = this;
cc.loader.loadRes('monsters', cc.SpriteAtlas, function (err, atlas) {
var sprite = self.getComponent(cc.Sprite);
var animFrames = [];
for (var i = 1; i < 4; i++) {
var spriteFrame = atlas.getSpriteFrame(self.faces[i]);
var animFrame = new cc.AnimationFrame();
animFrame.initWithSpriteFrame(spriteFrame, 1, null);
animFrames.push(animFrame);
}
var animation = sprite.Animation.create(animFrames, 0.2, 100);
var animate = sprite.Animate.create(animation);
sprite.runAction(animate);
});
},
I get this error:
cc.AnimationFrame is not a constructor
So then I tried this:
onLoad: function () {
// change monster face
this.faces['1'] = 'monster1';
this.faces['2'] = 'monster2';
this.faces['3'] = 'Rmonster1';
this.faces['4'] = 'Rmonster2';
var self = this;
cc.loader.loadRes('monsters', cc.SpriteAtlas, function (err, atlas) {
self.atlasA = atlas;
});
var sprite = this.getComponent(cc.Sprite);
var animFrames = [];
for (var i = 1; i < 4; i++) {
var spriteFrame = this.atlasA.getSpriteFrame(this.faces[i]);
var animFrame = new cc.AnimationFrame();
animFrame.initWithSpriteFrame(spriteFrame, 1, null);
animFrames.push(animFrame);
}
var animation = sprite.Animation.create(animFrames, 0.2, 100);
var animate = sprite.Animate.create(animation);
sprite.runAction(animate);
},
I get this error:
Cannot read property ‘getSpriteFrame’ of undefined
How can I use cc.animate to change the sprite using the spritesheet I have. All I want to achieve is to move through the plist in the order the images are in the plist, repeated until the monster is put back into the pool it came from.
Here is the solution for anyone who may still be looking.....
cc.AnimationClip.createWithSpriteFrames([sf1, sf2, ...], fps)
I need to get the longitude and latitude of a location from a text file through AJAX then create a map using that information. This is what I have done:
function createMap(){
var request;
if (window.XMLHttpRequest)
{
request = new XMLHttpRequest();
}
if (request)
{
var number = Math.floor( (Math.random() * 3) + 1 );
var url = "text_" + number + ".txt";
request.open("GET", url,true);
request.onreadystatechange = function()
{
if (request.readyState == 4 && request.status == 200)
{
var syd=new google.maps.LatLng(-33.884183, 151.214944);
var woll=new google.maps.LatLng(request.responseText);
function initialize()
{
var mapProp = {
center:syd,
zoom:6,
mapTypeId:google.maps.MapTypeId.ROADMAP
};
var map=new google.maps.Map(document.getElementById("outputAJAX"),mapProp);
var myTrip=[syd,woll];
var flightPath=new google.maps.Polyline({
path:myTrip,
strokeColor:"#0000FF",
strokeOpacity:0.8,
strokeWeight:2
});
flightPath.setMap(map);
}
initialize();
}
}
request.send();
} else {
document.getElementById("outputAJAX").innerHTML = "<span style='font-weight:bold;'>AJAX</span> is not supported by this browser!";
}}
However, the map didn't show up. Do you guys have any suggestion?
A google.maps.LatLng object takes two Numbers as its arguments:
LatLng(lat:number, lng:number, noWrap?:boolean) Creates a LatLng object representing a geographic point. Latitude is specified in degrees within the range [-90, 90]. Longitude is specified in degrees within the range [-180, 180]. Set noWrap to true to enable values outside of this range. Note the ordering of latitude and longitude.
This won't work (you are only passing one argument, a string):
var woll=new google.maps.LatLng(request.responseText);
Assuming request.responseText is a comma separated string containing two numeric values, this should work:
var coordStr = request.responseText;
var coords = coordStr.split(",");
var woll = new google.maps.LatLng(parseFloat(coords[0]),
parseFloat(coords[1]));
proof of concept fiddle
So I have a Flash ActionScript 2 code, which creates a preset amount of enemies, gives enemies stats, and makes them move around randomly. Code:
//Settings
var mapWidth:Number = 550;
var mapHeight:Number = 400;
var enemiesArray:Array = new Array();
var totalEnemies:Number;
var eClip:MovieClip;
//Math functions
function getdistance(x, y, x1, y1)
{
run = x1-x;
rise = y1-y;
return (hyp(run, rise));
}
function hyp(a, b)
{
return (Math.sqrt(a*a+b*b));
}
function resetDirection(mc:MovieClip)
{
mc.roamTime = random(50);
mc.t = mc.roamTime;
mc.roamDistance = random(60)+25;
mc.randomRoamDistanceX = (Math.random()*mc.roamDistance)+mc.xx-(mc.roamDistance/2);
mc.randomRoamDistanceY = (Math.random()*mc.roamDistance)+mc.yy-(mc.roamDistance/2);
mc.newRoamDistance = getdistance(mc._x, mc._y, mc.randomRoamDistanceX, mc.randomRoamDistanceY);
mc.norm = mc.roamSpeed/mc.newRoamDistance;
mc.finalRoamDistanceX = (mc.randomRoamDistanceX-mc.xx)*mc.norm;
mc.finalRoamDistanceY = (mc.randomRoamDistanceY-mc.yy)*mc.norm;
}
//function to move enemies
function moveIt(mc:MovieClip)
{
//reduce roamTime;
mc.t--;
//move enemy to new position
if (getdistance(mc._x, mc._y, mc.randomRoamDistanceX, mc.randomRoamDistanceY)>mc.roamSpeed) {
mc._x += mc.finalRoamDistanceX;
mc._y += mc.finalRoamDistanceY;
}
//rotate enemy
XXXdiff = mc.xx-mc.randomRoamDistanceX;
YYYdiff = -(mc.yy-mc.randomRoamDistanceY);
rrradAngle = Math.atan(YYYdiff/XXXdiff);
if (XXXdiff<0) {
cccorrFactor = 270;
} else {
cccorrFactor = 90;
}
//
mc.ship_mc._rotation = -(rrradAngle*360/(2*Math.PI)+cccorrFactor);
//check if time to reset, based on roamTime
if (mc.t<=0) {
resetDirection(mc);
}
}
//
// Generate Enemies
//
// set and save enemy stats
//
//
// createEnemies(number of enemies you want, movieclip where you want to create the enemies);
//
function createEnemies(amount:Number, targetLocation:MovieClip) {
trace("createEnemies: "+amount);
for (var i = 0; i<amount; i++) {
randomXpos = Math.round(Math.random()*mapWidth);
randomYpos = Math.round(Math.random()*mapHeight);
//add new enemy to map
var newEnemy:MovieClip = targetLocation.attachMovie("enemy1", "enemy1_"+i, targetLocation.getNextHighestDepth());
enemiesArray.push(newEnemy);
//
//set enemy stats
newEnemy.id = i;
newEnemy._x = randomXpos;
newEnemy._y = randomYpos;
//save x and y position
newEnemy.xx = newEnemy._x;
newEnemy.yy = newEnemy._y;
//
newEnemy.roamSpeed = 2
newEnemy.roamTime = random(50);
newEnemy.roamDistance = random(60)+25;
newEnemy.t = 0;
//
newEnemy.myHealth = 10;
newEnemy.myName = "Small Scout";
//
resetDirection(newEnemy);
//target enemy
newEnemy.onPress = function() {
trace("Enemy: "+this.tName+" "+this.id);
target_txt.text = this.myName+": "+this.id+" Health: "+this.myHealth;
};
newEnemy.onEnterFrame = function() {
moveIt(this);
};
}
}
start_btn.onRelease = function() {
if (start_txt.text == "Start") {
//run the create enemies function to start the engine
createEnemies(box_mc.numberOfEnemies.text, map_mc);
//hide start button
start_txt._visible =false;
this._visible = false;
box_mc._visible = false;
}
};
I want program enemies to be grouped (based on fireflies algorithm). My idea is write for loop to define attractiveness, but I don't know how to make my objects move to the most attractiveness. Maybe someone would help me with this problem?
I change this line:
newEnemy.myHealth = 10;
on this
newEnemy.myHealth = Math.round(random(9)+1);
myHealth would be responsible for attractiveness. I try to use code from this site and modificate code to let objects with low attractiveness follow objects with large attractiveness. Also, I want to stop algorith, when they are in the groups.
i dont have the code here so i hope you can understand, i'l edit and add the code when i get home.
I have built a class move that once initialized adds a jquery event (keyDown) to the rendered dom element.
the event checks what key is down in a switch case,
if the key is one of the cases the camera will be moved accordingly.
The camera does move, but for some reason it flickers a bit, like little jumps.
the speed for each camera move is 0.05;
when i did this in anouter app but via a javascript keydown event from the main script (no special class) it worked fine..
any idea why would it do this ?
edit: code
main script :
<script>
var moveMec = null;
var loopProg = null;
var renderer = null;
var scene = null;
var camera = null;
var mesh = null;
var earth = null;
var sun = null;
$(document).ready(
function() {
var container = document.getElementById("container");
renderer = new THREE.WebGLRenderer({ antialias: true } );
renderer.setSize(container.offsetWidth,container.offsetHeight);
container.appendChild(renderer.domElement)
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera( 45,
container.offsetWidth / container.offsetHeight, 1, 4000 );
earth = new Earth();
sun = new Sun({x:-10,y:0,z:20});
scene.add(earth.getEarth);
scene.add(sun.sunLight);
camera.position.set( 0, 0, 3 );
moveMec = new moveMechanics(camera,renderer.domElement)
loopProg = new loopProgram();
loopProg.add(function(){earth.update()});
//loopProg.add(function(){renderer.render( scene, camera );});
loopProg.solarLoop();
}
);
</script>
move script :
var moveMechanics = function (camera,domElement,speed)
{
moveMechanics.camera = camera;
moveMechanics.speed = speed != undefined ? speed : 0.01;
moveMechanics.domElement = domElement;
$(document).keydown(function(event)
{
switch(event.which)
{
case KeyEvent.DOM_VK_W:
camera.position.z -= moveMechanics.speed;
break;
case KeyEvent.DOM_VK_S:
camera.position.z += moveMechanics.speed;
break;
case KeyEvent.DOM_VK_D:
camera.position.x += moveMechanics.speed;
break;
case KeyEvent.DOM_VK_A:
camera.position.x -= moveMechanics.speed;
break;
}
});
}
loop code :
function loopProgram()
{
this.functionsToRun = new Array();
this.solarLoop= function()
{
jQuery.each(loopProg.functionsToRun, function(index,value)
{
value ? value() : null;
});
requestAnimationFrame(loopProg.solarLoop);
}
this.add = function(func)
{
this.functionsToRun[this.functionsToRun.length] = func;
}
}