GoogleEarth-like controls for Three.js - zooming

I've tried unsuccessfully (because of my poor 3D geometry understanding and unfortunate lack of time to dig in) to build a GoogleEarth-like controls for three.js. Maybe someone can help me, or might already have it. Anyways, i think it would be an excellent addition to three.js library.
Here's the specific functionality I am trying to build:
Zoom in with mouse wheel TO MOUSE CURSOR
Rotate around the scene by holding down Shift
Pan by pressing left mouse button.
As a bonus: show a little target icon during 1 and 2 operations above.
I have most trouble with 1, and haven't attempted 2. Panning is easy (there are lots of examples).
Right now I am unable to zoom into the scene so that it stays fixed under the cursor (so I can point at the top right corner of the screen, zoom-in and still see what I had under the cursor).
My thanks in advance,
Alex

I've implemented something similar in a past life. I assume here that you are interacting with a flat plane; conversion of these techniques to a plane tangent to a sphere is left as an exercise for the reader. ;)
Zoom in with mouse wheel TO MOUSE CURSOR
To do this, you'll want to cast a ray into the scene, and note where it hits. You'll then want to translate the eye point of the camera towards that intersection. To feel "correct", you'll want some kind of proportional zoom in instead of fixed steps--for example, each zoom step reduces the distance from the current eye point to the target by 20%, instead of just moving 20 units. This will automatically slow down the camera as it approaches.
Rotate around the scene by holding down Shift
One you hold shift, you'll want left and right mouse movements to orbit about your view point. To do this, you'll need to yaw about an axis perpendicular to your point of intersection. You'll cast a ray into the scene (once shift is held down), note the intersection point, and then rotate your camera's eye point about that axis. Note that you'll need also to reorient the camera to continually point towards that intersection as you rotate, or perhaps to have the eye direction rotate to keep a constant angle with the vector from the eye point to the intersection axis.
Pan by pressing left mouse button.
You simply need to get the eye right vector and eye up vector, and move in the appropriate direction (multiply the mouse dx/dy with the normalized eye right/eye up, and multiply by the timestep for framerate independent movement).
As a bonus: show a little target icon during 1 and 2 operations above.
At the intersection in the scene, add a little object. Once you exit a mode, remove the object.

for your first question you can use this program under mouse wheel
mousewheel = function (event) {
event.preventDefault();
var factor = 15;
var mX = (event.clientX / jQuery(THREE_STUFF.container).width()) * 2 - 1;
var mY = -(event.clientY / jQuery(THREE_STUFF.container).height()) * 2 + 1;
var vector = new THREE.Vector3(mX, mY, 0.1);
vector.unproject(camera);
vector.sub(camera.position);
if (event.deltaY < 0) {
camera.position.addVectors(camera.position, vector.setLength(factor)); trackBallControls.target.addVectors(trackBallControls.target, vector.setLength(factor));
} else {
camera.position.subVectors(camera.position, vector.setLength(factor)); trackBallControls.target.subVectors(trackBallControls.target, vector.setLength(factor));
}
}
I hope this will help you sure.

Related

ActionScript 3 How to make an animation that always goes toward the same point

I have a main object that moves around wherever the mouse is.
How would I make an animation that shoots out other objects from the main object toward receivers that don't move?
Is there an easier way than finding the angle between the main object and the receivers and then sending the animation out that way?
So the shooting animation should rotate depending on where the main object is so that the shooting animations will always reach the target.
You can use TweenLite and just specify the x, y location :
TweenLite.to(bullet, duration, {x:targetX, y:targetY});
You can download it here :
http://www.greensock.com/v12/
You'll probably want to calculate the duration of the tween based on the distance between the objects and how fast you'd like it to move in pixels per second. For example :
var duration:Number = distance / pixelsPerSecond;
That would give you the correct amount of time for the tween.

Flash AS3: Keeping the mouse within certain boundaries

