This is NekoView.m in view mode; [Download] [Up]
#import "NekoView.h" #import "Thinker.h" // based on xneko by Masayuki Koba // hacked into NeXTstep by Eric P. Scott // severely munged into BackSpace by sam streeper // go back to the X sources if you port this to other platforms... #import <libc.h> #import <math.h> #import <defaults/defaults.h> #import <appkit/graphics.h> #import <appkit/Application.h> #import <appkit/Window.h> #import <appkit/NXImage.h> #import <dpsclient/wraps.h> const NXCoord Even[]={ Mati2, // STATE_STOP Jare2, // STATE_JARE Kaki1, // STATE_KAKI Mati3, // STATE_AKUBI Sleep1, // STATE_SLEEP Awake, // STATE_AWAKE Up1, // STATE_U_MOVE Down1, // STATE_D_MOVE Left1, // STATE_L_MOVE Right1, // STATE_R_MOVE UpLeft1, // STATE_UL_MOVE UpRight1, // STATE_UR_MOVE DownLeft1, // STATE_DL_MOVE DownRight1, // STATE_DR_MOVE UpTogi1, // STATE_U_TOGI DownTogi1, // STATE_D_TOGI LeftTogi1, // STATE_L_TOGI RightTogi1 // STATE_R_TOGI }; const NXCoord Odd[]={ Mati2, // STATE_STOP Mati2, // STATE_JARE Kaki2, // STATE_KAKI Mati3, // STATE_AKUBI Sleep2, // STATE_SLEEP Awake, // STATE_AWAKE Up2, // STATE_U_MOVE Down2, // STATE_D_MOVE Left2, // STATE_L_MOVE Right2, // STATE_R_MOVE UpLeft2, // STATE_UL_MOVE UpRight2, // STATE_UR_MOVE DownLeft2, // STATE_DL_MOVE DownRight2, // STATE_DR_MOVE UpTogi2, // STATE_U_TOGI DownTogi2, // STATE_D_TOGI LeftTogi2, // STATE_L_TOGI RightTogi2 // STATE_R_TOGI }; #define PI_PER8 ((double)M_PI/(double)8) double SinPiPer8Times3; double SinPiPer8; @implementation NekoView - TickCount { if ( ++NekoTickCount >= MAX_TICK ) NekoTickCount = 0; if ( NekoTickCount % 2 == 0 ) if ( NekoStateCount < MAX_TICK ) NekoStateCount++; return self; } - SetNekoState: (int) SetValue { NekoTickCount=0; NekoStateCount=0; NekoState=SetValue; return self; } - DrawNeko: (NXCoord) DrawIcon { NekoLastIcon.origin.x=DrawIcon; if (NX_X(&NekoPos) != NekoLastXY.x || NX_Y(&NekoPos)!=NekoLastXY.y) { static const NXRect zero={ { Space, 0.0 }, { (NXCoord)BITMAP_WIDTH, (NXCoord)BITMAP_HEIGHT } }; [bitmaps composite:NX_SOVER fromRect:&zero toPoint:&NekoLastXY]; } [bitmaps composite:NX_SOVER fromRect:&NekoLastIcon toPoint:&NekoPos.origin]; NekoLastXY=NekoPos.origin; return self; } - NekoDirection { int NewState; double LargeX, LargeY; double Length; double SinTheta; if ( NekoMoveDx == 0 && NekoMoveDy == 0 ) NewState = STATE_STOP; else { LargeX = (double)NekoMoveDx; LargeY = (double)(-NekoMoveDy); Length = sqrt( LargeX * LargeX + LargeY * LargeY ); SinTheta = LargeY / Length; if ( NekoMoveDx > 0 ) { if ( SinTheta > SinPiPer8Times3 ) NewState = STATE_U_MOVE; else if ((SinTheta <= SinPiPer8Times3) && (SinTheta > SinPiPer8)) NewState = STATE_UR_MOVE; else if ((SinTheta <= SinPiPer8) && (SinTheta > -(SinPiPer8))) NewState = STATE_R_MOVE; else if ((SinTheta <= -SinPiPer8) && (SinTheta > -SinPiPer8Times3)) NewState = STATE_DR_MOVE; else NewState = STATE_D_MOVE; } else { if ( SinTheta > SinPiPer8Times3) NewState = STATE_U_MOVE; else if ((SinTheta <= SinPiPer8Times3) && (SinTheta > SinPiPer8)) NewState = STATE_UL_MOVE; else if ((SinTheta <= SinPiPer8 ) && (SinTheta > -SinPiPer8)) NewState = STATE_L_MOVE; else if ((SinTheta <= -SinPiPer8) && (SinTheta > -SinPiPer8Times3)) NewState = STATE_DL_MOVE; else NewState = STATE_D_MOVE; } } if ( NekoState != NewState ) [self SetNekoState: NewState]; return self; } - (BOOL) IsNekoDontMove { if ( NX_X(&NekoPos) == NekoLastXY.x && NX_Y(&NekoPos) == NekoLastXY.y ) return( YES ); return( NO ); } - (BOOL) IsNekoMoveStart { if ( ( PrevMouseX >= MouseX - IDLE_SPACE && PrevMouseX <= MouseX + IDLE_SPACE ) && ( PrevMouseY >= MouseY - IDLE_SPACE && PrevMouseY <= MouseY + IDLE_SPACE ) ) return( NO ); return( YES ); } - CalcDxDy { double LargeX, LargeY; double DoubleLength, Length; if (randCount1 == -100) // a signal to let values be... randCount1 = 200; else { PrevMouseX = MouseX; PrevMouseY = MouseY; } if (--randCount1 < 0) { randCount1 = (random() % (300)); MouseX = randBetween(-90,bounds.size.width+90); MouseY = randBetween(-90,bounds.size.height+90); } LargeX = (double)( MouseX - NX_X(&NekoPos) - BITMAP_WIDTH/2 ); LargeY = (double)( MouseY - NX_Y(&NekoPos)); DoubleLength = LargeX * LargeX + LargeY * LargeY; if ( DoubleLength != (double)0 ) { Length = sqrt( DoubleLength ); if ( Length <= NekoSpeed ) { NekoMoveDx = (int)LargeX; NekoMoveDy = (int)LargeY; } else { NekoMoveDx = (int)( ( NekoSpeed * LargeX ) / Length ); NekoMoveDy = (int)( ( NekoSpeed * LargeY ) / Length ); } } else NekoMoveDx = NekoMoveDy = 0; return self; } - oneStep { usleep(1000000 / 8); // run at about 8 frames/sec [self CalcDxDy]; if ( NekoState != STATE_SLEEP ) [self DrawNeko: NekoTickCount % 2 == 0 ? Even[NekoState] : Odd[NekoState]]; else [self DrawNeko: NekoTickCount % 8 <= 3 ? Even[NekoState] :Odd[NekoState]]; [self TickCount]; switch ( NekoState ) { case STATE_STOP: if ( [self IsNekoMoveStart]) { [self SetNekoState: STATE_AWAKE ]; break; } if ( NekoStateCount < TIME_STOP ) break; if ( NekoMoveDx < 0 && NX_X(&NekoPos) <= 0 ) [self SetNekoState: STATE_L_TOGI ]; else if ( NekoMoveDx > 0 && NX_X(&NekoPos) >= NX_WIDTH(&bounds) - BITMAP_WIDTH ) [self SetNekoState: STATE_R_TOGI ]; else if ( NekoMoveDy < 0 && NX_Y(&NekoPos) <= 0 ) [self SetNekoState: STATE_U_TOGI ]; else if ( NekoMoveDy > 0 && NX_Y(&NekoPos) >= NX_HEIGHT(&bounds) - BITMAP_HEIGHT ) [self SetNekoState: STATE_D_TOGI ]; else [self SetNekoState: STATE_JARE ]; break; case STATE_JARE: if ( [self IsNekoMoveStart] ) { [self SetNekoState: STATE_AWAKE ]; break; } if ( NekoStateCount < TIME_JARE ) break; [self SetNekoState: STATE_KAKI ]; break; case STATE_KAKI: if ( [self IsNekoMoveStart]) { [self SetNekoState: STATE_AWAKE ]; break; } if ( NekoStateCount < TIME_KAKI ) break; [self SetNekoState: STATE_AKUBI ]; break; case STATE_AKUBI: if ( [self IsNekoMoveStart] ) { [self SetNekoState: STATE_AWAKE ]; break; } if ( NekoStateCount < TIME_AKUBI ) break; [self SetNekoState: STATE_SLEEP ]; break; case STATE_SLEEP: if ( [self IsNekoMoveStart] ) { [self SetNekoState: STATE_AWAKE ]; break; } break; case STATE_AWAKE: if ( NekoStateCount < TIME_AWAKE ) break; [self NekoDirection]; break; case STATE_U_MOVE: case STATE_D_MOVE: case STATE_L_MOVE: case STATE_R_MOVE: case STATE_UL_MOVE: case STATE_UR_MOVE: case STATE_DL_MOVE: case STATE_DR_MOVE: NekoPos.origin.x += NekoMoveDx; NekoPos.origin.y += NekoMoveDy; [self NekoDirection]; [self NekoAdjust]; if ( [self IsNekoDontMove]) [self SetNekoState: STATE_STOP ]; break; case STATE_U_TOGI: case STATE_D_TOGI: case STATE_L_TOGI: case STATE_R_TOGI: if ( [self IsNekoMoveStart] ) { [self SetNekoState: STATE_AWAKE ]; break; } if ( NekoStateCount < TIME_TOGI ) break; [self SetNekoState: STATE_KAKI ]; break; default: /* Internal Error */ [self SetNekoState: STATE_STOP ]; break; } return self; } - NekoAdjust { if ( NX_X(&NekoPos) < 0 ) NekoPos.origin.x = 0; else if ( NX_X(&NekoPos) > NX_WIDTH(&bounds) - BITMAP_WIDTH ) NekoPos.origin.x = NX_WIDTH(&bounds) - BITMAP_WIDTH; if ( NX_Y(&NekoPos) < 0 ) NekoPos.origin.y = 0; else if ( NX_Y(&NekoPos) > NX_HEIGHT(&bounds) - BITMAP_HEIGHT ) NekoPos.origin.y = NX_HEIGHT(&bounds) - BITMAP_HEIGHT; return self; } - setBitmaps:anObject { bitmaps = anObject; return self; } - bitmaps { return bitmaps; } - initFrame:(const NXRect *)frameRect { SinPiPer8Times3=sin(PI_PER8*(double)3); SinPiPer8=sin(PI_PER8); [super initFrame:frameRect]; [self setClipping:NO]; [self allocateGState]; NXSetRect(&NekoPos, (NX_WIDTH(frameRect)-(NXCoord)(BITMAP_WIDTH/2))/2.0, (NX_HEIGHT(frameRect)-(NXCoord)(BITMAP_HEIGHT/2))/2.0, (NXCoord)BITMAP_WIDTH, (NXCoord)BITMAP_HEIGHT); NekoLastXY=NekoPos.origin; bitmaps=[self findImageNamed:"browncat"]; NXSetRect(&NekoLastIcon, Even[STATE_STOP], 0.0, (NXCoord)BITMAP_WIDTH, (NXCoord)BITMAP_HEIGHT); NekoSpeed=14; [self SetNekoState: STATE_STOP]; randCount1 = 100; return self; } - drawSelf:(const NXRect *)rects :(int)rectCount { if (!rects || !rectCount) return self; PSsetgray(0); NXRectFill(rects); [bitmaps composite:NX_SOVER fromRect:&NekoLastIcon toPoint:&NekoPos.origin]; return self; } - sizeTo:(NXCoord)width :(NXCoord)height { [super sizeTo:width:height]; [self NekoAdjust]; return self; } - (const char *) windowTitle { return "Neko"; } - inspector:sender { char buf[MAXPATHLEN]; if (!inspectorPanel) { sprintf(buf,"%s/Neko.nib",[sender moduleDirectory:"Neko"]); [NXApp loadNibFile:buf owner:self withNames:NO]; } return inspectorPanel; } - (BOOL) useBufferedWindow { return YES; } - findImageNamed:(const char *)name { char buf[1024]; id ret = [NXImage findImageNamed:name]; if (ret) return ret; sprintf(buf,"%s/%s.tiff",[(BSThinker()) moduleDirectory:"Neko"],name); ret = [[NXImage alloc] initFromFile:buf]; [ret setName:name]; return ret; } - inspectorWillBeRemoved { [infoWindow orderOut:self]; return self; } - mouseDown:(NXEvent *)event { NXPoint loc = event->location; [self convertPoint:&loc fromView:nil]; randCount1 = -100; PrevMouseX = MouseX; PrevMouseY = MouseY; MouseX = loc.x; MouseY = loc.y; return self; } @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.