Collision Handling in Javascript - Particles Get Stuck - javascript

I am trying to recreate this, and I have been fairly successful. I am having issues with the collision handling though. Although the collision handling seems to work, it has very strange behavior. Here is what I have so far. This is the code that handles collisions:
var dx = particle2.getX() - particle1.getX();
var dy = particle2.getY() - particle1.getY();
var angle = Math.atan2(dy, dx);
var newP2X = particle1.getX() + (particle1.getRadius() + particle2.getRadius()) * Math.cos(angle);
var newP2Y = particle1.getY() + (particle1.getRadius() + particle2.getRadius()) * Math.sin(angle);
particle2.setX(newP2X);
particle2.setY(newP2Y);
var p1Vxi = particle1.getVx();
var p1Vyi = particle1.getVy();
var p1Mass = particle1.getMass();
var p2Vxi = particle2.getVx();
var p2Vyi = particle2.getVy();
var p2Mass = particle2.getMass();
var vxf = (p1Mass * p1Vxi + p2Mass * p2Vxi) / (p1Mass + p2Mass);
var vyf = (p1Mass * p1Vyi + p2Mass * p2Vyi) / (p1Mass + p2Mass);
particle1.setVx(vxf);
particle1.setVy(vyf);
particle2.setVx(vxf);
particle2.setVy(vyf);
EDIT: I have tried to change it to inelastic collisions like suggested, but for some reason the balls collide erratically. Check it out here.
Any help is much appreciated!

