#include "enemyship.h" #include "spaceship.h" #include "input.h" #include "camera.h" #include #include "sound.h" #include "model.h" #include "playership.h" #include "missle.h" #include EnemyShip::EnemyShip() : Spaceship(ENEMY) { _state = FORWARD; _flashcount = 0; _flash = false; _explode = NULL; _fireTime = 0.0; } typedef struct materialStruct { GLfloat ambient[4]; GLfloat diffuse[4]; GLfloat specular[4]; GLfloat shininess; } materialStruct; extern materialStruct brassMaterials; extern materialStruct redPlasticMaterials; void EnemyShip::Render() { if (alive) { glPushMatrix(); // Math3d::M3d direction = GetDirection(); //cout << direction << endl; glDisable(GL_TEXTURE_2D); Math3d::M4x4 mat = GetRotationMat(); glTranslatef(position[0], position[1], position[2]); glMultMatrixd(mat); glRotatef(-90.0, 0.0,1.0,0.0); #if 1 if (_flash && _flashcount > 0.0) { glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, redPlasticMaterials.ambient); glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, redPlasticMaterials.diffuse); glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, redPlasticMaterials.specular); glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, redPlasticMaterials.shininess); } else { glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, brassMaterials.ambient); glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, brassMaterials.diffuse); glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, brassMaterials.specular); glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, brassMaterials.shininess); } #endif _flash = !_flash; glutSolidTeapot(10.0); // theModels.Render(Model::ENEMY_MODEL); glEnable(GL_TEXTURE_2D); glPopMatrix(); } if (_explode != NULL) _explode->Render(); } void EnemyShip::UpdateState(float timeElapsed) { #if 1 if (alive) { MakeDecision(); if (_decision.yawLeft) { yawinc -= timeElapsed*20.0; } if (_decision.yawRight) { yawinc += timeElapsed*20.0; } if (_decision.rollCCW) { rollinc -= timeElapsed*20.0; } if (_decision.rollCW) { rollinc += timeElapsed*20.0; } if (_decision.pitchUp) { pitchinc += timeElapsed*20.0; } if (_decision.pitchDown) { pitchinc -= timeElapsed*20.0; } if (_decision.accel) { velinc += timeElapsed / 40.0; } if (_decision.fire) { if (_fireTime > 1.0) { theMissles.AddMissle(GetPosition()+(GetDirection()*11.0), GetDirection(), 300.0, 2.0, missleDamage); _fireTime = 0.0; } } _fireTime += timeElapsed; Spaceship::UpdateState(timeElapsed); } #else velocity = 0.75; #endif #if 0 float maxdistance = 200.0; float distance; switch (_state) { case FORWARD: distance = position[2]; break; case BACKWARD: distance = -position[2]; break; case LEFT: distance = -position[0]; break; case RIGHT: distance = position[0]; break; } if (distance >= maxdistance) { matYaw.loadRotateY(PI/2); yawQuat = Math3d::MQuat(matYaw); orientation *= yawQuat; _state = (_state + 1) % NUM_STATES; } // Math3d::M3d direction = GetDirection(); // position += direction * velocity * timeElapsed * 50.0; #endif // update state of flash if ship has been hit if (_flashcount > 0.0) _flashcount -= timeElapsed; else _flash = false; // update state for explosion if its still there if (_explode != NULL) { _explode->UpdateState(timeElapsed); if (!_explode->IsAlive()) { delete _explode; _explode = NULL; } } } void EnemyShip::Hit(float damage) { Spaceship::Hit(damage); // slow the ship down for a second // velocity -= 0.5; if (health > 0.0) { _flashcount = 0.5; theSound.PlaySound(Sound::HIT); } else { _explode = new Explosion(position, 50); theSound.PlaySound(Sound::EXPLODE); } } void EnemyShip::MakeDecision() { _decision.yawLeft = false; _decision.yawRight = false; _decision.pitchUp = false; _decision.pitchDown = false; _decision.rollCW = false; _decision.rollCCW = false; _decision.accel = false; _decision.fire = false; // Math3d::M4x4 targetMat = thePlayer.GetRotationMat(); // predict where player will be when laser hits it Math3d::M3d goalDestination = thePlayer.GetPosition(); // Math3d::M3d shipVec = GetDirection() * velocity * 75.0; Math3d::M3d shipVec = (GetDirection() * 2.0 +(GetDirection() * velocity)) * 75.0; Math3d::M3d targetVec = thePlayer.GetDirection() * thePlayer.velocity * 75.0; Math3d::M3d distance; float time; for (int i=0; i<10; i++) { distance = goalDestination - position; if (shipVec.length() < 0.01) break; time = distance.length() / shipVec.length(); goalDestination = thePlayer.GetPosition() + targetVec * time; } Math3d::M3d targetHeading = goalDestination - position; targetHeading.normalize(); float dot = targetHeading * GetDirection(); // if they are going the same way, fire (may need to adjust this value) if (dot > 0.995) _decision.fire = true; // aim for spot behind player Math3d::M3d behindShip = thePlayer.GetPosition() - (thePlayer.GetDirection() * 64.0); distance = behindShip - position; float distToGoal = distance.length(); Math3d::M4x4 rotateMat; rotateMat.loadRotate(orientation); Math3d::M3d moveX = rotateMat * Math3d::M3d(1.0, 0.0, 0.0); Math3d::M3d moveY = rotateMat * Math3d::M3d(0.0, 1.0, 0.0); // quaternions for testing purposes float futureDist; // close to goal, find way to line up with target if (distToGoal < 100.0) { //cout << "Distance: " << distToGoal << endl; //cout << "Player: " << thePlayer.GetPosition() << ", Destination: " << goalDestination << endl; distance = goalDestination - position; distToGoal = distance.length(); Math3d::M3d dirVec = goalDestination - position; dirVec.normalize(); float dp = dirVec * GetDirection(); //cout << "DotP: " << dp << endl; #if 0 // decide whether to move left or right distance = goalDestination - (position + moveX); futureDist = distance.length(); if (futureDist < distToGoal) { // cout << "turn right" << endl; _decision.yawRight = true; } else if (futureDist > distToGoal) { //cout << "turn left" << endl; _decision.yawLeft = true; } // decide whether to move up or down distance = goalDestination - (position + moveY); futureDist = distance.length(); if (futureDist < distToGoal) _decision.pitchUp = true; else if (futureDist > distToGoal) _decision.pitchDown = true; #else Math3d::M4x4 yawMat; yawMat.loadRotateY(0.01); Math3d::MQuat yawQ = Math3d::MQuat(yawMat); yawQ = orientation * yawQ; Math3d::M3d newDir = GetDirection(yawQ); //cout << "Needed Dir: " << dirVec << ", Cur Dir: " << GetDirection() << ", Yaw Dir: " << newDir << endl; float dif = fabs((dirVec * newDir) - dp); //cout << "Dif: " << dif << endl; if (dif > 0.005) { if ((dirVec*newDir) > dp) _decision.yawRight = true; else { _decision.yawLeft = true; } } else { Math3d::M4x4 pitchMat; pitchMat.loadRotateX(0.01); Math3d::MQuat pitchQ = Math3d::MQuat(pitchMat); // pitchQ = orientation * pitchQ; pitchQ = orientation * pitchQ; newDir = GetDirection(pitchQ); if ((dirVec*newDir) < dp) _decision.pitchDown = true; else _decision.pitchUp = true; } #endif } // far away from goal, find out how to get there else { // determine if acceleration necessary distance = behindShip - (position + GetDirection()); futureDist = distance.length(); if (futureDist < distToGoal && futureDist > 100.0) _decision.accel = true; // roll CW or CCW? distance = behindShip - (position + moveX + moveY); futureDist = distance.length(); if (futureDist < distToGoal) _decision.rollCW = true; else if (futureDist > distToGoal) _decision.rollCCW = true; // turn right or left? distance = behindShip - (position + moveX); futureDist = distance.length(); if (futureDist < distToGoal) _decision.yawRight = true; else if (futureDist > distToGoal) _decision.yawLeft = true; // pitch up or down? distance = behindShip - (position + moveY); futureDist = distance.length(); if (futureDist < distToGoal) _decision.pitchUp = true; else if (futureDist > distToGoal) _decision.pitchDown = true; } // make sure the ship isnt too close to player goalDestination = thePlayer.GetPosition() - GetPosition(); distToGoal = goalDestination.length(); if (distToGoal < 60.0) { goalDestination.normalize(); dot = goalDestination * GetDirection(); if (dot > 0.5) { // roll CW or CCW? distance = goalDestination + moveX + moveY; futureDist = distance.length(); if (futureDist > distToGoal) { _decision.rollCW = true; _decision.rollCCW = false; } else if (futureDist > distToGoal) { _decision.rollCW = false; _decision.rollCCW = true; } // turn left or right? distance = goalDestination + moveX; futureDist = distance.length(); if (futureDist > distToGoal) { _decision.yawRight = true; _decision.yawLeft = false; } else if (futureDist < distToGoal) { _decision.yawRight = false; _decision.yawLeft = true; } // move up or down? distance = goalDestination + moveY; futureDist = distance.length(); if (futureDist > distToGoal) { _decision.pitchUp = true; _decision.pitchDown = false; } else if (futureDist < distToGoal) { _decision.pitchDown = false; _decision.pitchUp = true; } } } /* if (_decision.pitchUp) cout << "Up" << endl; if (_decision.pitchDown) cout << "Down" << endl; if (_decision.yawLeft) cout << "Left" << endl; if (_decision.yawRight) cout << "Right" << endl; cout << endl; */ }