From 6b7e229ee15985219272cfd20c5e212d8dba0b59 Mon Sep 17 00:00:00 2001 From: Charles Date: Thu, 18 Jan 2001 19:18:39 +0000 Subject: [PATCH] --- makefile.gaz | 1 + source/enemy/npc.cpp | 444 ++++++++++++++++++++++++++++++++++++--- source/enemy/npc.h | 44 +++- source/enemy/npcpath.cpp | 34 +-- source/enemy/npcpath.h | 10 +- 5 files changed, 477 insertions(+), 56 deletions(-) diff --git a/makefile.gaz b/makefile.gaz index f2b2043a5..3db3829fb 100644 --- a/makefile.gaz +++ b/makefile.gaz @@ -53,6 +53,7 @@ backend_src := gameover \ enemy_src := 2denemy \ npc \ + npcpath \ enemy fileio_src := fileio \ diff --git a/source/enemy/npc.cpp b/source/enemy/npc.cpp index 77d1ba0f4..612bf0cb6 100644 --- a/source/enemy/npc.cpp +++ b/source/enemy/npc.cpp @@ -33,14 +33,24 @@ #include "player\player.h" #endif +#ifndef __ENEMY_NPCPATH_H__ +#include "enemy\npcpath.h" +#endif + +#ifndef __UTILS_HEADER__ +#include "utils\utils.h" +#endif + CNpc::NPC_DATA CNpc::m_data[NPC_UNIT_TYPE_MAX] = { { NPC_INIT_DEFAULT, - NPC_SENSOR_NONE, - NPC_MOVEMENT_STATIC, - NPC_MOVEMENT_MODIFIER_NONE, + NPC_SENSOR_USER_CLOSE, + NPC_MOVEMENT_FIXED_PATH, + NPC_MOVEMENT_MODIFIER_JELLYFISH, + NPC_CLOSE_EVADE, + NPC_TIMER_NONE, false, }, @@ -49,6 +59,8 @@ CNpc::NPC_DATA CNpc::m_data[NPC_UNIT_TYPE_MAX] = NPC_SENSOR_NONE, NPC_MOVEMENT_STATIC, NPC_MOVEMENT_MODIFIER_NONE, + NPC_CLOSE_EVADE, + NPC_TIMER_NONE, true, }, }; @@ -56,13 +68,50 @@ CNpc::NPC_DATA CNpc::m_data[NPC_UNIT_TYPE_MAX] = void CNpc::init() { - m_type = NPC_SANDY_CHEEKS; + m_type = NPC_TEST_TYPE; + + m_heading = 0; + m_movementTimer = 0; + m_timerTimer = 0; + m_velocity = 0; + + Pos.vx = 100; + Pos.vy = 100; + + m_timerFunc = m_data[this->m_type].timerFunc; + m_sensorFunc = m_data[this->m_type].sensorFunc; switch ( m_data[this->m_type].initFunc ) { case NPC_INIT_DEFAULT: m_controlFunc = NPC_CONTROL_MOVEMENT; + m_npcPath.initPath(); + + DVECTOR newPos; + + newPos.vx = 100; + newPos.vy = 10; + + m_npcPath.addWaypoint( newPos ); + + newPos.vx = 500; + newPos.vy = 10; + + m_npcPath.addWaypoint( newPos ); + + newPos.vx = 500; + newPos.vy = 100; + + m_npcPath.addWaypoint( newPos ); + + newPos.vx = 100; + newPos.vy = 100; + + m_npcPath.addWaypoint( newPos ); + + m_npcPath.setPathType( REPEATING_PATH ); + break; default: @@ -80,14 +129,16 @@ void CNpc::shutdown() void CNpc::think(int _frames) { - m_controlFunc = NPC_CONTROL_MOVEMENT; - switch ( this->m_controlFunc ) { case NPC_CONTROL_MOVEMENT: if ( !processSensor() ) { - processMovement(); + processMovement(_frames); + } + else + { + processClose(_frames); } break; @@ -98,7 +149,7 @@ void CNpc::think(int _frames) break; case NPC_CONTROL_CLOSE: - processClose(); + processClose(_frames); break; @@ -108,88 +159,423 @@ void CNpc::think(int _frames) break; } - processTimer(); + processTimer(_frames); } bool CNpc::processSensor() { - switch( m_data[this->m_type].sensorFunc ) + switch( m_sensorFunc ) { case NPC_SENSOR_NONE: return( false ); case NPC_SENSOR_USER_CLOSE: - /*if ( user is close ) + { + CPlayer *player = GameScene.getPlayer(); + + DVECTOR playerPos = player->getPos(); + + s32 xDistSqr, yDistSqr; + + xDistSqr = playerPos.vx - this->Pos.vx; + xDistSqr *= xDistSqr; + + yDistSqr = playerPos.vy - this->Pos.vy; + yDistSqr *= yDistSqr; + + if ( xDistSqr + yDistSqr < 10000 ) { - this->controlFunc = NPC_CONTROL_CLOSE; - processClose(); + this->m_controlFunc = NPC_CONTROL_CLOSE; + + this->m_evadeClockwise = ( getRnd() % 2 ) - 1; return( true ); } - else*/ + else { return( false ); } - } + } - return( false ); + default: + return( false ); + } } -void CNpc::processMovement() +void CNpc::processMovement(int _frames) { + if ( _frames > 2 ) + { + _frames = 2; + } + + s32 moveX = 0, moveY = 0; + + s16 moveDist = 0; + + s32 moveVel = 0; + switch( m_data[this->m_type].movementFunc ) { case NPC_MOVEMENT_STATIC: - switch( m_data[this->m_type].movementModifierFunc ) + { + break; + } + + case NPC_MOVEMENT_FIXED_PATH: + { + bool pathComplete; + + s16 headingToTarget = m_npcPath.think( Pos, &pathComplete ); + + if ( !pathComplete ) { - case NPC_MOVEMENT_MODIFIER_NONE: - break; + s16 decDir, incDir; - case NPC_MOVEMENT_MODIFIER_BOB: - //staticBob(); + decDir = m_heading - headingToTarget; - break; + if ( decDir < 0 ) + { + decDir += ONE; + } + + incDir = headingToTarget - m_heading; + + if ( incDir < 0 ) + { + incDir += ONE; + } + + if ( decDir < incDir ) + { + moveDist = -decDir; + } + else + { + moveDist = incDir; + } + + if ( moveDist < -128 ) + { + moveDist = -128; + } + else if ( moveDist > 128 ) + { + moveDist = 128; + } + + m_heading += moveDist; + + m_heading = m_heading % ONE; + + moveX = ( _frames * 3 * rcos( m_heading ) ) >> 12; + moveY = ( _frames * 3 * rsin( m_heading ) ) >> 12; + moveVel = ( _frames * 3 ) << 8; } break; - - case NPC_MOVEMENT_FIXED_PATH: - - break; + } case NPC_MOVEMENT_USER_SEEK: + { CPlayer *player; player = GameScene.getPlayer(); break; + } case NPC_MOVEMENT_VERTICAL: + { Pos.vy--; break; + } default: break; } + + processMovementModifier(_frames, moveX, moveY, moveVel, moveDist); +} + +void CNpc::processMovementModifier(int _frames, s32 distX, s32 distY, s32 dist, s32 headingChange) +{ + switch( m_data[m_type].movementModifierFunc ) + { + case NPC_MOVEMENT_MODIFIER_NONE: + { + Pos.vx += distX; + Pos.vy += distY; + + break; + } + + case NPC_MOVEMENT_MODIFIER_BOB: + { + break; + } + + case NPC_MOVEMENT_MODIFIER_JELLYFISH: + { +#define NPC_JELLYFISH_RESISTANCE 64 + + s32 newX, newY; + s32 preShiftX, preShiftY; + + u16 jellyfishData[5] = { 96, 192, 256, 192, 128, }; + + u32 dataPoint; + + m_movementTimer += _frames; + + if ( m_movementTimer > GameState::getOneSecondInFrames() ) + { + m_movementTimer = 0; + } + + dataPoint = 4 * m_movementTimer; + + if ( dataPoint != 0 ) + { + dataPoint /= GameState::getOneSecondInFrames(); + } + + s32 resistance; + s32 absVelocity = abs( m_velocity ); + s32 reqVelocity = dist; + + resistance = _frames * NPC_JELLYFISH_RESISTANCE; + + if ( absVelocity < resistance ) + { + resistance = absVelocity; + } + + if ( absVelocity != 0 ) + { + resistance = -( resistance * m_velocity ) / absVelocity; + } + else + { + resistance = 0; + } + + m_velocity += resistance; + + reqVelocity = dist * jellyfishData[dataPoint]; + reqVelocity >>= 8; + reqVelocity *= 128 + ( 128 - headingChange ); + reqVelocity >>= 8; + + s32 absReqVelocity = abs( reqVelocity ); + + if ( absReqVelocity > absVelocity ) + { + m_velocity += reqVelocity >> 1; + } + + preShiftX = ( m_velocity >> 8 ) * rcos( m_heading ); + preShiftY = ( m_velocity >> 8 ) * rsin( m_heading ); + + newX = preShiftX >> 12; + if ( !newX && preShiftX ) + { + newX = preShiftX / abs( preShiftX ); + } + + newY = preShiftY >> 12; + if ( !newY && preShiftY ) + { + newY = preShiftY / abs( preShiftY ); + } + + Pos.vx += newX; + Pos.vy += newY; + + break; + } + } } void CNpc::processShot() { } -void CNpc::processClose() +void CNpc::processClose(int _frames) { + switch( m_data[this->m_type].closeFunc ) + { + case NPC_CLOSE_EVADE: + { + s32 moveX = 0, moveY = 0; + + s16 moveDist = 0; + + s32 moveVel = 0; + + CPlayer *player = GameScene.getPlayer(); + + DVECTOR playerPos = player->getPos(); + + s32 xDist, yDist; + s32 xDistSqr, yDistSqr; + + xDist = playerPos.vx - this->Pos.vx; + xDistSqr = xDist * xDist; + + yDist = playerPos.vy - this->Pos.vy; + yDistSqr = yDist * yDist; + + if ( xDistSqr + yDistSqr > 22500 ) + { + this->m_controlFunc = NPC_CONTROL_MOVEMENT; + } + else + { + bool pathComplete; + + s16 headingToTarget = m_npcPath.think( Pos, &pathComplete ); + + if ( pathComplete ) + { + this->m_controlFunc = NPC_CONTROL_MOVEMENT; + } + else + { + s16 headingToPlayer = ratan2( yDist, xDist ); + + if ( m_evadeClockwise ) + { + headingToPlayer += 1024; + } + else + { + headingToPlayer -= 1024; + } + + headingToPlayer %= ONE; + + s16 decDir, incDir; + + decDir = headingToPlayer - headingToTarget; + + if ( decDir < 0 ) + { + decDir += ONE; + } + + incDir = headingToTarget - headingToPlayer; + + if ( incDir < 0 ) + { + incDir += ONE; + } + + if ( decDir < incDir ) + { + moveDist = decDir; + } + else + { + moveDist = incDir; + } + + if ( moveDist < 128 ) + { + // evasion angle is close to angle required to go to waypoint, hence resume waypoint movement + + this->m_controlFunc = NPC_CONTROL_MOVEMENT; + this->m_timerFunc = NPC_TIMER_EVADE_DONE; + this->m_timerTimer = GameState::getOneSecondInFrames(); + this->m_sensorFunc = NPC_SENSOR_NONE; + } + else + { + decDir = m_heading - headingToPlayer; + + if ( decDir < 0 ) + { + decDir += ONE; + } + + incDir = headingToPlayer - m_heading; + + if ( incDir < 0 ) + { + incDir += ONE; + } + + if ( decDir < incDir ) + { + moveDist = -decDir; + } + else + { + moveDist = incDir; + } + + if ( moveDist < -128 ) + { + moveDist = -128; + } + else if ( moveDist > 128 ) + { + moveDist = 128; + } + + m_heading += moveDist; + + m_heading = m_heading % ONE; + + moveX = ( _frames * 3 * rcos( m_heading ) ) >> 12; + moveY = ( _frames * 3 * rsin( m_heading ) ) >> 12; + moveVel = ( _frames * 3 ) << 8; + + processMovementModifier(_frames, moveX, moveY, moveVel, moveDist); + } + } + } + } + + break; + + default: + break; + } } void CNpc::processCollision() { } -void CNpc::processTimer() +void CNpc::processTimer(int _frames) { + switch( m_timerFunc ) + { + case NPC_TIMER_NONE: + { + break; + } + + case NPC_TIMER_EVADE_DONE: + { + this->m_timerTimer -= _frames; + + if ( m_timerTimer <= 0 ) + { + this->m_timerFunc = NPC_TIMER_NONE; + this->m_sensorFunc = NPC_SENSOR_USER_CLOSE; + } + + break; + } + + default: + break; + } } void CNpc::render() diff --git a/source/enemy/npc.h b/source/enemy/npc.h index e57080085..b6a4181e7 100644 --- a/source/enemy/npc.h +++ b/source/enemy/npc.h @@ -11,13 +11,16 @@ ===========================================================================*/ -#ifndef __NPC_H__ -#define __NPC_H__ +#ifndef __ENEMY_NPC_H__ +#define __ENEMY_NPC_H__ //#include #include "Game/Thing.h" #include "Gfx/Skel.h" +#ifndef __ENEMY_NPCPATH_H__ +#include "enemy\npcpath.h" +#endif /*****************************************************************************/ @@ -62,6 +65,11 @@ protected: NPC_SENSOR_USER_CLOSE = 1, }; + enum NPC_CLOSE_FUNC + { + NPC_CLOSE_EVADE = 0, + }; + enum NPC_MOVEMENT_FUNC { NPC_MOVEMENT_STATIC = 0, @@ -74,6 +82,13 @@ protected: { NPC_MOVEMENT_MODIFIER_NONE = 0, NPC_MOVEMENT_MODIFIER_BOB = 1, + NPC_MOVEMENT_MODIFIER_JELLYFISH, + }; + + enum NPC_TIMER_FUNC + { + NPC_TIMER_NONE = 0, + NPC_TIMER_EVADE_DONE = 1, }; @@ -83,21 +98,34 @@ protected: NPC_SENSOR_FUNC sensorFunc; NPC_MOVEMENT_FUNC movementFunc; NPC_MOVEMENT_MODIFIER_FUNC movementModifierFunc; + NPC_CLOSE_FUNC closeFunc; + NPC_TIMER_FUNC timerFunc; bool canTalk; } NPC_DATA; - NPC_UNIT_TYPE m_type; - NPC_CONTROL_FUNC m_controlFunc; - bool processSensor(); - void processMovement(); + void processMovement(int _frames); + void processMovementModifier(int _frames, s32 distX, s32 distY, s32 dist, s32 headingChange); void processShot(); - void processClose(); + void processClose(int _frames); void processCollision(); - void processTimer(); + void processTimer(int _frames); static NPC_DATA m_data[NPC_UNIT_TYPE_MAX]; + + // internal variables + + NPC_UNIT_TYPE m_type; + NPC_CONTROL_FUNC m_controlFunc; + NPC_TIMER_FUNC m_timerFunc; + NPC_SENSOR_FUNC m_sensorFunc; + CNpcPath m_npcPath; + s32 m_heading; + s32 m_movementTimer; + s32 m_velocity; + bool m_evadeClockwise; + s32 m_timerTimer; }; diff --git a/source/enemy/npcpath.cpp b/source/enemy/npcpath.cpp index 68d64890f..a889d5832 100644 --- a/source/enemy/npcpath.cpp +++ b/source/enemy/npcpath.cpp @@ -11,19 +11,19 @@ ===========================================================================*/ -#ifndef __ENEMY_NCPPATH_H__ -#include "enemy\ncppath.h" +#ifndef __ENEMY_NPCPATH_H__ +#include "enemy\npcpath.h" #endif -bool CNpcWaypoint::isPointNear( DVECTOR testPos ) +bool CNpcWaypoint::isPointNear( DVECTOR testPos, s32 *xDist, s32 *yDist ) { s32 xDistSqr, yDistSqr; - xDistSqr = testPos.vx - this->pos.vx; - xDistSqr *= xDistSqr; + *xDist = testPos.vx - this->pos.vx; + xDistSqr = (*xDist) * (*xDist); - yDistSqr = testPos.vy - this->pos.vy; - yDistSqr *= yDistSqr; + *yDist = testPos.vy - this->pos.vy; + yDistSqr = (*yDist) * (*yDist); if ( xDistSqr + yDistSqr < 100 ) { @@ -42,7 +42,7 @@ void CNpcPath::initPath() for ( loop = 0 ; loop < NPC_MAX_WAYPOINTS ; loop++ ) { waypoint[loop].pos.vx = 0; - waypoint[loop].pox.vy = 0; + waypoint[loop].pos.vy = 0; } pathType = SINGLE_USE_PATH; @@ -55,7 +55,7 @@ void CNpcPath::addWaypoint( DVECTOR newPos ) { if ( waypointCount < NPC_MAX_WAYPOINTS ) { - waypoint[waypointCount] = newPos; + waypoint[waypointCount].pos = newPos; waypointCount++; } } @@ -69,7 +69,7 @@ bool CNpcPath::incPath() { if ( !reversePath ) { - if ( currentWaypoint < waypointCount ) + if ( currentWaypoint < waypointCount - 1 ) { currentWaypoint++; } @@ -117,14 +117,18 @@ bool CNpcPath::incPath() return( false ); } -void CNpcPath::think( DVECTOR currentPos ) +s32 CNpcPath::think( DVECTOR currentPos, bool *pathComplete ) { - CNpcWaypoint *currentWaypoint; + s32 xDist, yDist; - currentWaypoint = &waypoint[currentWaypoint] + *pathComplete = false; - if ( currentWaypoint->isPointNear( currentPos ) ) + if ( waypoint[currentWaypoint].isPointNear( currentPos, &xDist, &yDist ) ) { - incPath(); + *pathComplete = incPath(); } + + s32 headingToTarget = ratan2( -yDist, -xDist ); + + return( headingToTarget ); } \ No newline at end of file diff --git a/source/enemy/npcpath.h b/source/enemy/npcpath.h index ce1390368..6264f362b 100644 --- a/source/enemy/npcpath.h +++ b/source/enemy/npcpath.h @@ -11,15 +11,17 @@ ===========================================================================*/ -#ifndef __ENEMY_NCPPATH_H__ -#define __ENEMY_NCPPATH_H__ +#ifndef __ENEMY_NPCPATH_H__ +#define __ENEMY_NPCPATH_H__ + +#include "system\global.h" class CNpcWaypoint { public: DVECTOR pos; - bool isPointNear( DVECTOR testPos ); + bool isPointNear( DVECTOR testPos, s32 *xDist, s32 *yDist ); }; enum NPC_PATH_TYPE @@ -48,7 +50,7 @@ public: void addWaypoint( DVECTOR newPos ); void setPathType( NPC_PATH_TYPE newPathType ); bool incPath(); - void think( DVECTOR currentPos ); + s32 think( DVECTOR currentPos, bool *pathComplete ); }; #endif \ No newline at end of file