Find list of pixels between two points [duplicate] - javascript

This question already has answers here:
How to check if line segment intersects a rectangle?
(3 answers)
Closed 5 years ago.
I'm currently programming my first game in JavaScript, and I've never technically learned JavaScript, I'm more fluent with Python.
Anyway, I need to find a way to make a list of all the pixels between two points on a straight horizontal line. I would then use the list to reference whether the user's character is touching any of the pixels to trigger a screen change.
It would be something like
pixels = []
(Function here to add the pixels to the list)
For pixel in pixels
If (dist(object.x, object.y, pixel.x, 0) < 1) {
object.x = start point on new screen
Object.y =
Does this make any sense? I'm sorry I'm bad at explaining things but I could use the help.

You almost certainly don't want to test intersection this way. This is going to require many more steps than just doing standard line-rectangle collision detection.
I recommend googling something like "line rectangle intersection" or "line rectangle collision detection" for a ton of results, including:
line-rectangle collision detection
How to check if line segment intersects a rectangle?
How to find the intersection point between a line and a rectangle?
Line intersection with AABB Rectangle?
How to test if a line segment intersects an axis-aligned rectange in 2D?
https://gamedev.stackexchange.com/questions/111100/intersection-of-a-line-and-a-rectangle

Related

Tile Filling Algorithm for Game

Background:
I am working on a tile-based game in Javascript where a character freely moves around the map (no diagonal - Left/Right/Up/Down) and fills in tiles as he moves around the map. There are three tile types -- tiles you've filled (blue), your current path (red), and empty ones (black). There are also enemies (stars) that move around the map as well, but only in empty areas. The objective is to fill as much of the map as possible.
Map is sized as roughly 40x40 tiles. There is a 1 tile thick border around the entire outside of the map that is already "filled" (blue).
I have established that a flood-fill algorithm will work for filling up areas of tiles when needed. However, my problem is as follows:
PROBLEM STATEMENT:
I want to only fill a sectioned-off part of the map if there are no enemies in it.
My Question:
I could run flood-fill algorithm and stop it if it reaches a tile occupied by an enemy -- however, is this the most efficient approach (for a real time game)?
IF YES, how do I determine where to start the algorithm from in a systematic way since there are multiple areas to check and the character doesn't have to move in a perfectly straight line (can zig-zag up/down/right/left, but can't move diagonally).
Picture Example 1 (pics explain better):
Note: red areas turn blue (filled) once you reach another filled area. In example below, there are no enemies in the contained area, so the area is filled.
Picture Example 2:
In this second example, there is an enemy within the contained area (and on the outside area - not shown) so nothing but the line is filled.
Summary: What is the best approach for doing this type of filling? Is flood fill the best choice for determining whether to fill or not -- 40x40 makes for a pretty large calculation. If yes, how do I determine what tile do I start with?
Let me suggest a different way of looking at your problem.
Going by the description of your game, it seems like the user's main, perhaps only, "verb" (in game design terms) is to draw a line that divides the open area of the field into two sections. If either of these two sections is free of enemies, that section gets filled in; if neither section is free of enemies, the line remains but both sections remain open. There are no other conditions determining whether a section gets filled or not, right?
So the most efficient way to solve this problem, I would think, is simply to draw a continuous line, which may make corners but only moves in horizontal or vertical directions, from one of your enemies to every other enemy in turn. We'll call this line the "probe line". From here on, we're using the approach of Derek's suggested "Ray casting algorithm": We look at the number of times the "probe line" crosses the "border line", and if the number of crossings is ever odd, it means you have at least one enemy on each side of the line, and there's no filling.
Note, though, that there's a difference between the two lines coinciding and the two lines crossing. Picture a probe line that goes from the coordinates (0,10) to (39,10) , and a border line that goes down from (5,0) to (5,10) and then goes right to (13,10). If it goes down from there towards (13,39), the two lines are crossing; if instead it goes upwards toward (13,0), they're not.
After a lot of thought, I strongly suggest that you store the "border line", and construct the "probe line", in terms of line segments - rather than trying to determine from which cells are filled which line segments created them. That will make it much harder than it has to be.
Finally, one odd game design note to be aware of: unless you constrict the user's control so that he cannot bring the border line back to within one cell of itself, then a single border line drawn by a user might end up sectioning off the field into more than two sections - there could be sections created by the border line looping right back on itself. If you allow that, it could very drastically complicate the calculation of where to fill. Check the following diagram I made via Derek's fiddle (thank you, Derek!):
As you can see, one border line has actually created three sections: one on the upper side of the line, one below the line, and one formed by the line itself. I'm still thinking about how that would affect things algorithmically, for that to be possible.
EDIT: With a) time to think about the above creation-of-multiple-sections-by-loops, and b) the Simulation of Simplicity resource brought up by Derek, I think I can outline the simplest and most efficient algorithm that you're likely to get.
There's one subproblem to it which I'll leave to you, and that is determining what your new sections are after the player's actions have drawn a new line. I leave that to you because it's one that would have had to be solved before a solution to your original problem (how to tell if there are enemies within those sections) could have been called.
The solution, presented here as pseudocode, assumes you have the border of each section stored as line segments between coordinates.
Create a list of the sections.
Create a list of the enemies.
Continue as long as neither list is empty:
For each enemy in the enemy list:
Designate "Point A" as the coordinates of the enemy, PLUS 0.5 to both x and y.
For each section in the section list:
Designate "Point B" as the upper-left-most coordinate, PLUS 0.5 to both x and y.
Count how many of the section border segments cross a line between A and B.
If the answer is even:
remove this section from the section list
skip forward to the next enemy
If any sections remain in the list, they are free of enemies. Fill them in.
The addition of the 0.5 to the coordinates of the "probe line" are thanks to Derek's SoS resource; they eliminate the difficult case where the lines coincide rather than simply crossing or not crossing.
If you have the points of the border of your shape that lies on the same y as the enemy, then you can simply count the number of borders, starting from either left or right to the enemy. If it's odd then it's inside. If it's even then it's outside.
Since you are using a grid system this should be easy to implement (and very fast). This algorithm is called the Ray casting algorithm.
Here's a simple example I created: http://jsfiddle.net/DerekL/8QBz6/ (can't deal with degenerate cases)
function testInside(){
var passedBorder = 0,
passingBorder = false;
for(var x = 0; x <= enemy[0]; x++){
if(board[x][enemy[1]] === 1) passingBorder = true;
else if(board[x][enemy[1]] === 0 && passingBorder){
passingBorder = false;
passedBorder++;
}
}
return !!(passedBorder%2);
}
For example, you have this shape which you have determined:
removed
Guess what I found, (slightly modified)
//simple enough, it only needs the x,y of your testing point and the wall.
//no direction or anything else
function testInside3() {
var i, j, c = 0;
for (i = 0, j = wallList.length-1; i < wallList.length; j = i++) {
if ( ((wallList[i][1]>enemy[1]) ^ (wallList[j][1]>enemy[1])) &&
(enemy[0] < (wallList[j][0]-wallList[i][0]) * (enemy[1]-wallList[i][1]) / (wallList[j][1]-wallList[i][1]) + wallList[i][0]) )
c = !c;
}
return !!c;
}
http://jsfiddle.net/DerekL/NvLcK/
This is using the same ray casting algorithm I mentioned, but this time the "ray" is now mathematical using the following inequality for x and a condition for y:
(X2 - X1)(Py - Y1)
Px < ────────────────── + X1
Y2 - Y1
which is derived by combining these two:
Ray:
x(t) = Px + t, y(t) = Py, where t > 0 (the ray goes to the right)
Edge:
x(u) = (X2 - X1)u + X1, y(u) = (Y2 - Y1)u + Y1, where 0 <= u <= 1
And the condition for y:
(Y1 > Py) ⊕ (Y2 > Py)
which is equivalent to:
(Y1 ≥ Py > Y2) ∨ (Y2 ≥ Py > Y1)
and yadi yadi yada some other interesting technical stuff.
Seems like this is the default algorithm in many native libraries. The method used to dealing with degenerate cases is called Simulation of Simplicity, described in this paper (section 5.1).
Nevertheless, here's the result generated with the algorithm testing every coordinate:
If it's easy to determine where the borders of a region to possibly fill are, you can use the following approach:
Assign each edge a clockwise directionality. That is, construct a vector for each edge that starts on its corners and has a direction such that a clockwise path around the region is described by these vectors.
For each enemy:
Construct a vector starting from the enemy and ending on the closest edge. We'll call this an enemy_vector.
Calculate the cross product of the enemy_vector and the vector corresponding to the closest edge. The sign of the cross product will tell you whether the enemy is inside the region: if it's positive, the enemy is outside of it, and if it's negative it isn't!
EXAMPLE:
Suppose we have the following region and enemy to evaluate the inside-ness of.
We can encode the region as a series of vectors that give it a clockwise orientation, like so:
So how do we use that to determine the side of the region inhabited by the enemy? We draw a vector from it (which I've colored red) to the nearest edge (which I've colored green)...
...and take the cross product of the red vector and the green vector. Application of the right-hand rule tells us that (red) x (green) > 0, so the enemy must be outside the region!

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>