First, intuitively, imagine throwing a beanbag onto a frozen pond. It hits, doesn't bounce at all (loses whatever vertical velocity it had), and slides along with the same transverse velocity it had. That's the kind of collision we're trying for.
Now the physics. Moving reference frames. A North-bound train passes a barn. In the reference frame of the farmer in the barn, the barn is stationary and the train is moving North (0˚) at 10 m/s. In the reference frame of a passenger in the train, the train is stationary and the barn is moving South (180˚) at 10 m/s. A bicyclist is riding East (90˚) at 5 m/s (in the farmer's reference frame); in the bicyclist's frame, the bicycle is stationary, the barn is moving West (270˚) at 5 m/s and the train is moving at 11.18 m/s, bearing 333.4˚. We can convert between different frames with ease.
Two things are colliding. The frame we are interested in is the frame in which total momentum is zero. This called the Center-of-Mass Frame. If the two masses are m1 and m2, and the velocities are v1 and v2, then the velocity of the center of mass (a point that is stationary in the center-of-mass frame, like the bicycle in the bicyclist's frame) is (m1v1 + m2v2)/(m1 + m2). We calculate the velocities of the two objects in this frame and proceed.
The objects collide. We draw a plane of contact-- in this case a line tangent to both circles at the moment of contact. This is an instantaneous construct, the same in all reference frames (that don't involve rotation). In the center-of-mass frame, each object will act as if this boundary were a stationary solid surface-- in this case a sheet of ice, with no bouncing. So we divide the velocity vector into two components, the one parallel to the surface of the ice and the one normal (perpendicular) to it; we retain the first and discard the second.
Then we convert back into the barn frame and we're done.

Related

Calculating a quaternion from two combined angles

I'm creating a script that rotates a THREE.js camera arround based on a mobile phones gyroscope input. It's currently working pretty well, except that every time I rotate my phone over a quadrant, the camera will turn 180 degrees instead of continuing as intended. This is the code that I currently use:
private onDeviceOrientation = ( event ) => {
if( event.alpha !== null && event.beta !== null && event.gamma !== null ) {
let rotation = [
event.beta,
event.alpha,
event.gamma
],
this.orientation = new THREE.Vector3(rotation[0], rotation[1], rotation[2]);
this.viewer.navigation.setTarget(this.calcPosition());
}
};
private calcPosition = () => {
const camPosition = this.viewer.navigation.getPosition(),
radians = Math.PI / 180,
aAngle = radians * - this.orientation.y,
bAngle = radians * + this.orientation.z,
distance = this.calcDistance();
let medianX = Math.cos(bAngle) * Math.sin(aAngle);
let medianY = Math.cos(bAngle) * Math.cos(aAngle);
let nX = camPosition.x + (medianX * distance),
nY = camPosition.y + (medianY * distance),
nZ = camPosition.z + Math.sin(bAngle) * distance;
return new THREE.Vector3(nX, nY, nZ);
};
window.addEventListener('deviceorientation', this.onDeviceOrientation, false);
Soafter doing some research I found that I need to use a Quaternion prevent the switchen when going into a new quadrant. I have no experience with Quaternions, so I was wondering what the best way would be to combine the two Vector3's in the code above into a singel Quaternion.
[Edit]
I calculate the distance using this method:
private calcDistance = (): number => {
const camPosition = this.viewer.navigation.getPosition();
const curTarget = this.viewer.navigation.getTarget();
let nX = camPosition.x - curTarget.x,
nY = camPosition.y - curTarget.y,
nZ = camPosition.z - curTarget.z;
return Math.sqrt((nX * nX) + (nY * nY) + (nZ * nZ));from squared averages
};
And I follow the MDN conventions when working with the gyroscope.
[Edit #2]
Turns out I had my angle all wrong, I managed to fix it by calculating the final position like this:
let nX = camPosition.x - (Math.cos(zAngle) * Math.sin(yAngle)) * distance,
nY = camPosition.y + (Math.cos(zAngle) * Math.cos(yAngle)) * distance,
nZ = camPosition.z - (Math.cos(xAngle) * Math.sin(zAngle)) * distance;
Here is the closest I can give you to an answer:
First of all, you don't need a quaternion. (If you really find yourself needing to convert between Euler angles and quaternions, it is possible as long as you have all the axis conventions down pat.) The Euler angle orientation information you obtain from the device is sufficient to represent any rotation without ambiguity; if you were calculating angular velocities, I'd agree that you want to avoid Euler angles since there are some orientations in which the rates of change of the Euler angles go to infinity. But you're not, so you don't need it.
I'm going to try to summarize the underlying problem you're trying to solve, and then tell you why it might not be solvable. 🙁
You are given the full orientation of the device with a camera, as yaw, pitch, and roll. Assuming yaw is like panning the camera horizontally, and pitch is like tilting the camera vertically, then roll is a degree of freedom that doesn't change affect direction the camera is pointing, but it does affect the orientation of the images the camera sees. So you are given three coordinates, where two have to do with the direction the camera is pointing, and one does not.
You are trying to output this information to the camera controller but you are only allowed to specify the target location, which is the point in space that the camera is looking. This is to be specified via three Cartesian coordinates, which you can calculate from the direction the camera is pointing (2 degrees of freedom) and the distance to the target object (one degree of freedom).
So you have three inputs and three outputs, but only two of those have anything to do with each other. The target location has no way to represent the roll direction of the camera, and the orientation of the camera has no way to represent the distance to some target object.
Since you don't have a real target object, you can just pick an arbitrary fixed distance (1, for example) and use it. You certainly don't have anything from which to calculate it... if I follow your code, you are defining distance in terms of the target location, which is itself defined in terms of the distance from the previous step. This is extra work for no benefit at best (the distance drifts around some initial value), and numerically unstable at worst (the distance drifts toward zero and you lose precision or get infinities). Just use a fixed value for distance and make it simple.
So now you probably have a system that points a camera in a direction, but you cannot tell it what the roll angle is. That means your camera controller is apparently just going to choose it for you based on the yaw and pitch angles. Let's say it always picks zero degrees (that would be the least crazy thing it could do). This will cause discontinuities when the roll angle and yaw angle line up (when the pitch is at ±90°): Imagine pointing a physical camera at the northern horizon and yawing around westward, past the western horizon, and settling on the southern horizon. The whole time, the roll angle of the camera is 0°, so there's no problem. But now imagine pointing it at the northern horizon, and pitching upward, past the zenith, and continuing to pitch backward until you are facing the southern horizon. Now the camera is upside down; the roll angle is 180°. But if the camera controller doesn't change the roll angle from 0°, then it will do a nonphysical "flip" right when you pass the zenith. The problem is that there really is no way to synthesize a roll angle based purely on position and not have this happen. We've just demonstrated that there are two ways to move your camera from pointing north to pointing south, where the roll angle is completely different at the end.
So you're stuck, I guess. Well, maybe not. Can you rotate the image from the camera based on the roll angle of the device orientation? That is, add the roll back into the displayed image? If so, you may have a solution. Let's say the roll angle of the camera controller is always at zero. Then you just rotate the image by the desired roll angle (something derived from beta I guess?) and you're done. If the camera controller has some other convention for choosing the roll angle, you will need to figure that out, undo it, and add the roll angle back on.
Without the actual system in front of me I probably can't help you debug your way to a solution. So I think this is where my journey with this question must end. Good luck!
Summary:
You don't need a quaternion
Pick a fixed distance to your simulated target
Add the roll angle by rotating the image before displaying it
Good luck!

Circle to circle collision direction. Canvas html5 [duplicate]

I am writing software that extends Circle-Rectangle collision detection (intersection) to include responses to the collision. Circle-edge and circle-rectangle are rather straight-forward. But circle-circle has me stumped.
For example, let two circles collide, one red and one green, in a discrete event simulation. We might have the following situation:
Immediately after they collide we could have:
Here RIP and GIP were the locations of the circles at the previous clock tick. At the current clock tick, the collision is detected at RDP and GDP. However, the collision occurred between clock ticks when the two circles were at RCP and GCP. At the clock tick, the red circle moves RVy downward and RVx rightward; the green circle moves GVy downward and GVx leftward. RVy does not equal GVy; nor does RVx equal GVx.
The collision occurs when the distance between the circle centers is less than or equal to the sum of the circles' radii, that is, in the preceding figure, d <= ( Rr + Gr ). At a collision where d < ( Rr + Gr ), we need to position the DPs back to the CPs before adjusting the circles' velocity components. In the case of d == ( Rr + Gr ), no repositioning is required since the DPs are at the CPs.
This then is the problem: how do I make the move back to the CPs. Some authors have suggested that one-half of the penetration, given by p in the following figure, be applied.
To me that is just plain wrong. It assumes that the velocity vectors of the two circles are equal that, in this example, is not the case. I think penetration has something to do with the computation but how eludes me. I do know that the problem can be recast as a problem of right similar triangles in which we want to solve for Gcdy and GCdx.
The collision itself will be modeled as elastic, and the math for the exchange of inertia is already in place. The only issue is where to position the circles at collision.
"This then is the problem: how do I make the move."
It is likely that you want to know how "to position the DPs back to the CPs before adjusting the circles' velocity components."
So there are two issues, how to determine the CPs (where the collision occurs) and how to adjust the circles' motion going forward from that point. The first part has a rather easy solution (allowing for different radii and velocity components), but the second part depends on whether an elastic or inelastic response is modelled. In a Comment you write:
The collision will be modeled as elastic. The math for the exchange of inertia
is already in place. The problem is where to position the circles.
Given that I'm going to address only the first issue, solving for the exact position where the collision occurs. Assuming uniform motion of both circles, it is sufficient to know the exact time at which collision occurs, i.e. when does the distance between the circles' centers equal the sum of their radii.
With uniform motion one can treat one circle (red) as motionless by subtracting its velocity from that of the other circle (green). In effect we treat the center of the first circle as fixed and consider only the second circle to be in (uniform) motion.
Now the exact time of collision is found by solving a quadratic equation. Let V = (GVx-RVx, GVy-RVy) be the relative motion of the circles, and let P = (GIPx-RIPx,GIPy-RIPy) their relative positions in the "instant" prior to collision. We "animate" a linear path for the relative position P by defining:
P(t) = P + t*V
and ask when this straight line intersects the circle around the origin of radius Rr+Gr, or when does:
(Px + t*Vx)^2 + (Py + t*Vy)^2 = (Rr + Gr)^2
This is a quadratic equation in unknown time t, all other quantities involved being known. The circumstances are such that (with collision occurring at or before position CP) a positive real solution will exist (typically two solutions, one before CP and one after, but possibly a grazing contact giving a "double root"). The solution (root) t you want is the earlier one, the one where t (which is zero at "instant" RIP,GIP positions) is smaller.
If you're looking for a basic reference on inelastic collisions for circular objects, Pool Hall Lessons: Fast, Accurate Collision Detection Between Circles or Spheres by Joe van den Heuvel and Miles Jackson is very easy to follow.
From least formal to most formal, here are some follow up references on the craft of implementing the programming that underpins the solution to your question (collision responses).
Brian Beckman & Charles Torre The Physics in Games - Real-Time Simulation Explained
Chris Hecker, Physics, Part 3: Collision Response, Game Developer 1997
David Baraff, Physically Based Modeling: Principles and Practice, Online Siggraph '97 Course notes, of particular relevance are the Slides for rigid body simulations.
You're going to have to accept some approximations - Beckman demonstrates in the video that even for very simple cases, it isn't possible to analytically predict what would occur, this is even worse because you are simulating a continuous system with discrete steps.
To re-position the two overlapping circles with constant velocities, all you need to do is find the time at which the collision occurred, and add that factor of their velocities to their positions.
First, instead of two circles moving, we will consider one circle with combined radius and relative position and velocity. Let the input circles have positions P1 and P2, velocities V1 and V2, and radii r1 and r2. Let the combined circle have position P = P2 - P1, velocity V = V2 - V1, and radius r = r1 + r2.
We have to find the time at which the circle crosses the origin, in other words find the value of t for which r = |P + tV|. There should be 0, 1, or 2 values depending on whether the circle does not pass through the origin, flies tangent to it, or flies through it.
r^2 = ||P + tV|| by squaring both sides.
r^2 = (P + tV)*(P + tV) = t^2 V*V + 2tP*V + P*P using the fact that the L2-norm is equivalent to the dot product of a vector with itself, and then distributing the dot product.
t^2 V*V + 2tP*V + P*P - r^2 = 0 turning it into a quadratic equation.
If there are no solutions, then the discriminant b^2 - 4ac will be negative. If it is zero or positive, then we are interested in the first solution so we will subtract the discriminant.
a = V*V
b = 2 P*V
c = P*P - r^2
t = (-b - sqrt(b^2 - 4ac)) / (2a)
So t is the time of the collision.
You can actually derive an expression for the time required to reach a collision, given initial positions and velocity vectors.
Call your objects A and B, and say they have position vectors a and b and velocity vectors u and v, respectively. Let's say that A moves at a rate of u units per timestep (so, at time = t, A is at a; at time = t + 1, A is at a + u).
I'm not sure whether you want to see the derivation; it wouldn't look so great... my knowledge of LaTeX is pretty limited. (If you do want me to, I could edit it in later). For now, though, here's what I've got, using generic C#-ish syntax, with a Vector2 type that is declared Vector2(X, Y) and has functions for vector addition, scalar multiplication, dot product, and length.
double timeToCollision(Vector2 a, Vector2 b, Vector2 u, Vector2 v)
{
// w is the vector connecting their centers;
// z is normal to w and equal in length.
Vector2 w = b - a;
Vector2 z = new Vector2(-1 * w.Y, w.X);
Vector2 s = u - v;
// Dot() represents the dot product.
double m = Dot(z, s) / Dot(w, s);
double t = w.Length() / Dot(w, s) *
(w.Length() - sqrt( ((2 * r) ^ 2) * (1 + m ^ 2) - (m * w.Length()) ^ 2) ) /
(1 + m * m)
return t;
}
As for responding to collisions: if you can fast-forward to the point of impact, you don't have to worry about dealing with the intersecting circles.
If you're interested, this expression gives some cool results when there won't be a collision. If the two objects are moving away from each other, but would have collided had their velocities been reversed, you'll get a negative value for t. If the objects are on paths that aren't parallel, but will never meet (passing by each other), you'll get a negative value inside the square root. Discarding the square root term, you'll get the time when they're the closest to each other. And if they're moving in parallel at the same speed, you'll get zero in the denominator and an undefined value for t.
Well, hopefully this was helpful! I happened to have the same problem as you and decided to see whether I could work it out on paper.
Edit: I should have read the previous responses more carefully before posting this... the mess of a formula above is indeed the solution to the quadratic equation that hardmath described. Apologies for the redundant post.

Plotting points on segment of circumference

This one requires a bit of visualisation, so sorry if my explanation sucks.
So, I have a central point at 0,0. From this point, I am plotting random points on its circumference, at a radius of 350 pixels (random number). For this I am using this code:
var angle = Math.random()*Math.PI*2;
var x = Math.cos(angle)*radius;
var y = Math.sin(angle)*radius;
x+=parent.position.x;
y+=parent.position.y;
The parent.position this is because each point that is plotted also acts as a central node, which has children that act as nodes and so on. This just sets the position of the new node relative the position of its parent.
So this code works perfectly well for the central node. The problem is that once you've branched away from the centre, you want to continue moving in a particular direction to avoid a big cluster of nodes interfering with each other. So, whereas this code plots a point on the circumference, I need to be able to plot a point on a segment of the circumference. I'm thinking maybe about a third of the circumference should be accessible. The other obstacle is that this has to be the CORRECT segment of the circumference i.e If the nodes are branching upwards, I don't want the segment to be the bottom half of the circumference, the branch needs to continue moving in the upwards direction.
I can establish a general direction based on the position of the new parent node relative to the position of its parent. But does anyone have any ideas of how to use this data to reduce the field to the a segment in this direction?
Let me know if that made no sense, it's kinda hard to explain without diagrams.
I think one easy way of doing that would be to split your circle in n segments (each covering 2*PI / n angle). You could set n to whatever you want, depending on how precise you want to be. Then when you calculate a new point x, first get the segment in which x.parent is (relative to its own parent), and use that to put x in the same section wrt x.parent. You could then have something like this:
var getSection = function(point) {
var parent = point.parent;
var angle = Math.acos((point.x - parent.x) / radius) % (Math.PI*2);
var section = Math.floo(angle / (Math.PI * 2 / n))
return section;
}
var section = getSection(parent); // return the index of the section
var angle = (Math.random() + section) * Math.PI * 2 / n
var x = Math.cos(angle)*radius;
var y = Math.sin(angle)*radius;
x+=parent.position.x;
y+=parent.position.y;

CraftyJS how to calculate vector between 2 sprites?

I am a noob in game programming and not so good at Maths, I am trying to write a 1945 style shooting game, all been good so far but I am in a bottle neck that I cannot figure out how to make enemy aim at the player.
Lets say I have enemy sprite and player sprite, how do I find out the angle and the path? This sounds like calculating vector between 2 points, I have been reading the documentation and particularly this link http://craftyjs.com/api/Crafty-math-Vector2D.html
I just cannot figure out how to do it, I have tried the following
var enemyV = Crafty.math.Vector2D(enemy.x, enemy.y);
var playerV = Crafty.math.Vector2D(player.x, player.y);
var angle = enemyV.angleTo(playerV);
The value of angle is always between -3 to 3, which doesn't seem the right angles at all.
I hope someone who has CraftyJS experience can help me out here.
angleTo function returns radian value, so running this will give the actual angle degreex Crafty.math.radToDeg(radianValue)
To aim the player and make the bullet travel at that direction you just get the difference between 2 points
bullet.x - player.x'bullet.y - player.y' then apply a incremental rate such as below (
bullet.x_diff = (target.x - bullet.x)*0.02;
bullet.y_diff = (target.y - bullet.y)*0.02;
then inside enterframe loop:
this.x += this.x_diff;
this.y += this.y_diff;
Once you get the idea, you should normalize your diff by dividing by the distance between the points.

How can a large canvas have an animated 'viewable area'

The question title may be vague. Basically, imagine a racing game built in canvas. The track takes up 10,000 x 10,000 pixels of screen space. However the browser window is 500 x 500 pixels. The car should stay centered in the browser and the 'viewable' area of the 10,000 x 10,000 canvas will change. Otherwise the car would just drive off the edge at disappear.
Does this technique have a name?
What are the basic principles to make this happen?
If the car should stay at the same position (relative to the canvas' position), then you should not move the car. Instead, move the background picture/track/map to the other side.
Causing your eyes to think the car moves right can be done by either moving the car to the right, or by moving the map to the left. The second option seems to be what you want, since the car won't move whereas the viewable area (i.e. the map) will.
This is a quick demo from scratch: http://jsfiddle.net/vXsqM/.
It comes down to altering the map's position the other way round:
$("body").on("keydown", function(e) {
if(e.which === 37) pos.x += speed; // left key, so move map to the right
if(e.which === 38) pos.y += speed;
if(e.which === 39) pos.x -= speed;
if(e.which === 40) pos.y -= speed;
// make sure you can't move the map too far.
// clamp does: if x < -250 return -250
// if x > 0 return 0
// else it's allowed, so just return x
pos.x = clamp(pos.x, -250, 0);
pos.y = clamp(pos.y, -250, 0);
draw();
});
You can then draw the map with the position saved:
ctx.drawImage(img, pos.x, pos.y);
If you're looking for a way to actually move the car when the map cannot be moved any further (because you're driving the car close to a side of the map), then you'd have to extend the clamping and also keep track of when the car should be moved and how far: http://jsfiddle.net/vXsqM/1/.
// for x coordinate:
function clamp2(x, y, a, b) { // x = car x, y = map x, a = min map x, b = max map x
return y > b ? -y : y < a ? a - y : x;
}
The position clamping then becomes a little more complex:
// calculate how much car should be moved
posCar.x = clamp2(posCar.x, posMap.x, -250, 0);
posCar.y = clamp2(posCar.y, posMap.y, -250, 0);
// also don't allow the car to be moved off the map
posCar.x = clamp(posCar.x, -100, 100);
posCar.y = clamp(posCar.y, -100, 100);
// calculate where the map should be drawn
posMapReal.x = clamp(posMap.x, -250, 0);
posMapReal.y = clamp(posMap.y, -250, 0);
// keep track of where the map virtually is, to calculate car position
posMap.x = clamp(posMap.x, -250 - 100, 0 + 100);
posMap.y = clamp(posMap.y, -250 - 100, 0 + 100);
// the 100 is because the car (circle in demo) has a radius of 25 and can
// be moved max 100 pixels to the left and right (it then hits the side)
Two things:
Canvas transformation methods
First, the canvas transformation methods (along with context.save() and context.restore() are your friends and will greatly simplify the math needed to view a portion of a large 'world`. If you use this approach, you can get the desired behavior just by specifying the portion of the world that is visible and the world-coordinates of everything you want to draw.
This is not the only way of doing things* but the transformation methods are meant for exactly this kind of problem. You can use them or you can reinvent them by manually keeping track of where your background should be drawn, etc., etc.
Here's an example of how to use them, adapted from a project of mine:
function(outer, inner, ctx, drawFunction) {
//Save state so we can return to a clean transform matrix.
ctx.save();
//Clip so that we cannot draw outside of rectangle defined by `outer`
ctx.beginPath();
ctx.moveTo(outer.left, outer.top);
ctx.lineTo(outer.right, outer.top);
ctx.lineTo(outer.right, outer.bottom);
ctx.lineTo(outer.left, outer.bottom);
ctx.closePath();
//draw a border before clipping so we can see our viewport
ctx.stroke();
ctx.clip();
//transform the canvas so that the rectangle defined by `inner` fills the
//rectangle defined by `outer`.
var ratioWidth = (outer.right - outer.left) / (inner.right - inner.left);
var ratioHeight = (outer.bottom - outer.top) / (inner.bottom - inner.top);
ctx.translate(outer.left, outer.top);
ctx.scale(ratioWidth, ratioHeight);
ctx.translate(-inner.left, -inner.top);
//here I assume that your drawing code is a function that takes the context
//and draws your world into it. For performance reasons, you should
//probably pass `inner` as an argument too; if your draw function knows what
//portion of the world it is drawing, it can ignore things outside of that
//region.
drawFunction(ctx);
//go back to the previous canvas state.
ctx.restore();
};
If you are clever, you can use this to create multiple viewports, picture-in-pictures, etc. of different sizes and zoom in and out on stuff.
Performance
Second, as I commented in the code, you should make sure your drawing code knows what portion of your larger 'world' will be visible so that you don't do a lot of work trying to draw things that will not be visible.
The canvas transformation methods are meant for solving exactly this kind of problem. Use 'em!
*You will likely have problems if your world is so large that its coordinates cannot fit in an appropriate integer. You'll hit that problem roughly when your world exceeds billion (10^9) or a long trillion (10^18) pixels in any dimension, depending on whether the integers are 32- or 64-bit. If your world isn't measured in pixels but in 'world units', you'll run into problems when your world's total size and smallest feature scale lead to floating point inaccuracies. In that case, you will need to do extra work to keep track of things... but you'll probably still want to use the canvas transformation methods!
My very first game was a racing game where I moved the background instead of the car and although I want to think now that I had my reasons to make it so... I just didn't know better.
There are a few techniques that you need to know to achieve this well.
Tiled background. You need to make your track out of smaller pieces that tiled. To To draw 10,000 x 10,000 pixels is 100MPix image usually such image will have 32bit depth (4 bytes) this will end up being 400MB in memory. Compressions like PNG, JPEG won't help you since these are made to store and transfer images. They cant be rendered to a canvas without decompressing.
Move the car along your track. There is nothing worst then moving the BG under the car. If you need to add more features to your game like AI cars... now they will have to move along the map and to implement car collisions you need to make some not hard but strange spacial transformations.
Add camera entity. The camera needs to have position and viewport size (this is the size of your canvas). The camera will make or break your game. This is the entity that will give you the sense of speed in the game... You can have a camera shake for collisions, if you have drifts if your game the camera can slide pass the desired position and center back to the car, etc. Of course the most important thing will be tracking the car. Some simple suggestions I can give you are to not put the car in dead center of the camera. put the car a little behind so you can see a bit more what's in front of your. The faster the car moves the more you should offset the camera. Also you can't just compute the position of the camera instead compute desired position and slowly per frame move the current camera position to the desired position.
Now when you have camera and a large tiled map, when you draw the tiles you have to subtrack the camera position. You can also compute which tiles are not visible and skip them. This technique will allow you do extend your game with even larger maps or you can stream your map where you don't have all the tiles loaded and load in advance on background (AJAX) what will be visible soon.

Categories