This is Celestial.m in view mode; [Download] [Up]
#import "Celestial.h" #import "TiffManager.h" #import "Thinker.h" #import <appkit/NXBitmapImageRep.h> #define PI (3.141592653589) #define MAXMULTBODY 10 //total multiple objects allowed @implementation Celestial - init { [super init]; tiffStorageIndex = 0; animationIndex = 0; tiffManagerObject = [[TiffManager alloc] init]; tiffStorage = [tiffManagerObject returnTiffStorage]; bodyList = [[List alloc] init]; avoidStorage = [[Storage allocFromZone:[self zone]] initCount:0 elementSize:sizeof(AvoidStruct) description:"{ffff}"]; okToDoAnim = NO; currentBodyIndex = 0; cycleStartIndex = 0; cycles = 0; currentCycle = 1; bodyCount = 0; tiffsNeedBuilding = YES; okToDoAnim = NO; multDelay = floor(randBetween(objectSpeed * 0.1, (objectSpeed * 0.1) + 10)); currentMultTotal = 1; [starsObject setStarsStopped]; PSsetlinewidth(4.0); //0.0 is more efficient but I liked this better return self; } // Every module should have a first state method //since class info only gets loaded once - therefore only 1 init called - setFirstState { firstState = YES; okToDoAnim = NO; cycleStartIndex = currentBodyIndex; bodyCount = 0; tiffsNeedBuilding = YES; okToDoAnim = NO; multDelay = floor(randBetween(objectSpeed * 0.1, (objectSpeed * 0.1) + 10)); currentMultTotal = 1; starsStopping = NO; //[starsObject isStopping]; //should be NO starsStopped = NO; //[starsObject isStopped]; //should be NO bodiesDone = 0; currentCycle = 1; return self; } - (BOOL)doUntilDone { BOOL done; int ii,count; done = NO; if(!starsStopping){ if(!okToDoAnim){ //go build the tiffs if(tiffsNeedBuilding){ tiffsNeedBuilding = [tiffManagerObject createTiffs]; } else { //do the animation set up totalBodies = [tiffStorage count]; animBuilt = (MAXANIMATIONS > totalBodies) ? totalBodies : MAXANIMATIONS; //pick smaller [self changeBodyList:currentBodyIndex]; if(soundEnabled) [pwrUpSnd play]; [starsObject startStars]; starsStopping = NO; //[starsObject isStopping]; //should be NO starsStopped = NO; //[starsObject isStopped]; //should be NO okToDoAnim = YES; } } //now do the animation else { if(nextStartTime < 0){ //time to do animation count = [bodyList count]; multDelay--; if(multDelay < 0){ // reset delay timer for next multiple object currentMultTotal++; if(currentMultTotal > count) currentMultTotal = count; multDelay = floor(randBetween(objectSpeed * 0.1, (objectSpeed * 0.1) + 10)); } if(count){ // there are some objects to do for(ii = 0;ii < currentMultTotal;ii++){ currentBody = [bodyList objectAt:ii]; if([currentBody doUntilDone]){ [bodyList removeObjectAt:ii]; ii--; currentMultTotal--; currentBody = [currentBody free]; } } [starsObject setAvoidRect:avoidStorage];//set avoidance for all //bodies } else { // object has zipped off screen //in case of multiple - last one has zipped off screen [self setNextStartTime]; currentMultTotal = 1; multDelay = floor(randBetween(objectSpeed * 0.1, (objectSpeed * 0.1) + 10)); bodyCount++; if(bodyCount >= animBuilt ){ //complete cycle is done currentCycle++; if(currentCycle > cycles){//done with this module if(!([starsObject isStopping])){ if(soundEnabled) [pwrDownSnd play]; [starsObject stopStars]; starsStopping = YES; } currentBodyIndex++; if(currentBodyIndex >= totalBodies) currentBodyIndex = 0; cycleStartIndex = currentBodyIndex; } else { currentBodyIndex = cycleStartIndex; bodyCount = 0; [self changeBodyList:currentBodyIndex]; //create body } } else { currentBodyIndex++; if(currentBodyIndex >= totalBodies) currentBodyIndex = 0; [self changeBodyList:currentBodyIndex]; //create body } } } else nextStartTime--; } } else{ //stars are stopping if(starsStopped){ PSsetlinewidth(0.0); //reset done = YES; } } return done; } - setStartInterval: (Slider *)sender; { startInterval = [sender intValue]; nextStartTime = 0; return self; } - setNextStartTime { nextStartTime = startInterval; return self; } - setPwrDownSnd:(Sound *)theSound { pwrDownSnd = theSound; return self; } - setPwrUpSnd:(Sound *)theSound; { pwrUpSnd = theSound; return self; } - setObjectSpeed: (Slider *)sender { objectSpeed =([sender maxValue] + [sender minValue]) - [sender floatValue]; return self; } - setBoundsRect:(NXRect *)r { bounds.origin.x = r->origin.x; bounds.origin.y = r->origin.y; bounds.size.width = r->size.width; bounds.size.height = r->size.height; return self; } - changeBodyList:(int)index { int ii; int total; AvoidStruct avoidStruct; for(ii=0;ii < 4;ii++) //init the lastTheta array lastTheta[ii] = -1; total = floor(randBetween(2,MAXMULTBODY)); if([bodyList count]){ [bodyList freeObjects]; } [avoidStorage empty]; isMult = ((ImageStruct *)[tiffStorage elementAt: index])->isMult; avoidStruct.avoid.origin.x = 0.0; avoidStruct.avoid.origin.y = 0.0; avoidStruct.avoid.size.width = 0.0; avoidStruct.avoid.size.height = 0.0; if(isMult){ for(ii=0;ii < total;ii++){ currentBody = [self createBody:index]; [currentBody setBodyIndex:ii]; [bodyList addObject:currentBody]; [avoidStorage addElement:&avoidStruct]; } } else{ currentBody = [self createBody:currentBodyIndex]; [bodyList addObject:currentBody]; [avoidStorage addElement:&avoidStruct]; } return self; } - (Body *)createBody:(int)index { Body *body; float theta; //angle of travel for new body float multObjectSpeed; body = [[Body alloc] init]; [body setAvoidStorage:avoidStorage]; [body setImageList:((ImageStruct *)[tiffStorage elementAt:index])->imageList]; [body setNumberOfFrames]; [body setBoundsRect:(NXRect *)&bounds]; //must be done after setCellSize if(isMult){ multObjectSpeed = objectSpeed + floor(randBetween(0,10)); [body setObjectSpeed:multObjectSpeed]; theta = [self genUniqueTheta]; //make sure mult objects stay clear //of each other } else{ [body setObjectSpeed:objectSpeed]; theta = randBetween(0,(2*PI)); } [body setAngle:theta]; [body setStarsOutlet: (id)starsObject]; return(body); } - starsStopped { starsStopped = YES; return self; } - setStarsOutlet:(id)starsOutlet; { starsObject = starsOutlet; return self; }// just a prototype - not used in this module - setStarSpeed:sender { return self; } //The idea here was that individual modules could decide //how to interpret the slider value // if you only want this module to do one pass etc. - (int)setCycleValue:(int)value; { int mutiplier; // since this module is interesting make it 5 times the slider value // could be zero mutiplier = 5; if(!value) value = 1; else value *= mutiplier; cycles = value; currentCycle = 1; return mutiplier; } - windowSizeChanged { if(currentBody){ //if one exists [self setNextStartTime]; //[bodyList freeObjects]; //printf("window size changed bodylist has %d elements\n", //[bodyList count]); currentMultTotal = 1; currentBody = nil; [self changeBodyList:currentBodyIndex]; } return self; } - freeResources { [tiffManagerObject freeTiffs]; if ([bodyList count]){ [bodyList freeObjects]; } return self; } // just a prototype - sound isn't used in this module - setSoundEnabled:(BOOL)enabled { soundEnabled = enabled; return self; } //for each 4 in a row - make sure random theta is // 40 degrees from any of the others - (float)genUniqueTheta { int ii; int maxTest = 4; float theta; BOOL thetaOK = NO; theta = randBetween(0,(2*PI)); while(!thetaOK){ thetaOK = YES; for(ii = 0;ii < maxTest;ii++){ if(lastTheta[ii] < 0) continue; //.69 = 40 degrees if(theta > (lastTheta[ii] - .69) && theta < (lastTheta[ii] + .69)){ thetaOK = NO; theta = randBetween(0,(2*PI)); } } } for(ii = 1;ii < maxTest;ii++){ lastTheta[ii-1] = lastTheta[ii]; } lastTheta[ii-1] = theta; return theta; } @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.