Calculate overlap of two colliding objects?

UPDATE: I found this enormously helpful article explaining canvas per-pixel collision detection.
I'm working on a collision system for a javascript game using HTML5 canvas. Each object has an image as a sprite and when a non-transparent pixel of any one object overlaps another, the collision code is triggered. But before anything else the objects need to be moved so that they are just touching each other and no longer triggering a collision. I need help calculating the overlap of any two objects in terms of x and y in order to move one accordingly. Here's what we know:
The coordinates of the collision point relative to each object
The positions of the objects (and therefore the distance between them)
The width and height of the objects
The velocity of the objects in the x and y directions (a vector)
Another note: the images for these objects are uneven shapes, no perfect circles, but the radius from the center to the collision point can be calculated.
EDIT: I haven't seen a lot of response, so I'll be more specific. In the image below, two objects are colliding. The overlap area is in red. How would you go about finding the lengths of the green lines?
I'm honestly clueless about HTML 5 and how you can make games in pure HTML 5. But you would also need to know a velocity (IE, their direction. This way you can send them backwards from where they came)
If it was in a standard programming language, one method would be to use a while loop (moving the sprite back until the collision == false). Another method would be a more complicated calculation of how far the intersection is and subtract individual x and y values so they are not collided.
EDIT:
Then the easiest way is like I said, to put the object thats moving in a while loop that moves it backwards 1 pixel in each axis until its collision tests false. Example:
int x1 = 500; //x location on screen
int y2 = 500; //y location
public boolean fixOffSetX(Sprite s) {
int x2 = s.getX();
int y2 = s.getY();
//not writing the whole thing
//enter a while loop until its not colliding anymore
while(collision is still true) {
x--; or x++;
//depending on direction
//(which is why you need to know velocity/direction of your sprites)
//do the same for the Y axis.
}
}
//This method will return if the 2 sprites collided, you do this one
public boolean collisionTest(Sprite s1, Sprite s2) {}
You should look at doing very basic collisions, since it is a VERY complicated part of programming
If this is still an issue, I've found information about the subject in an e-book called Foundation Game Design with HTML5 en Javascript. Here: link to relevant pages. Hope this helps anyone in the future.

