Download Reference Manual
The Developer's Library for D
About Wiki Forums Source Search Contact

Collection Class

Moderators: larsivi kris

Posted: 02/28/07 22:18:39

Hi,

My first Tango related programming question.... Ok, I'm trying to create a collection class using a linked list and having an issue.

This is basically what I'm trying to do, minus all the extra code in my program:

import tango.util.collection.LinkSeq;
auto bird = new LinkSeq!(BOID);

class BOID{

	int velocity;
	int position;

}

At compile time I get the following:

boids.d(137): Error: non-constant expression new LinkSeq!(BOID) 

Any ideas what I'm missing?

Thanks, Mason

Author Message

Posted: 03/01/07 00:08:50

Try this:

import tango.util.collection.LinkSeq;

LinkSeq!(BOID) bird;

static this()
{
    bird = new LinkSeq!(BOID);
}

class BOID
{
    int velocity;
    int position;

}

D doesn't allow you to construct static objects at module scope--you have to do so inside a static ctor or inside a function. What's happening is that the compiler things you're trying to assign to a const, and the new preprocessor features can't do so.

Posted: 03/01/07 04:03:41

D doesn't allow you to construct static objects at module scope--you have to do so inside a static ctor or inside a 
function.  What's happening is that the compiler things you're trying to assign to a const, and the new preprocessor
features can't do so.

Sean,

Great, thanks a lot. I moved bird = new LinkSeq?!(BOID); inside my class constructor and it worked! My next question: after I have appended a few objects to the list, how do I find the size (number of objects added) of the list?

Mason

Posted: 03/01/07 06:37:39

bird.size should do it.

Not that easy to find, but here it is: http://www.dsource.org/projects/tango/docs/current/tango.util.collection.impl.Collection.html

Posted: 03/01/07 12:07:34

torhu wrote:

Cool, that does it! Thanks a lot!

Right now I'm playing around to learn the basics. Maybe when I'm finished I could upload my code to serve as a quick example for others?

Mason

Posted: 03/01/07 12:43:40

zzzzrrr wrote:

Right now I'm playing around to learn the basics. Maybe when I'm finished I could upload my code to serve as a quick example for others?

Mason

It would be nice if you could post it here, and we may adapt it for the example folder in the distribution :)

Posted: 03/06/07 02:53:36

larsivi wrote:

It would be nice if you could post it here, and we may adapt it for the example folder in the distribution :)

Ok, here is my first D program. I think it's fairly cool. Hopefully other D newcomers may find it useful.... Please let me know what you think....

/* Boids 2D v0.1
 *
 * I wrote this program as a means to familiarize myself with the D 
 * programming language and the Tango and Derelict libraries. Hopefully
 * others will find it useful as a learning tool.
 * 
 * The following sources were utilized for help on this project:
 *
 *	1. Conrad Parker's Boids Pseudocode  
 *		http://www.vergenet.net/~conrad/boids/pseudocode.html
 *	2. Stephen Chappell's Boids Python Code  
 *		http://aspn.activestate.com/ASPN/Python/Cookbook/
 *
 * Stephen Chappell's Python code inspired me to write my own version in D.  
 * Although I utilized many of Stephen's program variables to tweak my Boid 
 * behavior, Conrad Parker's pseudocode served as a primary reference. OpenGL 
 * and SDL code gleaned from various tutorials.
 *
 * Many thanks to the Tango and Derelict projects, and to Walter Brightfor D!
 * 
 * Author: Mason Green (mason.green@gmail.com)
 *	
 * Future ideas: Animation, Obstacles, 3D? 	
 *
 */
module boidGL;

import derelict.opengl.gl;		
import derelict.opengl.glu;
import derelict.sdl.sdl;

import tango.math.Core;			// Tango Rules!!
import tango.stdc.stringz;

import sky;

const int NUM_BOIDS = 30;

//Boid Boundaries
const int XMIN = 10;
const int XMAX = 950;
const int YMIN = 10;
const int YMAX = 790;

const int VLIM = 400;                	// Velocity limit
const int SLIM = 120;          		// Smooths the velocity step
const int WALL_FORCE = 30;		// Wall Repulsion	

const char[] WINDOW_TITLE = "Boids 2D v0.1";

//The screen attributes
const int SCREEN_WIDTH = 1000;
const int SCREEN_HEIGHT = 800;
const int SCREEN_BPP = 32;



// Circle variables
const float RAD2DEG = 0.0174532925;
const float ANGLE_STEP = PI/180.0;	 
const double RADIUS = 3;

bool running;				// The main loop flag

//Module constructor. 
static this(){

	DerelictGL.load();		// Load Derelict libraries
	DerelictGLU.load();
    	DerelictSDL.load();

    	if (SDL_Init(SDL_INIT_VIDEO) < 0)
        	throw new Exception("Failed to initialize SDL: " ~ getSDLError());
    
}

// Module destructor
static ~this(){
    
	SDL_Quit();

}

