If you look at the constructor it sets the initial motion and the life of the particles and then the onUpdate() updates the position. So you would put in what you want -- do you want them to start out in specific directions, move fast or slow, move randomly, move straight or in circles, etc.
And to spawn on the walls you just need to set their initial position to be where the wall is. Whether or not the wall is easy to detect would depend on whether the size and shape of the room is already expected to be a certain way or whether you want your particles to be smart enough to go around any shape and size of room.
However, I looked at that video you posted again and it is possible that they did not use particles. They may just be doing some sort of render effect.
Anyway, I think it would be possible for the disco ball in that example to have a TileEntity associated which is controlling the effect. In fact, if you keep track of the particles that are created, the TileEntity itself should be able to update the position.
I downloaded this mod to play with some mates and found that the classes to do with the Block are as followed:
BlockClass
and a TileEntityBlockClass
(I can't quite remember what they were named)
How would i achieve a similar effect with the tile entity because i have never seen anything like this before.
EDIT: I have opened the class file to try and see what is going on. This is it:
package maaatin.disco;
import abw;
import asp;
import asx;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
import java.util.Random;
public class TileEntityDiscoBall extends asp
{
public int lightsPerRow;
public int height;
public int resolution;
public double[][][] possibleLightCoords;
public int[][] orientations;
public double[][][] allLightXCoordinates;
public double[][][] allLightYCoordinates;
public double[][][] allLightZCoordinates;
public int[][][] allOrientations;
public int lightRange;
public double angle;
public boolean initialized;
public int[][] rand;
public int counter;
public double orientationAngle;
public int speed;
public TileEntityDiscoBall()
{
this.lightsPerRow = 16;
this.height = 9;
this.resolution = 300;
this.possibleLightCoords = new double[3][this.resolution][this.height];
this.orientations = new int[this.resolution][this.height];
this.allLightXCoordinates = new double[this.lightsPerRow][this.height][this.resolution];
this.allLightYCoordinates = new double[this.lightsPerRow][this.height][this.resolution];
this.allLightZCoordinates = new double[this.lightsPerRow][this.height][this.resolution];
this.allOrientations = new int[this.lightsPerRow][this.height][this.resolution];
this.lightRange = 16;
this.angle = 0.0D;
this.initialized = false;
this.rand = new int[60][60];
this.speed = 100;
}
public void h()
{
if (!this.initialized)
{
initialize();
}
}
@SideOnly(Side.CLIENT)
public asx getRenderBoundingBox()
{
return INFINITE_EXTENT_AABB;
}
public void initialize()
{
boolean stopLoop = false;
for (int h = 1; h < this.height; h++)
{
if ((!this.k.c(this.l, this.m - h, this.n)) && (!stopLoop))
{
this.height = h;
stopLoop = true;
}
}
for (int h = 0; h < this.height; h++)
{
for (int i = 0; i < this.lightsPerRow; i++)
{
this.rand[i][h] = this.k.s.nextInt(this.resolution / 10);
}
}
for (int h = 0; h < this.height; h++)
{
this.counter = (this.resolution - 1);
this.angle = 0.0D;
for (int i = this.resolution - 1; i >= 0; i--)
{
getCoords(this.l + 0.5D, this.m + 0.5D - h, this.n + 0.5D, this.k, this.angle, h);
this.angle += 3.141592653589793D / (this.resolution / 2.0D);
this.counter -= 1;
}
}
for (int h = 0; h < this.height; h++)
{
for (int i = 0; i < this.lightsPerRow; i++)
{
for (int j = 0; j < this.resolution; j++)
{
this.allLightXCoordinates[i][h][j] = this.possibleLightCoords[0][((j + (this.rand[i][h] + this.resolution * i / this.lightsPerRow)) % this.resolution)][h];
this.allLightYCoordinates[i][h][j] = this.possibleLightCoords[1][((j + (this.rand[i][h] + this.resolution * i / this.lightsPerRow)) % this.resolution)][h];
this.allLightZCoordinates[i][h][j] = this.possibleLightCoords[2][((j + (this.rand[i][h] + this.resolution * i / this.lightsPerRow)) % this.resolution)][h];
this.allOrientations[i][h][j] = this.orientations[((j + (this.rand[i][h] + this.resolution * i / this.lightsPerRow)) % this.resolution)][h];
}
}
}
this.initialized = true;
}
public void getCoords(double x, double y, double z, abw world, double angle, int h)
{
boolean coordinateFilled = false;
for (int i = 1; i < this.lightRange; i++)
{
if ((!coordinateFilled) && (!world.c(truncateDoubleToInt(x + i * Math.cos(angle)), (int)y, truncateDoubleToInt(z + i * Math.sin(angle)))))
{
if (world.c(truncateDoubleToInt(x + (i - 0.1D) * Math.cos(angle)), (int)y, truncateDoubleToInt(z + (i - 0.1D) * Math.sin(angle))))
{
fillCoords(0.1D, x, y, z, i, h);
}
else if (world.c(truncateDoubleToInt(x + (i - 0.2D) * Math.cos(angle)), (int)y, truncateDoubleToInt(z + (i - 0.2D) * Math.sin(angle))))
{
fillCoords(0.2D, x, y, z, i, h);
}
else if (world.c(truncateDoubleToInt(x + (i - 0.3D) * Math.cos(angle)), (int)y, truncateDoubleToInt(z + (i - 0.3D) * Math.sin(angle))))
{
fillCoords(0.3D, x, y, z, i, h);
}
else if (world.c(truncateDoubleToInt(x + (i - 0.4D) * Math.cos(angle)), (int)y, truncateDoubleToInt(z + (i - 0.4D) * Math.sin(angle))))
{
fillCoords(0.4D, x, y, z, i, h);
}
else if (world.c(truncateDoubleToInt(x + (i - 0.5D) * Math.cos(angle)), (int)y, truncateDoubleToInt(z + (i - 0.5D) * Math.sin(angle))))
{
fillCoords(0.5D, x, y, z, i, h);
}
else if (world.c(truncateDoubleToInt(x + (i - 0.6D) * Math.cos(angle)), (int)y, truncateDoubleToInt(z + (i - 0.6D) * Math.sin(angle))))
{
fillCoords(0.6D, x, y, z, i, h);
}
else if (world.c(truncateDoubleToInt(x + (i - 0.7D) * Math.cos(angle)), (int)y, truncateDoubleToInt(z + (i - 0.7D) * Math.sin(angle))))
{
fillCoords(0.7D, x, y, z, i, h);
}
else if (world.c(truncateDoubleToInt(x + (i - 0.8D) * Math.cos(angle)), (int)y, truncateDoubleToInt(z + (i - 0.8D) * Math.sin(angle))))
{
fillCoords(0.8D, x, y, z, i, h);
}
else if (world.c(truncateDoubleToInt(x + (i - 0.9D) * Math.cos(angle)), (int)y, truncateDoubleToInt(z + (i - 0.9D) * Math.sin(angle))))
{
fillCoords(0.9D, x, y, z, i, h);
}
else
{
fillCoords(1.0D, x, y, z, i, h);
}
coordinateFilled = true;
}
}
}
public void fillCoords(double j, double x, double y, double z, int i, int h)
{
this.possibleLightCoords[0][this.counter][h] = (x + (i - j) * Math.cos(this.angle));
this.possibleLightCoords[1][this.counter][h] = y;
this.possibleLightCoords[2][this.counter][h] = (z + (i - j) * Math.sin(this.angle));
this.orientations[this.counter][h] = getOrientation(this.possibleLightCoords[0][this.counter][h], this.possibleLightCoords[1][this.counter][h], this.possibleLightCoords[2][this.counter][h]);
}
public int getOrientation(double x, double y, double z)
{
this.orientationAngle = 0.0D;
for (int i = 0; i < 4; i++)
{
double j = 0.2D;
if (!this.k.c(truncateDoubleToInt(x + j * Math.cos(this.orientationAngle)), truncateDoubleToInt(y), truncateDoubleToInt(z + j * Math.sin(this.orientationAngle))))
{
return i;
}
this.orientationAngle += 1.570796326794897D;
}
return 0;
}
public static int truncateDoubleToInt(double par0)
{
return (int)(par0 + 1024.0D) - 1024;
}
}
Now i this abw is World. asp is TileEntity and asx is maybe Block.
I cannot see how this is working just due to the lack of methods actually listed.