How to do this coordinate system operation more efficiently? - javascript

I'm making a 3D game, where the player's back should always be facing the camera and he should move in that direction. I didn't come to the "back facing the camera" part yet, but I believe that it will be simple once I figure out how to move the player in the right direction...
Though it is a 3D coordinate system, height can be ignored (z-axis) because no matter how high the camera is, the player should always be going in the same speed (the camera system is planned to function much like in the game World of Warcraft).
Now, I have summarized my problem to this...
Point (0, 0) is the players position.
Point (x, y) is the camera's position.
The camera is (dx, dy) units away from the player (and because player is at (0, 0), it is also (x, y) units away, although this is a position vector, not a translation one)
Problem: how do I get a point (a, b) in this 2D space that lies on a circle r = 1 but is on the same line as (0, 0) and (x, y)?
Visualization:
By doing this, I should have a 2D vector (a, b), which would, when multiplied by -30, act as the speed for the player.
I know how to do this, but in a very expensive and inefficient way, using the Pythagora's theorem, square roots, and all those out-of-the-question tools (working in Javascript).
Basically, something like this:
c = sqrt(dx*dx + dy*dy); //Get the length of the line
rat = 1/c; //How many times is the desired length (1) bigger than the actual length
a = x*rat;
b = y*rat;
There must be something better!
For reference, I'm making the game in Javascript, using the Three.js engine.

There is nothing to make more efficient here, these calculations are standard stuff for 3D scenes.
Don't optimize prematurely. There is no way this stuff is a bottleneck in your app.
Remember, even if these calculations happen on each render(), they still only happen once every several milliseconds - 17ms assuming 60 FPS, which is a lot. Math.sin() / Math.cos() / Math.sqrt() are plenty efficient, and lots of other calculations happen on each render() that are much more complex.
You'll be just fine with what you have now.

Related

Acceleration over time