// Main
void main(char[][] args){
    
	bool fullScreen = false;
    	auto flock = new Sky(NUM_BOIDS, XMIN, XMAX, YMIN, YMAX, VLIM, WALL_FORCE, SLIM, RADIUS);
  
    	if (args.length > 1) fullScreen = args[1] == "-fullscreen";
    

	createGLWindow(WINDOW_TITLE, SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_BPP, fullScreen);
    
	initGL();

	flock.initPosition();
	
    	running = true;
    	while (running){		// Main Program Loop

		processEvents();        // User input
		flock.moveBoids();      // Update Boids
       		drawFillCircle(flock);  // Draw Boids

        	SDL_GL_SwapBuffers();
        	SDL_Delay(10);          // Pause
    }
}

// Process all the pending events.

void processEvents()
{
    SDL_Event event;
    while (SDL_PollEvent(&event))
    {
        switch (event.type)
        {
            case SDL_KEYUP:
                keyReleased(event.key.keysym.sym);
                break;
            case SDL_QUIT:
                running = false;
                break;
            default:
                break;
        }
    }
}

// Process a key released event.

void keyReleased(int key)
{
    switch (key)
    {
        case SDLK_ESCAPE:
            running = false;
            break;
        default:
            break;
    }
}

// Initialize OpenGL.
void initGL()
{
   
	glLoadIdentity();

	glMatrixMode( GL_PROJECTION );
	gluOrtho2D(0,SCREEN_WIDTH,0,SCREEN_HEIGHT);	// Use 2d Coordinate system
	glMatrixMode( GL_MODELVIEW );
        glDisable(GL_DEPTH_TEST);
    	 
    	glShadeModel(GL_SMOOTH);
    	glClearColor(0.0f, 0.0f, 0.0f, 0.0f); 		// Black Background
      
    	glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
	glLoadIdentity();

}

// Draw the Boids. 

void drawFillCircle(Sky flock){

	
	double vectorX1,vectorY1;		// vector to a point on circle from its center
	double vectorX0,vectorY0;		// previous version of vectorX1,Y1;
	double angle;				// Angle in radians from circle start point.
	
	// Clear The Screen And The Depth Buffer
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	// Reset The Current Modelview Matrix
	glLoadIdentity();
	glColor3f(1.0f, 0.0f, 0.0f);

	foreach(Boid b; flock.boids){ 
 	
		double xctr = b.position.x;
		double yctr = b.position.y;
		
		glBegin(GL_TRIANGLES);		// Tell OpenGL to draw a series of triangles
		
		vectorX1 = xctr + RADIUS;	// Start at the circle's rightmost point.
		vectorY1 = yctr;		
		
		for(angle=ANGLE_STEP;		// step through all other points on circle;
		    angle < 2.0*PI + ANGLE_STEP; angle+= ANGLE_STEP){    // (>2PI so that circle is always closed)
			
			vectorX0 = vectorX1;		// save previous point's position,
			vectorY0 = vectorY1;
			vectorX1= xctr + RADIUS*cos(angle);	// find a new point on the circle,
			vectorY1= yctr + RADIUS*sin(angle);		
			glVertex2d(xctr,yctr);		// plot the points of a triangle (CCW order)
			glVertex2d(vectorX0,vectorY0);	// center-->old pt-->new pt.
			glVertex2d(vectorX1,vectorY1);
		}

		glEnd(); 		// finished drawing triangles.
		glLoadIdentity();
		glFlush();		// Finish any pending drawing commands
	}
}

// Initializes and opens the SDL window.

void createGLWindow(char[] title, int width, int height, int bits,
    bool fullScreen){

	// Set the OpenGL attributes
    	SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5);
    	SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 6);
    	SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 5);
    	SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16);
    	SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);

    	// Set the window title
    	SDL_WM_SetCaption(toUtf8z(title), null);

    	// Note the SDL_DOUBLEBUF flag is not required to enable double
    	// buffering when setting an OpenGL video mode.
    	// Double buffering is enabled or disabled using the
    	// SDL_GL_DOUBLEBUFFER attribute. (See above.)
    	int mode = SDL_OPENGL;
    	if (fullScreen) mode |= SDL_FULLSCREEN;
    
	// Now open a SDL OpenGL window with the given parameters
    	if (SDL_SetVideoMode(width, height, bits, mode) is null){
           throw new Exception("Failed to open OpenGL window: " ~ getSDLError());
    	}
}

/* Get the SDL error as a D string. 
 * Returns: A D string containing the current SDL error.
 */

char[] getSDLError()
{
    return fromUtf8z(SDL_GetError());
}
/* Boids 2D v0.1
 *
 * I wrote this program as a means to familiarize myself with the D 
 * programming language and the Tango and Derelict libraries. Hopefully
 * others will find it useful as a learning tool.
 * 
 * The following sources were utilized for help on this project:
 *
 *	1. Conrad Parker's Boids Pseudocode  
 *		http://www.vergenet.net/~conrad/boids/pseudocode.html
 *	2. Stephen Chappell's Boids Python Code  
 *		http://aspn.activestate.com/ASPN/Python/Cookbook/
 *
 * Stephen Chappell's Python code inspired me to write my own version in D.  
 * Although I utilized many of Stephen's program variables to tweak my Boid 
 * behavior, Conrad Parker's pseudocode served as a primary reference. OpenGL 
 * and SDL code gleaned from various tutorials.
 *
 * Many thanks to the Tango and Derelict projects, and to Walter Brightfor D!
 * 
 * Author: Mason Green (mason.green@gmail.com)
 *	
 * Future ideas: Animation, Obstacles, 3D? 	
 *
 */
