00001 #include "Horde3D.h"
00002 #include "Horde3DUtils.h"
00003 #include "utMath.h"
00004 #include <btBulletDynamicsCommon.h>
00005 #include <iostream>
00006 #include <time.h>
00007 #include <stdlib.h>
00008
00009 #include "CharacterCollisionCallback.h"
00010 #include "Enemy.h"
00011 #include "Player.h"
00012 #include "Physics.h"
00013 #include "Airplane.h"
00014 #include "Game.h"
00015 #include "IShootable.h"
00016
00027 Enemy::Enemy(Game* game, Physics* physics, H3DNode parent, H3DRes fontRes, const int id)
00028 : IShootable(game, parent, physics, id, "Enemy") {
00029
00030 _level = 1;
00031 _health = ::Values::MAX_HEALTH;
00032 _fontRes = fontRes;
00033 _isReborn = false;
00034 srand(time(NULL));
00035
00036 _animationTime = (1 / (rand() + 0.0001f));
00037 _hasJumped = true;
00038 LEVEL_TEXTURE_COUNT = 4;
00039
00040
00041 _levelBelowCapsule = 0.20f;
00042
00043 _bodyRadius = 0.45f;
00044 float bodyHeight = 1.86f;
00045 _capsuleHeight = bodyHeight - _levelBelowCapsule - (_bodyRadius * 2);
00046 _capsule = new btCapsuleShape(_bodyRadius, _capsuleHeight);
00047 _startPosition = Vec3(20 + (2 * _bodyRadius * _id), 30, 20);
00048
00049
00050 _groundMotionState = new btDefaultMotionState(btTransform(
00051 btQuaternion(0,0,0,1),
00052 btVector3(_startPosition.x, _startPosition.y, _startPosition.z))
00053 );
00054
00055
00056 _body = new btRigidBody(90, _groundMotionState, _capsule);
00057
00058
00059 _body->setActivationState(DISABLE_DEACTIVATION);
00060 physics->addShootable(this);
00061
00062
00063
00064 _modelRes = h3dAddResource(H3DResTypes::SceneGraph, "models/man/man.scene.xml", 0);
00065 _texture2 = h3dAddResource(H3DResTypes::Texture, "models/man/civil02.jpg", 0);
00066 _texture3 = h3dAddResource(H3DResTypes::Texture, "models/man/civil03.jpg", 0);
00067 _texture4 = h3dAddResource(H3DResTypes::Texture, "models/man/civil04.jpg", 0);
00068 H3DRes manWalkRes = h3dAddResource(H3DResTypes::Animation, "animations/man.anim", 0);
00069 bool loaded = h3dutLoadResourcesFromDisk(::Values::CONTENT_DIR);
00070 if(! loaded) std::cout << "could not load one ore more enemy ressources" << std::endl;
00071
00072
00073 _model = h3dAddNodes(parent, _modelRes);
00074
00075 h3dSetupModelAnimStage(_model, 0, manWalkRes, 0, "", true);
00076
00077
00078 h3dSetNodeTransform(_model, _startPosition.x, _startPosition.y, _startPosition.z,
00079 0.0f, 0.0f, 0.0f,
00080 1, 1, 1);
00081 }
00082
00083 Enemy::~Enemy() {
00084
00085 }
00086
00095 void Enemy::update(H3DNode cam, Player* player, const float timeStep) {
00096
00097 if(! _hasJumped) {
00098
00099 _body->setLinearVelocity(btVector3(0,0,0));
00100
00101 if(! _game->getAirplane()->isReadyForJump()) {
00102 return;
00103 }
00104 _hasJumped = true;
00105 return;
00106 }
00107
00108 h3dSetNodeActivation(_model, true);
00109
00110
00111
00112 btTransform transform = _body->getCenterOfMassTransform();
00113 transform.setRotation(btQuaternion(0, 0, 0, 1));
00114 _body->setCenterOfMassTransform(transform);
00115
00116
00117 _body->setAngularVelocity(btVector3(0, 0, 0));
00118
00119
00120 Vec3 currentPosition = getPosition();
00121 Vec3 rollbackPosition;
00122 Vec3 collisionPoint;
00123 bool onground = castRayAndCorrectPosition(currentPosition, collisionPoint);
00124
00125
00126 Vec3 playerPosition = player->getPosition();
00127 float distanceToPlayer = playerPosition.getEuclideanDistance(currentPosition);
00128
00129 float vx = 0;
00130 float vy = 0;
00131 float vz = 1;
00132
00133
00134 if(distanceToPlayer >= 3 && distanceToPlayer < 4) vz = 0;
00135 else if(distanceToPlayer < 3) vz = -1;
00136
00137 Vec3 speed(vx, vy, vz);
00138
00139
00140 if (speed.getLengthSquared() >= 2) {
00141 speed /= 1.4142f;
00142 }
00143 speed *= (::Values::WALKING_SPEED_KM_H / 1.2f / 3.6f * timeStep);
00144 float angleToPlayer = currentPosition.getAngle(playerPosition);
00145 speed.rotateXZ(angleToPlayer);
00146
00147
00148
00149
00150 if(onground) {
00151
00152 _body->setLinearVelocity(btVector3(0,0,0));
00153
00154 rollbackPosition = currentPosition;
00155 setPosition(currentPosition);
00156 currentPosition += speed;
00157 setPosition(currentPosition);
00158
00159
00160
00161 setPosition(currentPosition);
00162
00163
00164 btConvexShape *shape = (btConvexShape*)_body->getCollisionShape();
00165 btTransform from = _body->getCenterOfMassTransform();
00166 btTransform to = from;
00167 to.setOrigin(to.getOrigin() + btVector3(speed.x, 0, speed.z));
00168
00169 CharacterCollisionCallback cb(_body, from.getOrigin(), to.getOrigin());
00170 _physics->getWorld()->convexSweepTest(shape, from, to, cb);
00171 if (! cb.hasHit()) {
00172 setPosition(currentPosition);
00173
00174
00175
00176
00177 castRayAndCorrectPosition(currentPosition, collisionPoint);
00178 setPosition(currentPosition);
00179 }
00180 else {
00181
00182 currentPosition = rollbackPosition;
00183 }
00184 }
00185
00186 btTransform trans;
00187 _body->getMotionState()->getWorldTransform(trans);
00188
00189
00190 _animationTime = _animationTime + (60 * timeStep);
00191
00192 if(distanceToPlayer >= 3 && distanceToPlayer < 5) {
00193
00194 }
00195 else {
00196
00197 h3dSetModelAnimParams(_model, 0, _animationTime, 1.0);
00198 }
00199
00200
00201 float enemyWorldOffset = 0.57f;
00202 h3dSetNodeTransform(_model,
00203 currentPosition.x, currentPosition.y - enemyWorldOffset, currentPosition.z,
00204 0, angleToPlayer, 0,
00205 1, 1, 1);
00206
00207
00208 displayEnemyInformation(cam);
00209
00210
00211
00212
00213
00214 }
00215
00222 bool Enemy::castRayAndCorrectPosition(Vec3& calculatedCurrentPosition, Vec3& collisionPoint) {
00223 float capsuleBottom = (-_capsuleHeight / 2) - _bodyRadius;
00224
00225
00226 Vec3 from = calculatedCurrentPosition;
00227 Vec3 to = calculatedCurrentPosition;
00228 from.y += capsuleBottom + 0.3f;
00229 to.y += capsuleBottom - 0.7f;
00230
00231 bool onground = _physics->castRay(from, to, collisionPoint, _body);
00232
00233
00234 if (onground) {
00235 calculatedCurrentPosition = Vec3(
00236 calculatedCurrentPosition.x,
00237 (_capsuleHeight / 2) + _levelBelowCapsule + collisionPoint.y,
00238 calculatedCurrentPosition.z);
00239 setPosition(calculatedCurrentPosition);
00240 }
00241 return onground;
00242 }
00243
00248 void Enemy::setPosition(const Vec3& newPosition) {
00249 btTransform transform;
00250 transform = _body->getCenterOfMassTransform();
00251 transform.setOrigin(btVector3(newPosition.x, newPosition.y, newPosition.z));
00252 _body->setCenterOfMassTransform(transform);
00253 }
00254
00259 Vec3 Enemy::getPosition() const {
00260 btTransform transform = _body->getCenterOfMassTransform();
00261 btVector3 pos = transform.getOrigin();
00262 return Vec3(pos.x(), pos.y(), pos.z());
00263 }
00264
00265 void Enemy::hit() {
00266 _health -= ((rand() % 20) + 5);
00267 if(_health <= 0) _game->recycleEnemy((Enemy*)this);
00268 }
00269
00275 bool Enemy::reset(const bool doRebirth){
00276
00277 h3dSetNodeActivation(_model, false);
00278 std::cout << "reset" << std::endl;
00279 if(! doRebirth) {
00280
00281 h3dRemoveNode(_model);
00282
00283 setPosition(Vec3(-100,-100,-100));
00284
00285 _body->setActivationState(WANTS_DEACTIVATION);
00286 return false;
00287 }
00288 _level++;
00289 _health = ::Values::MAX_HEALTH + (_level * 5);
00290 _isReborn = true;
00291
00292 setPosition(_startPosition);
00293 _hasJumped = false;
00294
00295
00296 changeTexture();
00297
00298 return true;
00299 }
00300
00305 void Enemy::changeTexture() {
00306
00307 if(_level > LEVEL_TEXTURE_COUNT) return;
00308
00309 H3DRes theTexture;
00310 switch(_level) {
00311 case 2:
00312 theTexture = _texture2;
00313 break;
00314 case 3:
00315 theTexture = _texture3;
00316 break;
00317 case 4:
00318 theTexture = _texture4;
00319 break;
00320 default:
00321 return;
00322 }
00323
00324 for(unsigned int i = 0; i < 4; i++) {
00325 H3DNode mesh = h3dGetNodeChild(_model, i);
00326 std::cout << "found mesh " << mesh << std::endl;
00327
00328 int meshMaterial = h3dGetNodeParamI(mesh, H3DMesh::MatResI);
00329 if(meshMaterial < 0) continue;
00330
00331
00332
00333 H3DRes clonedMaterialResource = h3dCloneResource(meshMaterial, "");
00334
00335
00336
00337 h3dSetNodeParamI(mesh, H3DMesh::MatResI, clonedMaterialResource);
00338
00339 int meshMaterialNew = h3dGetNodeParamI(mesh, H3DMesh::MatResI);
00340
00341
00342 int idx = h3dFindResElem(meshMaterialNew, H3DMatRes::SamplerElem, H3DMatRes::SampNameStr, "albedoMap");
00343
00344
00345 H3DRes texRes = h3dGetResParamI(meshMaterialNew, H3DMatRes::SamplerElem, idx, H3DMatRes::SampTexResI);
00346
00347
00348 h3dSetResParamI(meshMaterialNew, H3DMatRes::SamplerElem, idx, H3DMatRes::SampTexResI, theTexture);
00349 }
00350 }
00351
00356 void Enemy::displayEnemyInformation(H3DNode cam) {
00357
00358 if(! hasJumped()) return;
00359
00360
00361 const float *camTrans;
00362 h3dGetNodeTransMats(cam, 0x0, &camTrans);
00363 Matrix4f viewMat(Matrix4f(camTrans).inverted());
00364
00365
00366 float camProj[16];
00367 h3dGetCameraProjMat(cam, camProj);
00368
00369 Matrix4f projMat(camProj);
00370
00371 std::ostringstream enemyName;
00372 enemyName << _name << _id << ": " << _health;
00373
00374
00375 const float *nodeTrans;
00376 h3dGetNodeTransMats(_model, 0, &nodeTrans);
00377 Vec4f pos(nodeTrans[12], nodeTrans[13], nodeTrans[14], 1);
00378
00379
00380 pos = projMat * viewMat * pos;
00381 float x = (pos.x - 1) / pos.w;
00382 float y = (pos.y + 5) / pos.w;
00383
00384
00385 x = x * 0.5f + 0.5f;
00386 y = -y * 0.5f + 0.5f;
00387
00388 float maxFontSize = 0.03f;
00389 float minFontSize = 0.01f;
00390
00391
00392 float fontSize = 0.2f / pos.z;
00393
00394
00395 if( pos.w > 0 && fontSize >= minFontSize ) {
00396 if( fontSize >= maxFontSize ) fontSize = maxFontSize;
00397 h3dutShowText(enemyName.str().c_str(), x, y, fontSize, 1.0f, 1.0f, 1.0f, _fontRes, 0);
00398 }
00399 }
00400
00402
00407 btRigidBody* Enemy::getBody() const {
00408 return _body;
00409 }
00410
00415 H3DNode Enemy::getModel() const {
00416 return _model;
00417 }
00418
00423 bool Enemy::hasJumped() const {
00424 return _hasJumped;
00425 }