So this one is a tricky one (for me) vital to the development of my project due to the fact that we can't directly modify the position of mouseX and mouseY - they are read-only variables.
Basically, what I want to do is have a player able to move their mouse only within a certain triangular area when a specific instance is active. The latter bit I can manage just fine, however I am having trouble restricting mouse movement -- or apparent mouse movement.
Here's what I have done so far:
1. Assign a library moveclip to the mouseX and mouseY position in the Event.ENTER_FRAME event - although I acknowledge that this should be moved to Mouse.MOUSE_MOVE. (this does not matter yet)
2. Using Corey O'Neils Collision detection kit, do a hit test on the border instances of the area with the crosshair/cursor.
3. Offset the cursor appropriately, and then set a standard Boolean value to false so that the cursor will not keep bouncing back into the cursor over and over.
My problem is, I am not sure what the best way is to go about allowing mouse movement again. Can anyone give me some tips on the best way to do this, or if necessary, point me in another direction where restricting mouse movement is a little easier?
For what it's worth, this is to stop users from aiming in an unrealistic direction with a character in a top-down (ish) shooter.
For those unfamiliar with Corey O'Neil's Collision Detection Kit, I believe it is just a pre-built setup of bitmap (or maybe vector) collision testing - I could be wrong. I'm not sure on the details of how it works, just its basic implementation.
Here is my code regarding mouse movement thus far:
import flash.ui.Mouse;
import flash.events.event
import com.coreyoneil.collision.CollisionList;
Mouse.hide();
var c:crosshair = new crosshair();
addchild(c);
var myCollisionList:CollisionList;
myCollisionList = new CollisionList(c); //sets up detection for the object c
myCollisionList.addItem(mcB); // adds mcB to the list of objects to check c's hittest with
function aim(e:Event) {
var collisions:Array = myCollisionList.checkCollisions();
if (collisions.length>0)
{
hashit = true; // tells the program that the mouse has collided with a boundary
c.x += 1;
c.y += 1;
}
else
{
if (hashit == false)
{
c.x = mouseX;
c.y = mouseY;
}
}
}
Apologies for the code block, but I figure it is best to show all relevant code -- I'm not sure about the complexity of this issue due to the read-only nature of the mouse's X and Y position.
Also, I'm looking for a possible solution which will not be clunky - that is, as soon as the mouse is back in the area, mouse movement will be smooth as it is originally, and where the cursor will still be matching the mouse position (meaning, the cursor is ALWAYS relevant to the mouse and will not change position should the mouse leave the boundaries).
Could anyone please give me some pointers? Sorry for the long question. I gather there might be a bit to get my head around here, being relatively new to AS3 - but I still feel this is a problem I can get past, if one of you can show me the right direction and help me with both the logic and programming side of things slightly.
Here is a diagram of my stage to clarify the boundary areas etc.
Thanks very much for any help in advance, I really do appreciate it!
Cheers, Harry.
How about trying getObjectsUnderPoint which returns an array of objects under a certain point.
If your triangle object is within the array the cursor must be above it.
var pt:Point = new Point(c.x, c.y);
var objects:Array = stage.getObjectsUnderPoint(pt);
if (objects.indexOf(triangleObject) > -1) {
trace("still within bounds");
}
The workaround here could be to hide the system mouse cursor and add a bespoke cursor movieclip to the stage.
Using a MOUSE_MOVE event listener attached to the stage, set the bespoke cursor movieclip to match the stage.mouseX and stage.mouseY values and also test whether the movieclip is outside your bounds. If so, set it back within your bounds.

Flash - SideScroller Turret Math

I'm working on a side scroller, and for the enemy I'm making a turret. I'm trying to make the turret aim at the player but I cant seem to get it right. Below is a rough sketch of what I want to achieve:
I want the barrel (dark blue), to aim/rotate to its pointing at the player.
I have uploaded a YouTube video of my scene:
http://www.youtube.com/watch?v=eeP47VoX9uA&feature=youtu.be
This is what I have so far (loop):
function enterFrameHandler(e : Event) : void{
_turretBarrel.rotation = Math.atan2(enTarget.x, enTarget.y) * 180/Math.PI;
}
What this does is only rotate the barrel when I jump, and the barrel isn't even aiming at the player, also the barrel doesn't change rotation when I walk on the other side of the turret.
My enTarget.x is always central to the stage and the scene (including the turret) moves around the player left and right (x)... Only the enTarget.y moves (jump/high platform).
I'm slightly new to Flash and ActionScript. If anyone could help me out, or point me in the right direction then that would be great.
Thanks
1) Make sure you got the right numbers and the position of the avatar and the turret are in the same coordinate space. A simple trace of each would do. In this case you probably want the world (relative to stage) position of both clips. Make sure they make sense compared to top left corner of the screen (0, 0).
2) Remember that _turretBarrel.rotation is a rotation that ranges from -180 to 180 so this would need to be taken into consideration when calculating angles.
3) Make sure you use the corresponding degrees/radians where appropriate.
4) force focus on avatar, run the game and see if the bounds looks ok. Then do the same thing with the turret.
Another good thing in general for debugging purposes is to setup some kind of debug graphics. i.e. draw a line of what you think is the direction vector to verify your numbers and calculations.
On a side note:
This is what the majority of programming is; Debugging. Assume nothing but hard facts, get your numbers from the debugger (probably quicker), or trace output. If you're still using the horrible flash professional IDE. I would really recommend getting one with a proper debugger like FlashDevelop (free) or Flash Builder (commercial)
Oliver, it looks like you are calculating the tangens of wrong angle (between player and X-axis). You need something like the following:
function enterFrameHandler(e : Event) : void{
_turretBarrel.rotation = Math.atan2(enTarget.x - barrel.x, enTarget.y - barrel.y) * 180/Math.PI;
}

Mouse interaction with nested movieclips in Away3D