module sky;

import tango.math.Core;			// Tango Rules!!
import tango.math.Random;
import tango.io.Stdout;

class Sky{
	
	this(int NUM_BOIDS, uint XMIN, int XMAX, int YMIN, uint YMAX, int VLIM, int WALL_FORCE, int SLIM, double RADIUS){

		numBoids = NUM_BOIDS;
		wallForce = WALL_FORCE;		
		xMax = XMAX; xMin = XMIN;
		yMax = YMAX; yMin = YMIN;
		vLim = VLIM; sLim = SLIM;
		radius = RADIUS;
		
		v1 = new Vector; v2 = new Vector; v3 = new Vector; 
		boids.length = numBoids;

		for(int i = 0; i < boids.length; i++)
			boids[i] = new Boid();
		
	}

public:

	Boid[] boids;

	void initPosition(){					// Start Boids in Random Positions

		auto rand = new Random;
			
		foreach(inout Boid b; boids){                  

			b.position.x = rand.next(xMax);		
			b.position.y = rand.next(yMax);
		}
	}

	void moveBoids(){

		foreach(inout Boid b; boids){

			bound(b);				// Stay inside the screen

			rule1(b);				// Clumping			  
			rule2(b);				// Avoidance
			rule3(b);				// Schooling
			
			b.velocity.add(v1,v2,v3);		// Add Vectors
			limitVelocity(b);			// Limit Velocity
			b.position.add(b.velocity, sLim);	// Add speed vector to position

		}
	}

private:

	Vector v1; Vector v2; Vector v3; 

	int xMax, xMin;
	int yMax, yMin;
	int vLim, sLim;
	int numBoids;
	int wallForce;
	double radius;
	
	void rule1(Boid x){					// Clumping	
	
		v1.x = v1.y = 0;

		auto pc = new Vector;

		foreach(Boid b; boids)
			if(b != x) pc.add(b.position); 

		pc.centerMass(numBoids);	
		v1.move(pc, x.position, 7.5);		 
				
	}

	void rule2(Boid x){					// Avoidance

		v2.x = v2.y = 0;

		foreach(Boid b; boids)
			if (b != x)
				if((x.position.range(b.position))<radius*8) 
					v2.repell(b.position,x.position);
		
	}

	void rule3(Boid x){					// Schooling
		
		v3.x = v3.y = 0;

		auto pv = new Vector;

		foreach(Boid b; boids)
			if(b != x) pv.add(b.velocity); 

		pv.centerMass(numBoids);
		v3.move(pv, x.velocity,8);	

	}

	void bound(Boid b){       				// Bound Position

		if (b.position.x < xMin) b.velocity.x += wallForce;
			else if (b.position.x > xMax) b.velocity.x -= wallForce;
		if (b.position.y < yMin)  b.velocity.y += wallForce;
			else if (b.position.y > yMax) b.velocity.y -= wallForce;

	}

	void limitVelocity(inout Boid b){			// Limit Velocity

		float mag;
	       	b.velocity.magnitude(mag);
		
		if(mag > vLim){

			b.velocity.x = (b.velocity.x / mag) * vLim;
			b.velocity.y = (b.velocity.y / mag) * vLim;
		}
	}
}

// Vector Class
class Vector{					

public:

	float x,y;

	this(){x = 0; y = 0;}
        
	void add(Vector v, int sLim){
		
		x =  x + v.x/(sLim); 		// sLim helps limit the velocity step
		y =  y + v.y/(sLim);
		
	}

	void add(Vector v){
		
		x += v.x;
		y += v.y;
		
	}

	void add(Vector v1, Vector v2, Vector v3){
		
		x += v1.x + v2.x + v3.x;
		y += v1.y + v2.y + v3.y;
		
	}

	void centerMass(int numBoids){

		x = x / (numBoids-1);
		y = y / (numBoids-1);

	}

	void move(Vector v1, Vector v2, float div){
		
		x = (v1.x-v2.x)/div;
		y = (v1.y-v2.y)/div;

	}		

	float range(Vector v){
		
		float d;
		float x2,y2;

		x2 = abs(x-v.x);
 		y2 = abs(y-v.y);

		d = sqrt((x2*x2+y2*y2));
		return(d);
	}

	void repell(Vector v1, Vector v2){

		x = (x - (v1.x-v2.x))*2;
		y = (y - (v1.y-v2.y))*2;

	}

	void magnitude(inout float mag){

		mag = sqrt(x*x+y*y);
			
	}
		
}

// Boid Class
class Boid{

public:

	Vector position;
	Vector velocity;

	this(){

		position = new Vector;
		velocity = new Vector;

	}
	
}

Any comments, complaints, or suggestions will be appreciated. Anyone interested in posting this in the tutorial section?