JavaScript Separating Axis Theorem

I'm trying to wrap my head around using the Separating Axis Theorem in JavaScript to detect two squares colliding (one rotated, one not). As hard as I try, I can't figure out what this would look like in JavaScript, nor can I find any JavaScript examples. Please help, an explanation with plain numbers or JavaScript code would be most useful.
Update: After researching lots of geometry and math theories I've decided to roll out a simplified SAT implementation in a GitHub repo. You can find a working copy of SAT in JavaScript here: https://github.com/ashblue/canvas-sat
Transforming polygons
First you have to transform all points of your convex polygons (squares in this case) so they are all in the same space, by applying a rotation of angle.
For future support of scaling, translation, etc. I recommend doing this through matrix transforms. You'll have to code your own Matrix class or find some library that has this functionality already (I'm sure there are plenty of options).
Then you'll use code in the vain of:
var transform = new Matrix();
transform.appendRotation(alpha);
points = transform.transformPoints(points);
Where points is an array of Point objects or so.
Collision algorithm overview
So that's all before you get to any collision stuff. Regarding the collision algorithm, it's standard practice to try and separate 2 convex polygons (squares in your case) using the following steps:
For each polygon edge (edges of both polygon 0 and polygon 1):
Classify both polgyons as "in front", "spanning" or "behind" the edge.
If both polygons are on different sides (1 "in front" and 1 "behind"), there is no collision, and you can stop the algorithm (early exit).
If you get here, no edge was able to separate the polgyons: The polygons intersect/collide.
Note that conceptually, the "separating axis" is the axis perpendicular to the edge we're classifying the polygons with.
Classifying polygons with regards to an edge
In order to do this, we'll classify a polygon's points/vertices with regards to the edge. If all points are on one side, the polygon's on that side. Otherwise, the polygon's spanning the edge (partially on one side, partially on the other side).
To classify points, we first need to get the edge's normal:
// this code assumes p0 and p1 are instances of some Vector3D class
var p0 = edge[0]; // first point of edge
var p1 = edge[1]; // second point of edge
var v = p1.subtract(p0);
var normal = new Vector3D(0, 0, 1).crossProduct(v);
normal.normalize();
The above code uses the cross-product of the edge direction and the z-vector to get the normal. Ofcourse, you should pre-calculate this for each edge instead.
Note: The normal represents the separating axis from the SAT.
Next, we can classify an arbitrary point by first making it relative to the edge (subtracting an edge point), and using the dot-product with the normal:
// point is the point to classify as "in front" or "behind" the edge
var point = point.subtract(p0);
var distance = point.dotProduct(normal);
var inFront = distance >= 0;
Now, inFront is true if the point is in front or on the edge, and false otherwise.
Note that, when you loop over a polygon's points to classify the polygon, you can also exit early if you have at least 1 point in front and 1 behind, since then it's already determined that the polygon is spanning the edge (and not in front or behind).
So as you can see, you still have quite a bit of coding to do. Find some js library with Matrix and Vector3D classes or so and use that to implement the above. Represent your collision shapes (polygons) as sequences of Point and Edge instances.
Hopefully, this will get you started.