I am building a globe with the countries. I have all of the spheres built and everything works fine. The problem is to get the globe to look right I had to put all of the movieclips into one big moveclip then broke down from there. The problem is I cannot get Away3D to recognize the secondary movieclips. If I apply the listener to the whole sphere it works fine (but that isn't functional). Is there a way to use nested movieclips in away3d?
//what works
var materialMovie:MovieClip = new causticsMovie() as MovieClip;
var causticsMaterial:MovieMaterial = new MovieMaterial( materialMovie);
var sphere:Sphere = new Sphere({material:causticsMaterial, radius:300,segmentsH:18,segmentsW:26, interactive:true});
causticsMaterial.interactive = true;
view.scene.addChild(sphere);
sphere.addEventListener(MouseEvent3D.MOUSE_DOWN, NA);
//what doesn't
world_map.northAfrica_mc.addEventListener(MouseEvent3D.MOUSE_DOWN, NA);
Is there a solution to this problem?
If I understand how 3d engines in flash generally work, this won't be possible. They create a texture from the original movieclip(s) which they then transform. So there are no movieclips left to click on.
There is a couple of ways around this I think. You could transform the click location into polar coordinates (I'm not sure about the maths there, but google should be helpful), and figure out which location was clicked that way.
Or, you could (probably) have a second, invisible sphere (off stage or not added as a child, not sure which will work), where you create a different texture where each country has a different color. You would rotate this to the same angles as the visible sphere. Then, on click, render that to a BitmapData and check the pixel value of the point you clicked (translated so the point on the visible sphere and the invisible sphere are the same). I think this way is the easier of the two, and will have better results.

Actionscript collisions: solving exceptions and strange cases

I have created a collision class to detect collisions using pixels. In my class I've also developed some functions for determining the collsion angle. Based on this I created some examples:
http://megaswf.com/serve/25437/
http://megaswf.com/serve/25436/
(Space to change gravity, right/left to give some speed to the ball.)
As you will probably notice, there are strange things that happen:
When the ball speed is very low
When the direction of the ball is
almost tangent to the obstacle.
collision http://img514.imageshack.us/img514/4059/colisao.png
The above image shows how I calculate the collision angle.
I call the red dots the keypoints. I search for a maximum number of keypoints (normally 4). If I find more then 2 keypoints, I choose the 2 farthest ones (as shown in one of the blue objects). Thats how I then find the normal angle to where in the surface the object collided. I don't know if this is an obsolete way of doing things.
based on that angle, I rotate the speed vector to do the bouncing.
The piece of code to do the maths is here:
static public function newSpeedVector(speedX: Number, speedY: Number, normalAngle: Number): Object{
var vector_angle: Number = Math.atan2(speedY, speedX) * (180/Math.PI);
var rotating_angle: Number = (2*(normalAngle - vector_angle) + 180) % 360;
var cos_ang: Number = Math.cos(rotating_angle/DEGREES_OF_1RAD);
var sin_ang: Number = Math.sin(rotating_angle/DEGREES_OF_1RAD);
var final_speedX: Number = speedX * cos_ang - speedY * sin_ang;
var final_speedY: Number = speedX * sin_ang + speedY * cos_ang;
return {x_speed: final_speedX, y_speed: final_speedY};
}
This is how the new speed vector is calculated...
My question is, has anyone faced this kind of problem or has some idea on how to avoid this from happening?
Without seeing your code, this is the best I can provide.
Collision physics should have some velocity threshold that is considered "stopped". That is, once the velocity gets small enough you should explicitly mark an object as stopped and exempt it from your collision code. This will help stabilize slow moving objects. Trial and error is required for a good threshold.
When a collision happens, it is important to at least attempt to correct any inter-penetration. This is most likely the reason why tangent collisions are behaving strangely. Attempt to move the colliding object away from what it hit in a reasonable manner.
Your method of determining the normal should work fine. Game physics is all about cheating (cheating in a way that still looks good). I take it rotation and friction isn't a part of what you're going for?
Try this. You have the contact normal. When you detect a collision, calculate the penetration depth and move your object along the normal so that is isn't penetrating anymore. You can use the two points you have already calculated to get one point of penetration, you'll need to calculate the other though. For circles it's easy (center point + radius in direction of normal). There are more complex ways of going about this but see if the simple method works well for you.
I have read and recommend this book: Game Physics Engine Development
I did something a little like that and got a similar problem.
What I did is that when the pixels from the bouncing object (a ball in your case) overlap with the pixels from the obstacle, you need to move the ball out of the obstacle so that they are not overlapping.
Say the ball is rolling on the obstacle, before your render the ball again you need to move it back by the amount of 'overlap'. If you know at what angle the ball hit the obstable just move it out along that angle.
You also need to add some damping otherwise the ball will never stop. Take a (very) small value, if the ball velocity is bellow that value, set the velocity to 0.
You can try one more thing, which I think is very effective.
You can make functions such as getNextX() and getNextY()(Which of course give their position coordinated after the next update) in your game objects and Check collision on objects based on their next position instead of their current position.
This way, the objects will never overlap, you'll know when they are about collide and apply your after collision physics gracefully!