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.