Pixel Perfect Collision Detection in HTML5 Canvas

I want to check a collision between two Sprites in HTML5 canvas. So for the sake of the discussion, let's assume that both sprites are IMG objects and a collision means that the alpha channel is not 0. Now both of these sprites can have a rotation around the object's center but no other transformation in case this makes this any easier.
Now the obvious solution I came up with would be this:
calculate the transformation matrix for both
figure out a rough estimation of the area where the code should test (like offset of both + calculated extra space for the rotation)
for all the pixels in the intersecting rectangle, transform the coordinate and test the image at the calculated position (rounded to nearest neighbor) for the alpha channel. Then abort on first hit.
The problem I see with that is that a) there are no matrix classes in JavaScript which means I have to do that in JavaScript which could be quite slow, I have to test for collisions every frame which makes this pretty expensive. Furthermore I have to replicate something I already have to do on drawing (or what canvas does for me, setting up the matrices).
I wonder if I'm missing anything here and if there is an easier solution for collision detection.
I'm not a javascript coder but I'd imagine the same optimisation tricks work just as well for Javascript as they do for C++.
Just rotate the corners of the sprite instead of every pixel. Effectively you would be doing something like software texture mapping. You could work out the x,y position of a given pixel using various gradient information. Look up software texture mapping for more info.
If you quadtree decomposed the sprite into "hit" and "non-hit" areas then you could effectively check to see if a given quad tree decomposition is all "non-hit", "all hit" or "possible hit" (ie contains hits and non-hit pixels. The first 2 are trivial to pass through. In the last case you then go down to the next decomposition level and repeat the test. This way you only check the pixels you need too and for large areas of "non-hit" and "hit" you don't have to do such a complex set of checks.
Anyway thats just a couple of thoughts.
I have to replicate something I already have to do on drawing
Well, you could make a new rendering context, plot one rotated white-background mask to it, set the compositing operation to lighter and plot the other rotated mask on top at the given offset.
Now if there's a non-white pixel left, there's a hit. You'd still have to getImageData and sift through the pixels to find that out. You might be able to reduce that workload a bit by scaling the resultant image downwards (relying on anti-aliasing to keep some pixels non-white), but I'm thinking it's probably still going to be quite slow.
I have to test for collisions every frame which makes this pretty expensive.
Yeah, I think realistically you're going to be using precalculated collision tables. If you've got space for it, you could store one hit/no hit bit for every combination of sprite a, sprite b, relative rotation, relative-x-normalised-to-rotation and relative-y-normalised-to-rotation. Depending on how many sprites you have and how many steps of rotation or movement, this could get rather large.
A compromise would be to store the pre-rotated masks of each sprite in a JavaScript array (of Number, giving you 32 bits/pixels of easily &&-able data, or as a character in a Sring, giving you 16 bits) and && each line of intersecting sprite masks together.
Or, give up on pixels and start looking at eg. paths.
Same problem, an alternative solution. First I use getImageData data to find a polygon that surrounds the sprite. Careful here because the implementation works with images with transparent background that have a single solid object. Like a ship. The next step is Ramer Douglas Peucker Algorithm to reduce the number of vertices in the polygon. I finally get a polygon of very few vertices easy and cheap to rotate and check collisions with the other polygons for each sprite.
http://jsfiddle.net/rnrlabs/9dxSg/
var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
var img = document.getElementById("img");
context.drawImage(img, 0,0);
var dat = context.getImageData(0,0,img.width, img.height);
// see jsfiddle
var startPixel = findStartPixel(dat, 0);
var path = followPath(startPixel, dat, 0);
// 4 is RDP epsilon
map1 = properRDP(path.map, 4, path.startpixel.x, path.startpixel.y);
// draw
context.beginPath();
context.moveTo(path.startpixel.x, path.startpixel.x);
for(var i = 0; i < map.length; i++) {
var p = map[i];
context.lineTo(p.x, p.y);
}
context.strokeStyle = 'red';
context.closePath();
context.stroke();

Categories