I've used an expression to emit particles on the death of a first particle object and it works really well. What I want to do now is use the second set of emitted particles to drive joint rotation, again using expressions.
So, the sum total of what I have now is:
if (volumeAxis_nParticle1_nerveImpulseShape.age >= volumeAxis_nParticle1_nerveImpulseShape.lifespanPP)
//if particle age is >= lifespan
{
vector $pos = volumeAxis_nParticle1_nerveImpulseShape.position;
//determines where the particles are when they die
float $emitNum = 3;
//determines how many particles will be emitted upon particle death ie 3
for ($i = 0; $i < $emitNum; $i ++)
// for variable $i, start at 0 and if $i <emitNum then add 1 to it and execute the following commands, but if $i =3, then quit
{
vector $randVel = <<rand(-0.5,0.5), -1, rand(-0.5,0.5)>>;
//determines the direction of the emitted particles in x, y, z
emit -o emitOnDeath_nParticle1_acetylCholine //emit the second particle object
-position ($pos.x) ($pos.y) ($pos.z) //where first particle object dies
-at velocity //now determine velocity
–vv ($randVel.x) ($randVel.y) ($randVel.z); //vector values (vv) for random velocity x, y or z
};
};
The next set of expressions I have is:
if (emitOnDeath_nParticle1_acetylCholineShape.age < emitOnDeath_nParticle1_acetylCholineShape.lifespanPP)
longMuscleController22.rotateY = 0;
else if (emitOnDeath_nParticle1_acetylCholineShape.age >= emitOnDeath_nParticle1_acetylCholineShape.lifespanPP)
longMuscleController22.rotateY = -0.1;
This second expression does rotate the joint, but for greater control, what I really need is another command to quickly return the joint rotation to 0 again, ie relax quickly after a contraction. At the moment, the rotation only returns to 0 when the first expression starts again. I was thinking maybe another else if line, something to the effect that when the particle count =0 (ie once all the particles have died off when lifespanPP is exceeded), that rotate y = 0 again?
I tried this instead, using particle count:
int $numPar = `particle -ct emitOnDeath_nParticle1_acetylCholineShape`;
if($numPar == 0)
longMuscleController22.rotateY = 0;
else if($numPar > 0)
longMuscleController22.rotateY = -0.1;
Maya says the syntax is correct, but it throws up all sorts of errors once it executes and doesn't move the joint. I'd really appreciate any advice please on how to use the second set of particles to control joint rotation, if you have any?
Thank you in advance for all your help and best wishes,
Maja
Related
I'm trying to create a smooth "wave" when the mouse moves over isometric logo shape.
I've created in in processing now I'm trying to recreate it in THREE.js
The shape acts strangely - the shape doesn't look as smooth when elevated compared to the processing sketch. If you look at the edges you can see segments that are not supposed to be there. I'm not sure what causes this.
Basically the shape is created through a loops that goes over 2 arrays:
for (var i = 0; i < xpos0.length; i++) {
shape.lineTo(xpos0[i], ypos0[i]);
}
Then it animates through another for loop that checks the distance between verteces[i].x and mouse location intersection with the ground
for (let p = 0; p < mesh.geometry.vertices.length; p=p+1) {
let delta = Math.abs(mesh.geometry.vertices[p].x - intersects[0].point.x);
mesh.geometry.vertices[p].z = bump2(-2, 2000, -1, 2, delta);
}
z value is calculated through this function:
function bump2(a,b,c,d,xval) {
xval = parseFloat(xval);
// console.log(typeof xval);
return Math.exp(a / (-xval * xval / b + c) + d) * -1;
}
https://codepen.io/NotYetDesignLab/pen/JjYaqRJ
How it looks on THREE.JS
notice how some segments appear "broken", like it's made of stiff parts instead of the many points that make up the segment in the array and give the illusion of "paper".
THIS IS HOW IT'S SUPPOSED TO LOOK: (Processing/java)
This has been done using Processing. Notice how the elevation of the edges is smooth and not broken.
I am trying to store the motion detected from optical flow for frames in a video sequence and then use these stored motion vectors in order to predict the already known frames using just the first frame as a reference. I am currently using two processing sketches - the first sketch draws a motion vector for every pixel grid (each of width and height 10 pixels). This is done for every frame in the video sequence. The vector is only drawn in a grid if there is sufficient motion detected. The second sketch aims to reconstruct the video frames crudely from just the initial frame of the video sequence combined with information about the motion vectors got from the first sketch.
My approach so far is as follows: I am able to determine the size, position and direction of each motion vector drawn in the first sketch from four variables. By creating four arrays (two for the motion vector's x and y coordinate and another two for its length in the x and y direction), every time a motion vector is drawn I can append each of the four variables to the arrays mentioned above. This is done for each pixel grid throughout an entire frame where the vector is drawn and for each frame in the sequence - via for loops. Once the arrays are full, I can then save them to a text file as a list of strings. I then load these strings from the text file into the second sketch, along with the first frame of the video sequence. I load the strings into variables within a while loop in the draw function and convert them back into floats. I increment a variable by one each time the draw function is called - this moves on to the next frame (I used a specific number as a separator in my text-files which appears at the end of every frame - the loop searches for this number and then increments the variable by one, thus breaking the while loop and the draw function is called again for the subsequent frame). For each frame, I can draw 10 by 10 pixel boxes and move then by the parameters got from the text files in the first sketch. My problem is simply this: How do I draw the motion of a particular frame without letting what I've have blitted to the screen in the previous frame affect what will be drawn for the next frame. My only way of getting my 10 by 10 pixel box is by using the get() function which gets pixels that are already drawn to the screen.
Apologies for the length and complexity of my question. Any tips would be very much appreciated! I will add the code for the second sketch. I can also add the first sketch if required, but it's rather long and a lot of it is not my own. Here is the second sketch:
import processing.video.*;
Movie video;
PImage [] naturalMovie = new PImage [0];
String xlengths [];
String ylengths [];
String xpositions [];
String ypositions [];
int a = 0;
int c = 0;
int d = 0;
int p;
int gs = 10;
void setup(){
size(640, 480, JAVA2D);
xlengths = loadStrings("xlengths.txt");
ylengths = loadStrings("ylengths.txt");
xpositions = loadStrings("xpositions.txt");
ypositions = loadStrings("ypositions.txt");
video = new Movie(this, "sample1.mov");
video.play();
rectMode(CENTER);
}
void movieEvent(Movie m) {
m.read();
PImage f = createImage(m.width, m.height, ARGB);
f.set(0, 0, m);
f.resize(width, height);
naturalMovie = (PImage []) append(naturalMovie, f);
println("naturalMovie length: " + naturalMovie.length);
p = naturalMovie.length - 1;
}
void draw() {
if(naturalMovie.length >= p && p > 0){
if (c == 0){
image(naturalMovie[0], 0, 0);
}
d = c;
while (c == d && c < xlengths.length){
float u, v, x0, y0;
u = float(xlengths[a]);
v = float(ylengths[a]);
x0 = float(xpositions[a]);
y0 = float(ypositions[a]);
if (u != 1.0E-19){
//stroke(255,255,255);
//line(x0,y0,x0+u,y0+v);
PImage box;
box = get(int(x0-gs/2), int(y0 - gs/2), gs, gs);
image(box, x0-gs/2 +u, y0 - gs/2 +v, gs, gs);
if (a < xlengths.length - 1){
a += 1;
}
}
else if (u == 1.0E-19){
if (a < xlengths.length - 1){
c += 1;
a += 1;
}
}
}
}
}
Word to the wise: most people aren't going to read that wall of text. Try to "dumb down" your posts so they get to the details right away, without any extra information. You'll also be better off if you post an MCVE instead of only giving us half your code. Note that this does not mean posting your entire project. Instead, start over with a blank sketch and only create the most basic code required to show the problem. Don't include any of your movie logic, and hardcode as much as possible. We should be able to copy and paste your code onto our own machines to run it and see the problem.
All of that being said, I think I understand what you're asking.
How do I draw the motion of a particular frame without letting what I've have blitted to the screen in the previous frame affect what will be drawn for the next frame. My only way of getting my 10 by 10 pixel box is by using the get() function which gets pixels that are already drawn to the screen.
Separate your program into a view and a model. Right now you're using the screen (the view) to store all of your information, which is going to cause you headaches. Instead, store the state of your program into a set of variables (the model). For you, this might just be a bunch of PVector instances.
Let's say I have an ArrayList<PVector> that holds the current position of all of my vectors:
ArrayList<PVector> currentPositions = new ArrayList<PVector>();
void setup() {
size(500, 500);
for (int i = 0; i < 100; i++) {
currentPositions.add(new PVector(random(width), random(height)));
}
}
void draw(){
background(0);
for(PVector vector : currentPositions){
ellipse(vector.x, vector.y, 10, 10);
}
}
Notice that I'm just hardcoding their positions to be random. This is what your MCVE should do as well. And then in the draw() function, I'm simply drawing each vector. This is like drawing a single frame for you.
Now that we have that, we can create a nextFrame() function that moves the vectors based on the ArrayList (our model) and not what's drawn on the screen!
void nextFrame(){
for(PVector vector : currentPositions){
vector.x += random(-2, 2);
vector.y += random(-2, 2);
}
}
Again, I'm just hardcoding a random movement, but you would be reading these from your file. Then we just call the nextFrame() function as the last line in the draw() function:
If you're still having trouble, I highly recommend posting an MCVE similar to mine and posting a new question. Good luck.
I was trying to implement the IBVS algorithm (the one explained in the Introduction here) in MATLAB myself, but I am facing the following problem : The algorithm seems to work only for the cases that the camera does not have to change its orientation in respect to the world frame.For example, if I just try to make one vertex of the initial (almost) square go closer to its opposite vertex, the algorithm does not work, as can be seen in the following image
The red x are the desired projections, the blue circles are the initial ones and the green ones are the ones I get from my algorithm.
Also the errors are not exponentially dereasing as they should.
What am I doing wrong? I am attaching my MATLAB code which is fully runable. If anyone could take a look, I would be really grateful. I took out the code that was performing the plotting. I hope it is more readable now. Visual servoing has to be performed with at least 4 target points, because else the problem has no unique solution. If you are willing to help, I would suggest you take a look at the calc_Rotation_matrix() function to check that the rotation matrix is properly calculated, then verify that the line ds = vc; in euler_ode is correct. The camera orientation is expressed in Euler angles according to this convention. Finally, one could check if the interaction matrix L is properly calculated.
function VisualServo()
global A3D B3D C3D D3D A B C D Ad Bd Cd Dd
%coordinates of the 4 points wrt camera frame
A3D = [-0.2633;0.27547;0.8956];
B3D = [0.2863;-0.2749;0.8937];
C3D = [-0.2637;-0.2746;0.8977];
D3D = [0.2866;0.2751;0.8916];
%initial projections (computed here only to show their relation with the desired ones)
A=A3D(1:2)/A3D(3);
B=B3D(1:2)/B3D(3);
C=C3D(1:2)/C3D(3);
D=D3D(1:2)/D3D(3);
%initial camera position and orientation
%orientation is expressed in Euler angles (X-Y-Z around the inertial frame
%of reference)
cam=[0;0;0;0;0;0];
%desired projections
Ad=A+[0.1;0];
Bd=B;
Cd=C+[0.1;0];
Dd=D;
t0 = 0;
tf = 50;
s0 = cam;
%time step
dt=0.01;
t = euler_ode(t0, tf, dt, s0);
end
function ts = euler_ode(t0,tf,dt,s0)
global A3D B3D C3D D3D Ad Bd Cd Dd
s = s0;
ts=[];
for t=t0:dt:tf
ts(end+1)=t;
cam = s;
% rotation matrix R_WCS_CCS
R = calc_Rotation_matrix(cam(4),cam(5),cam(6));
r = cam(1:3);
% 3D coordinates of the 4 points wrt the NEW camera frame
A3D_cam = R'*(A3D-r);
B3D_cam = R'*(B3D-r);
C3D_cam = R'*(C3D-r);
D3D_cam = R'*(D3D-r);
% NEW projections
A=A3D_cam(1:2)/A3D_cam(3);
B=B3D_cam(1:2)/B3D_cam(3);
C=C3D_cam(1:2)/C3D_cam(3);
D=D3D_cam(1:2)/D3D_cam(3);
% computing the L matrices
L1 = L_matrix(A(1),A(2),A3D_cam(3));
L2 = L_matrix(B(1),B(2),B3D_cam(3));
L3 = L_matrix(C(1),C(2),C3D_cam(3));
L4 = L_matrix(D(1),D(2),D3D_cam(3));
L = [L1;L2;L3;L4];
%updating the projection errors
e = [A-Ad;B-Bd;C-Cd;D-Dd];
%compute camera velocity
vc = -0.5*pinv(L)*e;
%change of the camera position and orientation
ds = vc;
%update camera position and orientation
s = s + ds*dt;
end
ts(end+1)=tf+dt;
end
function R = calc_Rotation_matrix(theta_x, theta_y, theta_z)
Rx = [1 0 0; 0 cos(theta_x) -sin(theta_x); 0 sin(theta_x) cos(theta_x)];
Ry = [cos(theta_y) 0 sin(theta_y); 0 1 0; -sin(theta_y) 0 cos(theta_y)];
Rz = [cos(theta_z) -sin(theta_z) 0; sin(theta_z) cos(theta_z) 0; 0 0 1];
R = Rx*Ry*Rz;
end
function L = L_matrix(x,y,z)
L = [-1/z,0,x/z,x*y,-(1+x^2),y;
0,-1/z,y/z,1+y^2,-x*y,-x];
end
Cases that work:
Ad=2*A;
Bd=2*B;
Cd=2*C;
Dd=2*D;
Ad=A+1;
Bd=B+1;
Cd=C+1;
Dd=D+1;
Ad=2*A+1;
Bd=2*B+1;
Cd=2*C+1;
Dd=2*D+1;
Cases that do NOT work:
Rotation by 90 degrees and zoom out (zoom out alone works, but I am doing it here for better visualization)
Ad=2*D;
Bd=2*C;
Cd=2*A;
Dd=2*B;
Your problem comes from the way you move the camera from the resulting visual servoing velocity. Rather than
cam = cam + vc*dt;
you should compute the new camera position using the exponential map
cam = cam*expm(vc*dt)
I wish to determine the intersection point between a ray and a box. The box is defined by its min 3D coordinate and max 3D coordinate and the ray is defined by its origin and the direction to which it points.
Currently, I am forming a plane for each face of the box and I'm intersecting the ray with the plane. If the ray intersects the plane, then I check whether or not the intersection point is actually on the surface of the box. If so, I check whether it is the closest intersection for this ray and I return the closest intersection.
The way I check whether the plane-intersection point is on the box surface itself is through a function
bool PointOnBoxFace(R3Point point, R3Point corner1, R3Point corner2)
{
double min_x = min(corner1.X(), corner2.X());
double max_x = max(corner1.X(), corner2.X());
double min_y = min(corner1.Y(), corner2.Y());
double max_y = max(corner1.Y(), corner2.Y());
double min_z = min(corner1.Z(), corner2.Z());
double max_z = max(corner1.Z(), corner2.Z());
if(point.X() >= min_x && point.X() <= max_x &&
point.Y() >= min_y && point.Y() <= max_y &&
point.Z() >= min_z && point.Z() <= max_z)
return true;
return false;
}
where corner1 is one corner of the rectangle for that box face and corner2 is the opposite corner. My implementation works most of the time but sometimes it gives me the wrong intersection. Please see image:
The image shows rays coming from the camera's eye and hitting the box surface. The other rays are the normals to the box surface. It can be seen that the one ray in particular (it's actually the normal that is seen) comes out from the "back" of the box, whereas the normal should be coming up from the top of the box. This seems to be strange since there are multiple other rays that hit the top of the box correctly.
I was wondering if the way I'm checking whether the intersection point is on the box is correct or if I should use some other algorithm.
Thanks.
Increasing things by epsilon is not actually a great way to do this, as you now have a border of size epsilon at the edge of your box through which rays can pass. So you'll get rid of this (relatively common) weird set of errors, and end up with another (rarer) set of weird errors.
I assume that you're already envisioning that your ray is traveling at some speed along its vector and find the time of intersection with each plane. So, for example, if you are intersecting the plane at x=x0, and your ray is going in direction (rx,ry,rz) from (0,0,0), then the time of intersection is t = x0/rx. If t is negative, ignore it--you're going the other way. If t is zero, you have to decide how to handle that special case--if you're in a plane already, do you bounce off it, or pass through it? You may also want to handle rx==0 as a special case (so that you can hit the edge of the box).
Anyway, now you have exactly the coordinates where you struck that plane: they are (t*rx , t*ry , t*rz). Now you can just read off whether t*ry and t*rz are within the rectangle they need to be in (i.e. between the min and max for the cube along those axes). You don't test the x coordinate because you already know that you hit it Again, you have to decide whether/how to handle hitting corners as a special case. Furthermore, now you can order your collisions with the various surfaces by time and pick the first one as your collision point.
This allows you to compute, without resorting to arbitrary epsilon-factors, whether and where your ray intersects your cube, to the accuracy possible with floating point arithmetic.
So you just need three functions like the one you've already got: one for testing whether you hit within yz assuming you hit x, and the corresponding ones for xz and xy assuming that you hit y and z respectively.
Edit: code added to (verbosely) show how to do the tests differently for each axis:
#define X_FACE 0
#define Y_FACE 1
#define Z_FACE 2
#define MAX_FACE 4
// true if we hit a box face, false otherwise
bool hit_face(double uhit,double vhit,
double umin,double umax,double vmin,double vmax)
{
return (umin <= uhit && uhit <= umax && vmin <= vhit && vhit <= vmax);
}
// 0.0 if we missed, the time of impact otherwise
double hit_box(double rx,double ry, double rz,
double min_x,double min_y,double min_z,
double max_x,double max_y,double max_z)
{
double times[6];
bool hits[6];
int faces[6];
double t;
if (rx==0) { times[0] = times[1] = 0.0; }
else {
t = min_x/rx;
times[0] = t; faces[0] = X_FACE;
hits[0] = hit_box(t*ry , t*rz , min_y , max_y , min_z , max_z);
t = max_x/rx;
times[1] = t; faces[1] = X_FACE + MAX_FACE;
hits[1] = hit_box(t*ry , t*rz , min_y , max_y , min_z , max_z);
}
if (ry==0) { times[2] = times[3] = 0.0; }
else {
t = min_y/ry;
times[2] = t; faces[2] = Y_FACE;
hits[2] = hit_box(t*rx , t*rz , min_x , max_x , min_z , max_z);
t = max_y/ry;
times[3] = t; faces[3] = Y_FACE + MAX_FACE;
hits[3] = hit_box(t*rx , t*rz , min_x , max_x , min_z , max_z);
}
if (rz==0) { times[4] = times[5] = 0.0; }
else {
t = min_z/rz;
times[4] = t; faces[4] = Z_FACE;
hits[4] = hit_box(t*rx , t*ry , min_x , max_x , min_y , max_y);
t = max_z/rz;
times[5] = t; faces[5] = Z_FACE + MAX_FACE;
hits[5] = hit_box(t*rx , t*ry , min_x , max_x , min_y , max_y);
}
int first = 6;
t = 0.0;
for (int i=0 ; i<6 ; i++) {
if (times[i] > 0.0 && (times[i]<t || t==0.0)) {
first = i;
t = times[i];
}
}
if (first>5) return 0.0; // Found nothing
else return times[first]; // Probably want hits[first] and faces[first] also....
}
(I just typed this, didn't compile it, so beware of bugs.)
(Edit: just corrected an i -> first.)
Anyway, the point is that you treat the three directions separately, and test to see whether the impact has occurred within the right box in (u,v) coordinates, where (u,v) are either (x,y), (x,z), or (y,z) depending on which plane you hit.
PointOnBoxFace should be a two-dimensional check instead of three-dimensional. For example, if you're testing against the z = z_min plane, then you should only need to compare x and y to their respective boundaries. You've already figured out that z coordinate is correct. Floating point precision is likely tripping you up as you "re-check" the third coordinate.
For example, if z_min is 1.0, you first test against that plane. You find an intersection point of (x, y, 0.999999999). Now, even though x and y are within bounds, the z isn't quite right.
Code looks fine. Try to find this particular ray and debug it.
Could it be that that ray ends up passing exactly through the edge of the box? Floating point roundoff errors might cause it to be missed by both the right and the back face.
EDIT: Ignore this answer (see comments below where I am quite convincingly shown the error of my ways).
You are testing whether the point is inside the volume, but the point is on the periphery of that volume, so you may find that it is an "infinitesimal" distance outside the volume. Try growing the box by some small epsilon, e.g.:
double epsilon = 1e-10; // Depends the scale of things in your code.
double min_x = min(corner1.X(), corner2.X()) - epsilon;
double max_x = max(corner1.X(), corner2.X()) + epsilon;
double min_y = min(corner1.Y(), corner2.Y()) - epsilon;
...
Technically, the correct way to compare almost-equal numbers is to cast their bit representations to ints and compare the integers for some small offset, e.g., in C:
#define EPSILON 10 /* some small int; tune to suit */
int almostequal(double a, double b) {
return llabs(*(long long*)&a - *(long long*)&b) < EPSILON;
}
Of course, this isn't so easy in C#, but perhaps unsafe semantics can achieve the same effect. (Thanks to #Novox for his comments, which lead me to a nice page explaining this technique in detail.)
I have a simple sketch (in Processing), basically a bunch of dots wander around, if they come into contact with each other they fight (each has a strength value, increased each time they win, if it's equal the winner is randomly chosen)
It works well with about 5000 12-pixel "zombies" (there's a slight slowdown for a half a second, while the zombies initially collide with each other), the problem is when the zombies are made smaller, they don't collide with each other as quick, and the slowdown can last much longer..
The code is really simple - basically each zombie is a class, which has an X/Y coordinate. Each frame all the zombies are nudged one pixel, randomly turning lurching degrees (or not). I think the biggest cause of slowness is the collision detection - each zombie checks every other one (so zombie 1 checks 2-5000, zombie 2 checks 1,3-5000 etc..)
I'd like to keep everything simple, and "plain Processing" (not using external libraries, which might be more efficient and easy, but I don't find it very useful for learning)
int numZombies = 5000;
Zombie[] zombies = new Zombie[numZombies];
void setup(){
size(512, 512);
noStroke();
for(int i = 0; i < numZombies; i++){
zombies[i] = new Zombie(i, random(width), random(height), random(360), zombies);
}
}
void draw(){
background(0);
for(int i = 0; i < numZombies; i++){
zombies[i].move();
zombies[i].display();
}
}
class Zombie{
int id; // the index of this zombie
float x, y; // current location
float angle; // angle of zombies movement
float lurching = 10; // Amount angle can change
float strength = 2;
boolean dead = false; // true means zombie is dead
float diameter = 12; // How big the zombie is
float velocity = 1.0; // How fast zombie moves
Zombie[] others; // Stores the other zombies
Zombie(int inid, float xin, float yin, float inangle, Zombie[] oin){
id = inid;
x = xin;
y = yin;
angle = inangle;
others = oin;
}
void move(){
if(dead) return;
float vx = velocity * sin(radians(180-angle));
float vy = velocity * cos(radians(180-angle));
x = x + vx;
y = y + vy;
if(x + vx < 0 || x + vx > width || y + vy < 0 || y + vy > height){
// Collided with wall
angle = angle + 180;
}
float adecide = random(3);
if(adecide < 1){
// Move left
angle=angle - lurching;
}
else if(adecide > 1 && adecide < 2){
// Don't move x
}
else if(adecide > 2){
// Move right
angle = angle + lurching;
}
checkFights();
}
void checkFights(){
for (int i=0; i < numZombies; i++) {
if (i == id || dead || others[i].dead){
continue;
}
float dx = others[i].x - x;
float dy = others[i].y - y;
float distance = sqrt(dx*dx + dy*dy);
if (distance < diameter){
fight(i);
}
}
}
void fight(int oid){
Zombie o = others[oid];
//println("Zombie " + id + "(s: "+ strength +") fighting " + oid + "(s: "+ o.strength +")");
if(strength < o.strength){
kill();
o.strength++;
}
else if (strength == o.strength){
if(random(1) > 0.5){
kill();
o.strength++;
}
else{
o.kill();
strength++;
}
}
}
void kill(){
dead = true;
}
void display(){
if(dead) return;
ellipse(x, y, diameter, diameter);
}
}
You got yourself O(n^2) complexity, and that's killing your algorithm. It's correct that each zombie that moves has to check with all the others if they collided which brings you to quadratic complexity.
One direction might be to create a matrix representing your screen, and instead of iterating over all the other zombies, simply update the current zombie's location on the matrix, and check there if another zombie is already occupying that same cell.
Like 1800 INFORMATION says, somehow you need to reduce the number of comparisons.
Splitting the playing area into zones is a good idea. I would imagine the time it takes to compare current location against zone boundaries and add/remove zombies from the appropriate collections is worth it. Assuming they generally will go in straight lines, they shouldn't be changing zones too frequently.
We have the problem though of possible collisions between zones. To piggyback on the idea, you could divide the screen into 4 zones then 9 zones again. Think a tic-tac-toe board overlaid on a cross. This is a bad drawing, but:
| ! |
| ! |
----+--!-+----
| ! |
====|==x=|====
----+--!-+----
| ! |
| ! |
This way each zombie is in two zones at once and every border in one scheme is covered by another zone. You wouldn't even have to check all the same zombies again because either we'd be dead or they would. So the only double-processing is a single others[i].dead check.
Another thing I can see quickly is you still loop through the rest of the elements even though you're dead:
if (i == id || dead || others[i].dead){
continue;
}
It might not save a lot of processing, but it can certainly cut some instructions if you:
if (dead) return;
instead.
Also as a side note, do you want to be checking the diameter or the radius against the distance?
Your basic collision detection algorithm has O(n^2) complexity.
You need some approach which will reduce the number of comparisons.
One approach already mentioned, is to divide the playing field into zones/regions, and
only check for collision when a zombie is in the same zone/region. This is an attempt
to sort the entities topologically (by distance). What you want is to separate these
zombies not simply by geography, but to sort them so that they are only compared when
they are 'close' to one another. And you want to ignore empty regions.
Consider a tree structure to your regions. When a region has more than some number N of zombies, you could split the region smaller, until the region radius approaches your collision distance. Use a map to lookup region, and check all zombies in a given region (and any 'close enough' region).
You probably want N to be <= log(n)...
Maybe you should split the playing field up into zones and only check for collisions between zombies that are in the same zone. You need to reduce the number of comparisons.
It reminds me of this thread: No idea what could be the problem!!. And collision detection help where I point to Wikipedia's Collision detection article.
Quadtrees seem to be often used for 2D partitioning.