Scenario
I am working on a top-down view game in which enemies move towards certain positions. The destination being moved towards will often change drastically - sometimes while the enemy is still in motion towards the previous destination...
I want to achieve movement which is more realistic than linear movement, so there should be some acceleration and deceleration as enemies switch between the destinations.
Steering (direction) is not a factor. You may assume the sprites will move much like a hovercraft, drifting between the destinations as quickly as it can manage with respect to acceleration and deceleration.
For simplicity - lets assume there is only 1 dimension (Y) instead of X and Y... the movement should emulate a car which can only move north or south.
Since we are considering realistic movement in this scenario, you might not be surprised that a maximum speed over time is also a consideration. The enemy should never exceed it's own maximum speed; enemies store their own maximum speed in a variable.
One final consideration is that enemies will not only have a 'maximum speed' value, but it will also have a 'maximum acceleration' value - this would be the thing which guides how quickly each enemy can respond to moving in the opposite direction.
For simplicity, assume that the enemy does not have any movement friction... when it stops accelerating, it just keeps cruising at the current velocity forever.
Example
For context, lets elaborate on the car example. A particular car has:
Maximum speed: 10 meters per second
Maximum acceleration: can reach top speed in 2 seconds
(Other factors like destination y-pos, position y-pos, current velocity, etc)
Just like when I'm driving a car, I imagine all of these values are present, but I can't change them. All I can really change is how much I'm putting my foot on the acceleration/brake. Let's call this the 'throttle'. Like the acceleration pedal in a car, I can change this value to any amount at any time, in no time at all.
I can plant my foot down (throttle=1), let go of the pedal immediately (throttle=0), and even change into reverse and plant my foot down again (throttle=-1). Lets assume these changes in throttle are INSTANT (unlike speed or acceleration, which grow/shrink over TIME)
All that said, I imagine the only value that I really need to calculate is what the throttle should be, since thats the only thing I can control in the vehicle.
So, how then do I know how much throttle to use at any given moment, to arrive as quickly as possible to a destination (like some traffic lights) without overshooting my destination? I will need to know how much to push down the accelerator, briefly not accelerate at all, and then how hard decelerate as I'm closing in on the destination.
Preempted movement
This game will likely have an online component. That said, players will be transmitting their positions over a socket connection... however even the best connection could never achieve sending positions frequently enough to achieve smooth movement - you need interpolation. You need to send the 'velocity' (speed) along with the co-ordinates so that I can assume future positions in the time between packets being received.
For that reason, Tweens are a no-go. There would be no way to send a tween, then accurately inform the other parties at what point along each tween each entity currently is (I mean, I guess it is possible, but horrendously overcomplicated and probably involves rather large packet sends, and is probably also very exploitable in terms of the online component), then you need to consider aborting Tweens as the destinations change, etc.
Don't get me wrong, I could probably already model some very realistic movement with the ease-in/ease-out functionality of Tweens, and it would look great, but in an online setting that would be.. very messy.
How's it look so far?
So, essentially I have established that the primary aspect which needs to be calculated at any time is how much throttle to use. Let's work through my logic...
Imagine a very basic, linear movement over time formula... it would look like this:
Example 1 - position over time
currentDY = 5; // Current 'velocity' (also called Delta Y or 'DY')
currentY += currentDY * time // Current Y pos is increased by movement speed over time.
As you can see, at any given moment, the Y position increases over time due to the 'velocity' or DY (over time). Time is only a factor ONCE, so once we reach the destination we just set the DY to zero. Very sharp unrealistic movement. To smoothen the movement, the velocity ALSO needs to change over time...
Example 2 - velocity over time
throttle = -1
currentDY += throttle * time;
currentY += (currentDY * time);
//Throttle being -1 eventually decelerates the DY over time...
Here, the throttle is '-1' (maximum reverse!), so over time this will reduce the velocity. This works great for realistic acceleration, but provides no realistic anticipation or deceleration.
If we reach the destination this time, we can set the throttle to '0'... but it's too late to brake, so the resulting enemy will just keep moving past the target forever. We could throttle = '1' to go back, but we'll end up swinging back and forth forever.
(Also note that the maximum acceleration and speed isn't even a factor yet - it definately needs to be! The enemy cannot keep ramping up their speed forever; velocity delta AND ALSO acceleration delta need to have limits).
All that said, it's not enough to simply change velocity over time, but we also need be able to anticipate how much to decelerate (i.e. 'backwards throttle') BEFORE IT HAPPENS. Here's what I've got so far, and I'm practically certain this is the wrong approach...
Example 3 - throttle over time?? (I'm stuck)
guideY = currentY + (currentDY * (timeScale * 3000));
dist = endY - guideY;
throttle = Math.max(-1, Math.min(1, dist / 200));
currentDY += throttle * time;
currentY += (currentDY * time);
As you can see, this time we attempt to anticipate how much throttle to use by guessing where the enemies position will be in an arbitrary time in the future (i.e. 3 seconds). If the guideY went past the destination, we know that we have to start BRAKING (i.e. reducing speed to stop on top of the destination). By how much - depends on how far away the enemies future position is (i.e. throttle = dist / 200;)
Here's is where I gave up. Testing this code and changing the values to see if they scale properly, the enemy always swings way over the destination, or takes far too long to 'close in' on the destination.
I feel like this is the wrong approach, and I need something more accurate. It feels like I need an intersection to correctly anticipate future positions.
Am I simply using the wrong values for the 3 seconds and dist / 200, or am I not implementing a fully working solution here?
Presently, compared to the linear movement, it always seems to take 8 times longer to arrive at the target position. I haven't even reached the point of implementing maximum values for DeltaVelocity or DeltaAcceleration yet - the accepted solution MUST consider these values despite not being present in my JSFiddle below...
Test my logic
I've put all my examples in a working JSFiddle.
JSFiddle working testbed
(Click the 'ms' buttons below the canvas to simulate the passing of time. Click a button then press+hold Return for very fast repetition)
The sprite is initially moving in the 'wrong' direction - this is intended for testing robustness - It assumes an imaginary scenario where we just finished moving as fast as possible toward an old destination far lower on the screen, and now we need to suddenly start moving up...
As you can see, my third example (see the update function), the time for the sprite to 'settle' at the desired location takes far longer than it should. My math is wrong. I can't get my head around what is needed here.
What should the throttle be at any given time? Is using throttle even a correct approach? Your assistance is very appreciated.
Tiebreaker
Alright, I've been stuck on this for days. This question is going up for some phat bounty.
If a tiebreaker is required, the winner will need to prove the math is legit enough to be tested in reverse. Here's why:
Since the game also comprises of a multiplayer component, enemies will be transmitting their positions and velocities.
As hacking protection, I will eventually need a way to remotely 'check' if the velocity and position at between any two sample times is possible
If the movement was too fast based on maximum velocity and acceleration, the account will be investigated etc. You may assume that the game will know the true maximum acceleration and velocity values of the enemies ahead of time.
So, as well as bounty, you can also take satisfaction in knowing your answer will contribute to ruining the lives of filthy video game cheaters!
Edit 2: Fiddle added by answer author; adding into his answer in case anyone else finds this question: http://jsfiddle.net/Inexorably/cstxLjqf/. Usage/math explained further below.
Edit 1: Rewritten for clarification received in comments.
You should really change your implementation style.
Lets say that we have the following variables: currentX, currentY, currentVX, currentVY, currentAX, currentAY, jerk.
currentVX is what would have been your currentDX. Likewise, currentAX is the x component of your delta velocity value (accel is derivative of velocity).
Now, following your style, we're going to have a guideX and a guideY. However, there is another problem with how you're doing this: You are finding guideY by predicting the target's position in three seconds. While this is a good idea, you're using three seconds no matter how close you are to the target (no matter how small dist is). So when the sprite is 0.5 seconds from the target, it's going to still be moving towards the target's estimated position (three seconds into the future). This means it won't actually be able to hit the target, which seems to be the problem that you implied.
Moving on, recall the previous variables that I mentioned. Those are the current variables -- ie, they will be updated at every call after some seconds have been passed (like you have been doing before). You also mentioned a desire to have maxV, and maxA.
Note that if you have a currentVX of 5 and a currentVY of 7, the velocity is (5^2+7^2)^0.5. So, what you're going to want to do each time you're updating the 'current' archetype of variables is before updating the value, see if the magnitude (so sqrt(x^2+y^2) of those variables like I showed with velocity) will exceed the respective maxV, maxA, or jmax values that you have set as constants.
I'd also like to improve how you generate your guide values. I'm going to assume that the guide can be moving. In this case, the target will have the values listed above: x, y, vx, vy, ax, ay, jx, jy. You can name these however you'd like, I'm going to use targetX, targetY... etc to better illustrate my point.
From here you should be finding your guide values. While the sprite is more than three seconds away from the target, you may use the target's position in three seconds (note: I recommend setting this as a variable so it is simple to modify). For this case:
predictionTime = 3000*timescale; //You can set this to however many seconds you want to be predicting the position from.
If you really wanted to, you could smooth the curve using integration functions or loops for the guide values to get a more accurate guide value from the target values. However, this is not a good idea because if you ever implement multiple targets / etc, it could have a negative impact on performance. Thus, we will use a very simple estimation that is pretty accurate for being such low cost.
if (sprite is more than predictionTime seconds away from the target){
guideX = targetX + predictionTime * targetVX;
guideY = targetY + predictionTime * targetVY;
}
Note that we didn't account for the acceleration and jerk of the target in this, it's not needed for such a simple approximation.
However, what if the sprite is lese than predictionTime seconds away from the target? In this case we want to start increasingly lessening our predictionTime values.
else{
guideX = targetX + remainingTime * targetVX;
guideY = targetY + remainingTime * targetVY;.
}
Here you have three choices on finding the value of remaining time. You can set remainingTime to zero, making the guide coordinates the same as the targets. You can set remainingTime to be sqrt((targetX-currentX)^2+(targetY-currentY))/(sqrt(currentVX)^2+(currentVY)^2), which is basically distance / time in 2d, a cheap and decent approximation. Or you can use for loops as mentioned before to simulate an integral to account for the changing velocity values (if they are deviating from maxV). However, generally you will be remaining at or close to maxV, so this is not really worth the expense. Edit: Also, I'd also recommend setting remainingTime to be 0 if it is less than some value (perhaps about 0.5 or so. This is because you don't want hitbox issues because your sprite is following guide coordinates that have a slight offset (as well as the target moving in circles would give it a larger velocity value while changing direction / essentially a strong evasion tactic. Maybe you should add something in specifically for that.
We now have the guideX and guideY values, and account for getting very close to a moving target having an effect on how far from the target the guide coordinates should be placed. We will now do the 'current' value archetype.
We will update the lowest derivative values first, check to see if they are within bounds of our maximum values, and then update the next lowest and etc. Note that JX and JY are as mentioned before to allow for non constant acceleration.
//You will have to choose the jerk factor -- the rate at which acceleration changes with respect to time.
//We need to figure out what direction we're going in first. Note that the arc tangent function could be atan or whatever your library uses.
dir = arctan((guideY-currentY)/(guideX-currentX));
This will return the direction as an angle, either in radians or degree depending on your trig library. This is the angle that your sprite needs to take to go in the direction of guide.
t = time; //For ease of writing.
newAX = currentAX + jerk*t*cos(dir);
newAY = currentAY + jerk*t*sin(dir);
You may be wondering how the newAx value will ever decrease. If so, note that cos(dir) will return negative if guide is to the left of the target, and likewise sin(dir) will return negative if the sprite needs to go down. Thus, also note that if the guide is directly below the sprite, then newAx will be 0 and newAY will be a negative value because it's going down, but the magnitude of acceleration, in other words what you compare to maxA, will be positive -- as even if the sprite is moving downwards, it's not moving at negative speed.
Note that because cos and sin are of the same library as atan presumably, so the units will be the same (all degrees or all radians). We have a maximum acceleration value. So, we will check to make sure we haven't exceeded that.
magnitudeA = sqrt(newAX^2+newAY^2);
if (magnitudeA > maxA){
currentAX = maxA * cos(dir);
currentAY = maxA * sin(dir);
}
So at this point, we have either capped our acceleration or have satisfactory acceleration components with a magnitude less than maxA. Let us do the same for velocity.
newVX = currentVX + currentAX*t;
newVY = currentVY + magnitudeA*t*sin(dir);
Note that I have included two ways to find the velocity components here. Either one works, I'd recommend choosing one and using it for both x and y velocity values for simplicity. I just wanted to highlight the concept of magnitude of acceleration.
magnitudeV = sqrt(newVX^2+newVY^2);
if (magnitudeV > maxV){
currentVX = maxV * cos(dir);
currentVY = maxV * sin(dir);
}
We'd also like to stop boomeranging around our target. However, we don't want to just say slow down alot like you did in your JSFiddle, because then if the target is moving it will get away (lol). Thus, I suggest checking how close you are, and if you are in a certain proximity, reduce your speed linearly with distance with an offset of the target's speed. So set closeTime to something small like 0.3 or what ever feels good in your game.
if (remainingTime < closeTime){
//We are very close to the target and will stop the boomerang effect. Note we add the target velocity so we don't stall while it's moving.
//Edit: We should have a min speed for the enemy so that it doesn't slow down too much as it gets close. Lets call this min speed, relative to the target.
currentVX = targetVX + currentVX * (closeTime - remainingTime);
currentVY = targetVY + currentVY * (closeTime - remainingTime);
if (minSpeed > sqrt(currentVX^2+currentVY^2) - sqqrt(targetVX^2-targetVY^2)){
currentVX = minSpeed * cos(dir);
currentVY = minSpeed * sin(dir);
}
}
magnitudeV = sqrt(currentVX^2+currentVY^2);
At this point we have good values for velocity too. If you going to put in a speedometer or check the speed, you're interested in magnitudeV.
Now we do the same for position. Note you should include checks that the position is good.
newX = currentX + currentVX*t;
newY = currentY + currentVY*t;
//Check if x, y values are good.
current X = newX; currentY = newY;
Now everything has been updated with the good values, and you may write to the screen.

How does Three.js store direction?

i'm writing a server for a game me and my friends are making. I want to keep the direction a certain player is looking at in a 3D plane in a variable. I was considering having it an object with two variables of radians, i.e vertical angle and horizontal angle. But my friend told me to store it the way Three.js stores it because it would make his life easier. Could anybody help me out here?
You should brush up on Math for Game Developers series: https://www.youtube.com/watch?v=sKCF8A3XGxQ&list=PLW3Zl3wyJwWOpdhYedlD-yCB7WQoHf-My&index=1
Specifically, using vectors. You should store the orientation / facing angle of your characters or entities as a Vector3, or a 3 dimensional vector. In THREE.js, that's new THREE.Vector3( x, y, z )
To get the direction of object A to object B, relative to A you would do:
var direction = posB.clone().sub( posA )
This clones position B so we don't mess it up by subtraction, and then immediately subtract it by A.
However you'll notice how the vector now has some length. This is often undesirable in calculations, for example if you wanted to multiply this direction by something else say, a thrust force. In this case, we need to normalize the vector:
direction.normalize()
Now you can do fun stuff like:
posA.add( direction.clone().multiplyScalar( 10.0 ) );
This will move posA in the direction towards posB, 10 units of space.

JavaScript "pixel"-perfect collision detection for rotating sprites using math (probably linear algebra)

I'm making a 2D game in JavaScript. For it, I need to be able to "perfectly" check collision between two sprites which have x/y positions (corresponding to their centre), a rotation in radians, and of course known width/height.
After spending many weeks of work (yeah, I'm not even exaggerating), I finally came up with a working solution, which unfortunately turned out to be about 10,000x too slow and impossible to optimize in any meaningful manner. I have entirely abandoned the idea of actually drawing and reading pixels from a canvas. That's just not going to cut it, but please don't make me explain in detail why. This needs to be done with math and an "imaginated" 2D world/grid, and from talking to numerous people, the basic idea became obvious. However, the practical implementation is not. Here's what I do and want to do:
What I already have done
In the beginning of the program, each sprite is pixel-looked through in its default upright position and a 1-dimensional array is filled up with data corresponding to the alpha channel of the image: solid pixels get represented by a 1, and transparent ones by 0. See figure 3.
The idea behind that is that those 1s and 0s no longer represent "pixels", but "little math orbs positioned in perfect distances to each other", which can be rotated without "losing" or "adding" data, as happens with pixels if you rotate images in anything but 90 degrees at a time.
I naturally do the quick "bounding box" check first to see if I should bother calculating accurately. This is done. The problem is the fine/"for-sure" check...
What I cannot figure out
Now that I need to figure out whether the sprites collide for sure, I need to construct a math expression of some sort using "linear algebra" (which I do not know) to determine if these "rectangles of data points", positioned and rotated correctly, both have a "1" in an overlapping position.
Although the theory is very simple, the practical code needed to accomplish this is simply beyond my capabilities. I've stared at the code for many hours, asking numerous people (and had massive problems explaining my problem clearly) and really put in an effort. Now I finally want to give up. I would very, very much appreciate getting this done with. I can't even give up and "cheat" by using a library, because nothing I find even comes close to solving this problem from what I can tell. They are all impossible for me to understand, and seem to have entirely different assumptions/requirements in mind. Whatever I'm doing always seems to be some special case. It's annoying.
This is the pseudo code for the relevant part of the program:
function doThisAtTheStartOfTheProgram()
{
makeQuickVectorFromImageAlpha(sprite1);
makeQuickVectorFromImageAlpha(sprite2);
}
function detectCollision(sprite1, sprite2)
{
// This easy, outer check works. Please ignore it as it is unrelated to the problem.
if (bounding_box_match)
{
/*
This part is the entire problem.
I must do a math-based check to see if they really collide.
These are the relevant variables as I have named them:
sprite1.x
sprite1.y
sprite1.rotation // in radians
sprite1.width
sprite1.height
sprite1.diagonal // might not be needed, but is provided
sprite2.x
sprite2.y
sprite2.rotation // in radians
sprite2.width
sprite2.height
sprite2.diagonal // might not be needed, but is provided
sprite1.vectorForCollisionDetection
sprite2.vectorForCollisionDetection
Can you please help me construct the math expression, or the series of math expressions, needed to do this check?
To clarify, using the variables above, I need to check if the two sprites (which can rotate around their centre, have any position and any dimensions) are colliding. A collision happens when at least one "unit" (an imagined sphere) of BOTH sprites are on the same unit in our imaginated 2D world (starting from 0,0 in the top-left).
*/
if (accurate_check_goes_here)
return true;
}
return false;
}
In other words, "accurate_check_goes_here" is what I wonder what it should be. It doesn't need to be a single expression, of course, and I would very much prefer seeing it done in "steps" (with comments!) so that I have a chance of understanding it, but please don't see this as "spoon feeding". I fully admit I suck at math and this is beyond my capabilities. It's just a fact. I want to move on and work on the stuff I can actually solve on my own.
To clarify: the 1D arrays are 1D and not 2D due to performance. As it turns out, speed matters very much in JS World.
Although this is a non-profit project, entirely made for private satisfaction, I just don't have the time and energy to order and sit down with some math book and learn about that from the ground up. I take no pride in lacking the math skills which would help me a lot, but at this point, I need to get this game done or I'll go crazy. This particular problem has prevented me from getting any other work done for far too long.
I hope I have explained the problem well. However, one of the most frustrating feelings is when people send well-meaning replies that unfortunately show that the person helping has not read the question. I'm not pre-insulting you all -- I just wish that won't happen this time! Sorry if my description is poor. I really tried my best to be perfectly clear.
Okay, so I need "reputation" to be able to post the illustrations I spent time to create to illustrate my problem. So instead I link to them:
Illustrations
(censored by Stackoverflow)
(censored by Stackoverflow)
OK. This site won't let me even link to the images. Only one. Then I'll pick the most important one, but it would've helped a lot if I could link to the others...
First you need to understand that detecting such collisions cannot be done with a single/simple equation. Because the shapes of the sprites matter and these are described by an array of Width x Height = Area bits. So the worst-case complexity of the algorithm must be at least O(Area).
Here is how I would do it:
Represent the sprites in two ways:
1) a bitmap indicating where pixels are opaque,
2) a list of the coordinates of the opaque pixels. [Optional, for speedup, in case of hollow sprites.]
Choose the sprite with the shortest pixel list. Find the rigid transform (translation + rotation) that transforms the local coordinates of this sprite into the local coordinates of the other sprite (this is where linear algebra comes into play - the rotation is the difference of the angles, the translation is the vector between upper-left corners - see http://planning.cs.uiuc.edu/node99.html).
Now scan the opaque pixel list, transforming the local coordinates of the pixels to the local coordinates of the other sprite. Check if you fall on an opaque pixel by looking up the bitmap representation.
This takes at worst O(Opaque Area) coordinate transforms + pixel tests, which is optimal.
If you sprites are zoomed-in (big pixels), as a first approximation you can ignore the zooming. If you need more accuracy, you can think of sampling a few points per pixel. Exact computation will involve a square/square collision intersection algorithm (with rotation), more complex and costly. See http://en.wikipedia.org/wiki/Sutherland%E2%80%93Hodgman_algorithm.
Here is an exact solution that will work regardless the size of the pixels (zoomed or not).
Use both a bitmap representation (1 opacity bit per pixel) and a decomposition into squares or rectangles (rectangles are optional, just an optimization; single pixels are ok).
Process all rectangles of the (source) sprite in turn. By means of rotation/translation, map the rectangles to the coordinate space of the other sprite (target). You will obtain a rotated rectangle overlaid on a grid of pixels.
Now you will perform a filling of this rectangle with a scanline algorithm: first split the rectangle in three (two triangles and one parallelogram), using horizontal lines through the rectangle vertexes. For the three shapes independently, find all horizontal between-pixel lines that cross them (this is simply done by looking at the ranges of Y values). For every such horizontal line, compute the two intersections points. Then find all pixel corners that fall between the two intersections (range of X values). For any pixel having a corner inside the rectangle, lookup the corresponding bit in the (target) sprite bitmap.
No too difficult to program, no complicated data structure. The computational effort is roughly proportional to the number of target pixels covered by every source rectangle.
Although you have already stated that you don't feel rendering to the canvas and checking that data is a viable solution, I'd like to present an idea which may or may not have already occurred to you and which ought to be reasonably efficient.
This solution relies on the fact that rendering any pixel to the canvas with half-opacity twice will result in a pixel of full opacity. The steps follow:
Size the test canvas so that both sprites will fit on it (this will also clear the canvas, so you don't have to create a new element each time you need to test for collision).
Transform the sprite data such that any pixel that has any opacity or color is set to be black at 50% opacity.
Render the sprites at the appropriate distance and relative position to one another.
Loop through the resulting canvas data. If any pixels have an opacity of 100%, then a collision has been detected. Return true.
Else, return false.
Wash, rinse, repeat.
This method should run reasonably fast. Now, for optimization--the bottleneck here will likely be the final opacity check (although rendering the images to the canvas could be slow, as might be clearing/resizing it):
reduce the resolution of the opacity detection in the final step, by changing the increment in your loop through the pixels of the final data.
Loop from middle up and down, rather than from the top to bottom (and return as soon as you find any single collision). This way you have a higher chance of encountering any collisions earlier in the loop, thus reducing its length.
I don't know what your limitations are and why you can't render to canvas, since you have declined to comment on that, but hopefully this method will be of some use to you. If it isn't, perhaps it might come in handy to future users.
Please see if the following idea works for you. Here I create a linear array of points corresponding to pixels set in each of the two sprites. I then rotate/translate these points, to give me two sets of coordinates for individual pixels. Finally, I check the pixels against each other to see if any pair are within a distance of 1 - which is "collision".
You can obviously add some segmentation of your sprite (only test "boundary pixels"), test for bounding boxes, and do other things to speed this up - but it's actually pretty fast (once you take all the console.log() statements out that are just there to confirm things are behaving…). Note that I test for dx - if that is too large, there is no need to compute the entire distance. Also, I don't need the square root for knowing whether the distance is less than 1.
I am not sure whether the use of new array() inside the pixLocs function will cause a problem with memory leaks. Something to look at if you run this function 30 times per second...
<html>
<script type="text/javascript">
var s1 = {
'pix': new Array(0,0,1,1,0,0,1,0,0,1,1,0),
'x': 1,
'y': 2,
'width': 4,
'height': 3,
'rotation': 45};
var s2 = {
'pix': new Array(1,0,1,0,1,0,1,0,1,0,1,0),
'x': 0,
'y': 1,
'width': 4,
'height': 3,
'rotation': 90};
pixLocs(s1);
console.log("now rotating the second sprite...");
pixLocs(s2);
console.log("collision detector says " + collision(s1, s2));
function pixLocs(s) {
var i;
var x, y;
var l1, l2;
var ca, sa;
var pi;
s.locx = new Array();
s.locy = new Array();
pi = Math.acos(0.0) * 2;
var l = new Array();
ca = Math.cos(s.rotation * pi / 180.0);
sa = Math.sin(s.rotation * pi / 180.0);
i = 0;
for(x = 0; x < s.width; ++x) {
for(y = 0; y < s.height; ++y) {
// offset to center of sprite
if(s.pix[i++]==1) {
l1 = x - (s.width - 1) * 0.5;
l2 = y - (s.height - 1) * 0.5;
// rotate:
r1 = ca * l1 - sa * l2;
r2 = sa * l1 + ca * l2;
// add position:
p1 = r1 + s.x;
p2 = r2 + s.y;
console.log("rotated pixel [ " + x + "," + y + " ] is at ( " + p1 + "," + p2 + " ) " );
s.locx.push(p1);
s.locy.push(p2);
}
else console.log("no pixel at [" + x + "," + y + "]");
}
}
}
function collision(s1, s2) {
var i, j;
var dx, dy;
for (i = 0; i < s1.locx.length; i++) {
for (j = 0; j < s2.locx.length; j++) {
dx = Math.abs(s1.locx[i] - s2.locx[j]);
if(dx < 1) {
dy = Math.abs(s1.locy[i] - s2.locy[j]);
if (dx*dx + dy+dy < 1) return 1;
}
}
}
return 0;
}
</script>
</html>

Determining the point and angle at which two circles intersect.

I have recently started playing with canvas after seeing how easy it can be. My first project was just to keep a circle in its boundaries as it moves around. I made a few more things involving the movement of circles and now...
I'm currently working on bouncing two circles off of each other when they hit. You can see the example of that here: http://jsfiddle.net/shawn31313/QQMgm/7/
However, I would like to use a little more real world physics. At the moment, when the circles hit each other they just reverse their path.
As shown here:
// Dont be confused, this is just the Distance Formula
// We compare the distance of the two circles centers to the sum of the radii of the two
// circles. This is because we want to check when they hit each other on the surface
// and not the center.
var distance = Math.sqrt(Math.pow(c1.x - c2.x, 2) + Math.pow(c1.y - c2.y, 2));
var r1 = c1.rad;
var r2 = c2.rad;
if (distance < r1 + r2) {
// Change the slope of both circle
// I would like to figure out a more effecience way of bouncing the circles back
// However, I have no idea how to determine the angle the ball was struck,
// and with that information bounce it off at that angle
c1.xi = -c1.xi; // path is reversed
c1.yi = -c1.yi;
c2.xi = -c1.xi;
c2.yi = -c1.yi;
}
However, I would like the circles to go in opposite direction determined by the point and angle of intersection.
I am only in the 9th grade and not sure how the formula for something like this would look. But I know that it is possible because this kind of physics is present in many games. An example would be an 8-ball game. When the balls hit each other, they move across the table according to how the balls hit each other.
I would appreciate any tips on how to do this or if I should wait until I have a stronger understanding of Physics and Math in general.
too bad we can't draw a very simple scheme.
As far as physics is concerned, you know that the total momentum is conserved, see
http://en.wikipedia.org/wiki/Momentum
There is a good illustration and formulas here http://en.wikipedia.org/wiki/Elastic_collision#Two-_and_three-dimensional
You can simplify formulas if the two object have the same weight.
so now, let's consider the reference frame in which c2 is fixed and center in (0,0).
c1 velocity in this reference would be :
c1.xfi=c1.xi-c2.xi
c1.yfi=c1.yi-c2.yi
Now you have a collision when the distance between the two is the sum of radius. Consider the tangent plane of the two circles.
You now have to decompose the velocity of c1 into a tangent component, which is conserved, and a perpendicular (following the line between c1 and c2), which is transfered to c2.
Then you need to go back to your original reference frame.
(sorry i didn't give you the exact formulas but they are on the links I provided)
If I were doing this myself, I would implement the motion using Newtons law of restitution. Essentially this is a coefficient that relates approach and separation speed of 2 particles before/after impact and it has a value that depends on the material properties of your particles.
Your analysis will essentially amount to identifying the point of impact, then breaking down the approach velocities into components that are parallel and perpendicular to the line of centres of the circle at the point of impact.
The momentum of the particles is conserved perpendicular to the line of centres (so the velocities in that direction remain unchanged by the collision) and the law of restitution applies to the velocities parallel to the line of centres. Thus if you fix the coefficient of restitution (it has to be between 0 and 1) to some value of your choice you can use this law to calculate the separation speeds along the line of centres of your particles after collision using the value of the approach speeds.
If your particles are all of the same mass and radius then the calculations become simpler. You can model elastic collisions by setting the coefficient to 1 (this indicates that separation speed of the particles is the same as the approach speed) which is probably the easiest place to start. By changing the value you will see different behaviour between particles after collisions.
Sorry not to be able to write this all down in formula for you, but this is not really the appropriate place for it. Living in the UK I have no idea what "9th grade" is so I can't assess if the above is too advanced for your current level of education. Here in the UK this type of problem would typically be covered at A-level mathematics education level.
Hopefully though it will give you an indication of the terms and topics that you can teach yourself/ research in order to achieve your goal.

2d parabolic projectile

I'm looking to create a basic Javascript implementation of a projectile that follows a parabolic arc (or something close to one) to arrive at a specific point. I'm not particularly well versed when it comes to complex mathematics and have spent days reading material on the problem. Unfortunately, seeing mathematical solutions is fairly useless to me. I'm ideally looking for pseudo code (or even existing example code) to try to get my head around it. Everything I find seems to only offer partial solutions to the problem.
In practical terms, I'm looking to simulate the flight of an arrow from one location (the location of the bow) to another. I have already simulated the effects of gravity on my projectile by updating its velocity at each logic interval. What I'm now looking to figure out is exactly how I figure out the correct trajectory/angle to fire my arrow at in order to reach my target in the shortest time possible.
Any help would be greatly appreciated.
Pointy's answer is a good summary of how to simulate the movement of an object given an initial trajectory (where a trajectory is considered to be a direction, and a speed, or in combination a vector).
However you've said in the question (if I've read you correctly) that you want to determine the initial trajectory knowing only the point of origin O and the intended point of target P.
The bad news is that in practise for any particular P there's an infinite number of parabolic trajectories that will get you there from O. The angle and speed are interdependent.
If we translate everything so that O is at the origin (i.e. [0, 0]) then:
T_x = P_x - O_x // the X distance to travel
T_y = P_y - O_y // the Y distance to travel
s_x = speed * cos(angle) // the X speed
s_y = speed * sin(angle) // the Y speed
Then the position (x, y) at any point in time (t) is:
x = s_x * t
y = s_y * t - 0.5 * g * (t ^ 2)
so at impact you've got
T_x = s_x * t
T_y = -0.5 * g * (t ^ 2) + s_y * t
but you have three unknowns (t, s_x and s_y) and two simultaneous equations. If you fix one of those, that should be sufficient to solve the equations.
FWIW, fixing s_x or s_y is equivalent to fixing either speed or angle, that bit is just simple trigonometry.
Some combinations are of course impossible - if the speed is too low or the angle too high the projectile will hit the ground before reaching the target.
NB: this assumes that position is evaluated continuously. It doesn't quite match what happens when time passes in discrete increments, per Pointy's answer and your own description of how you're simulating motion. If you recalculate the position sufficiently frequently (i.e. 10s of times per second) it should be sufficiently accurate, though.
I'm not a physicist so all I can do is tell you an approach based on really simple process.
Your "arrow" has an "x" and "y" coordinate, and "vx" and "vy" velocities. The initial position of the arrow is the initial "x" and "y". The initial "vx" is the horizontal speed of the arrow, and the initial "vy" is the vertical speed (well velocity really but those are just words). The values of those two, conceptually, depend on the angle your bowman will use when shooting the arrow off.
You're going to be simulating the progression of time with discrete computations at discrete time intervals. You don't have to worry about the equations for "smooth" trajectory arcs. Thus, you'll run a timer and compute updated positions every 100 milliseconds (or whatever interval you want).
At each time interval, you're going to add "vx" to "x" and "vy" to "y". (Thus, note that the initial choice of "vx" and "vy" is bound up with your choice of time interval.) You'll also update "vx" and "vy" to reflect the effect of gravity and (if you feel like it) wind. If "vx" doesn't change, you're basically simulating shooting an arrow on the moon :-) But "vy" will change because of gravity. That change should be a constant amount subtracted on each time interval. Call that "delta vy", and you'll have to tinker with things to get the values right based on the effect you want. (Math-wise, "vy" is like the "y" component of the first derivative, and the "delta vy" value is the second derivative.)
Because you're adding a small amount to "vy" every time, the incremental change will add up, correctly simulating "gravity's rainbow" as your arrow moves across the screen.
Now a nuance you'll need to work out is the sign of "vy". The initial sign of "vy" should be the opposite of "delta vy". Which should be positive and which should be negative depends on how the coordinate grid relates to the screen.
edit — See #Alnitak's answer for something actually germane to your question.

Categories