void HUDBase::getRelativePositions(list<Vertex<float> > &above, list<Vertex<float> > &below) { // Reset the vectors above.clear(); below.clear(); set<PhysicalObject*>::iterator it; m_mutex.lock(); for(it = m_destroyables.begin(); it != m_destroyables.end(); it++) { // Calculate the mapping of the difference vector: PhysicalObject* obj = *it; Vertex<float> diff = obj->getPosition() - m_fighter->getPosition(); // Project onto current flight axis float x = diff * m_fighter->getXAxis(); float y = diff * m_fighter->getYAxis(); float z = diff * m_fighter->getZAxis(); // Create new relative position Vertex<float> rel(x,y,z); //And add to the relative positions if(z<0) { below.push_back(rel); } else { above.push_back(rel); } } m_mutex.unlock(); }
PhysicalObject* PhysicsSim::applyPhysics(SceneObject* object, Shape shape, float mass) { PhysicalObject* phyObject; switch(shape) { case shSphere: phyObject = new Sphere(object, mass); break; case shBox: phyObject = new Box(object, mass); break; case shCapsule: phyObject = new Capsule(object, mass); break; case shCylinder: phyObject = new Cylinder(object, mass); break; case shCone: phyObject = new Cone(object, mass); break; case shConvexHull: phyObject = new ConvexHull(object, mass); break; case shTriMesh: phyObject = new TriMesh(object, mass); break; } objects_list.push_back(phyObject); dynamicsWorld->addRigidBody(phyObject->getRigidBody()); updateObjects(); return phyObject; }
/** Update the world and the track. * \param dt Time step size. */ void ThreeStrikesBattle::update(float dt) { WorldWithRank::update(dt); WorldWithRank::updateTrack(dt); core::vector3df tire_offset; std::string tire; float scale = 0.5f; float radius = 0.5f; PhysicalObject::bodyTypes tire_model; // insert blown away tire(s) now if was requested while (m_insert_tire > 0) { if(m_insert_tire == 1) { tire_offset = core::vector3df(0.0f, 0.0f, 0.0f); tire = file_manager->getModelFile("tire.b3d"); scale = 0.5f; radius = 0.5f; tire_model = PhysicalObject::MP_CYLINDER_Y; } else { scale = 1.0f; tire_model = PhysicalObject::MP_CYLINDER_X; radius = m_tire_radius[m_insert_tire-2]; tire_offset = m_tire_offsets[m_insert_tire-2]; if (m_insert_tire == 2) tire = m_tire_dir+"/wheel-rear-left.b3d"; else if(m_insert_tire == 3) tire = m_tire_dir+"/wheel-front-left.b3d"; else if(m_insert_tire == 4) tire = m_tire_dir+"/wheel-front-right.b3d"; else if(m_insert_tire == 5) tire = m_tire_dir+"/wheel-rear-right.b3d"; } TrackObjectManager* tom = m_track->getTrackObjectManager(); PhysicalObject* obj = tom->insertObject(tire, tire_model, 15 /* mass */, radius /* radius */, core::vector3df(800.0f,0,m_tire_rotation / M_PI * 180 + 180) , m_tire_position + tire_offset, core::vector3df(scale,scale,scale) /* scale */); // FIXME: orient the force relative to kart orientation obj->getBody()->applyCentralForce(btVector3(60.0f, 0.0f, 0.0f)); m_insert_tire--; if(m_insert_tire == 1) m_insert_tire = 0; m_tires.push_back(obj); } } // update
void Laser::fire() { InternalMessage("Model","entering fire") ; // handle firing rate if (m_time_to_fire.Second() > 0) return ; Positioned* positioned = getObject()->getParent<Positioned>() ; Oriented* oriented = getObject()->getParent<Oriented>() ; PhysicalObject* object = getObject()->getParent<PhysicalObject>() ; PhysicalWorld* world = object ? object->getObject()->getAncestor<PhysicalWorld>() : NULL ; if (world && positioned && oriented) { InternalMessage("Model","firing") ; // create a laser beam object Kernel::Object* beam = world->getObject()->createObject() ; // should apply local rotation to have correct local position.. Orientation orientation_of_laser = oriented->getOrientation(world->getObject()) ; Position position_of_the_beam = positioned->getPosition(world->getObject()) + m_out_position*orientation_of_laser ; beam->addTrait(new Positioned(position_of_the_beam)) ; Orientation orientation_of_the_beam = orientation_of_laser*m_out_orientation ; beam->addTrait(new Oriented(orientation_of_the_beam)) ; // orientation gives speed vector // basic_speed(full Z oriented) * orientation Speed speed = Speed::MeterPerSecond(0,0,-getLaserSpeedMeterPerSecond())*orientation_of_the_beam ; // maybe we should add the object speed ?? (i.e. the speed of the ship) beam->addTrait(new Mobile(speed)) ; beam->addTrait(new Massive(Mass(m_laser_beam_energy,speed))) ; beam->addTrait(new LaserBeam(object->getObject(),m_beam_length,m_beam_radius)) ; beam->addTrait(new WithLifetime(getLaserBeamLifeDuration())) ; // shot Kernel::Object* shot = world->getObject()->createObject() ; shot->addTrait(new Positioned(position_of_the_beam)) ; shot->addTrait(new Shot()) ; // re-init timer m_time_to_fire = m_time_between_shots ; // done } // else : not much sense thus do nothing InternalMessage("Model","leaving fire") ; }
void PhysicalGroup::Render(float minX, float minY, float maxX, float maxY) { if(m_physicsHandler) m_physicsHandler->Render(minX, minY, maxX, maxY); else //- TODO: Determine if this is necessary - { for(vector<Group::Member *>::iterator it = m_members.begin(); it != m_members.end(); it++) { PhysicalObject *object = (PhysicalObject *)*it; object->Render(); } } }
void PhysicsSim::shootTestSphere() { removeObject(testSphere); testSphere = loadSceneObject("lemon.dae"); testSphere->setPosition(fpscam->getPosition()); testSphere->setScale(Vector3D(2,2,2)); PhysicalObject* phyObj = applyPhysics(testSphere, shSphere, 20); vector3df dir = fpscam->getTarget() - fpscam->getPosition(); dir = 250*dir.normalize(); phyObj->getRigidBody()->applyCentralImpulse(btVector3(dir.X, dir.Y, dir.Z)); }
const SUCCESS PhysicalObject::collided(PhysicalObject &object, const Radians angle) { Vector initVec(getVelocity()-object.getVelocity()); Mag_t<double> initVel(initVec.mag()); Radians initTheta(initVec.theta()); if(fabs(getX(initVel, initTheta-angle)) < REST_THRESHOLD) { setVelocity(getVelocity()+initVec/2.0); object.setVelocity(object.getVelocity()-initVec/2.0); antigravitate(object); object.antigravitate(*this); return SUCCEEDED; } // Frame of reference with the object at rest with this approaching it with an angle of 0 Point<double> p2(Vector(Mag_t<double>(2.0*getMass()*getX(initVel, initTheta-angle)/(getMass()+object.getMass())), initTheta-angle)); // Gets the velocity of 2 based on elastic collision equation Point<double> p1((initVel*getMass()-p2.x()*object.getMass())/getMass(), -p2.y()*object.getMass()/getMass()); // Gets the velocity of 1 based off of elastic collision rulez if(fabs(p1.x()) < REST_THRESHOLD && fabs(p2.x()) < REST_THRESHOLD) { p1.x(0.0); p2.x(0.0); } Vector v1(p1); Vector v2(p2); v1.theta(-v1.theta()+initTheta); v2.theta(angle); v1 += object.getVelocity(); v2 += object.getVelocity(); Point<double> dif(object.getPosition()-*position); while(getCollider()->collides(*object.getCollider())) acceleration.set(*position-dif/pythagoras<double>(dif)); setVelocity(v1); object.setVelocity(v2); return SUCCEEDED; }
const SUCCESS StaticObject::checkCollision(PhysicalObject &object) { if(getCollider() == NULL || object.getCollider() == NULL) { return SUCCEEDED; } else { Radians angle; if(getCollider()->canCollide(object.getCollider()->getType())) if(getCollider()->collides(*object.getCollider(), &angle)) return collided(object, angle); // this ensures that object collider is called by this collided function, likewise a derived class needs to make sure its own derived collided function is called else return SUCCEEDED; else if(object.getCollider()->canCollide(getCollider()->getType())) if(object.getCollider()->collides(*getCollider(), &angle)) return collided(object, angle); else return SUCCEEDED; else return FAILED; } }
const SUCCESS StaticObject::collided(PhysicalObject &object, const Radians angle) { Vector v(object.getVelocity()); v.theta() -= angle; Point<double> appliedMomentum(v); if(fabs(appliedMomentum.x()) < REST_THRESHOLD) { appliedMomentum.x(0); } appliedMomentum.x() *= -1; v = appliedMomentum; v.theta() += angle; object.setVelocity(v); Point<double> dif(getPosition()-object.getPosition()); while(getCollider()->collides(*object.getCollider())) object.setPosition(object.getPosition()-dif/pythagoras<double>(dif)); return SUCCEEDED; }
void HumanMovementPlugin::Refresh(const float &fDeltaTime) { if (m_vControlledObjects.size() > 0) { int dwAlphaInput = gInput()->GetKeyboardAlphaFlags(); VECTOR3 vVelocity; if (dwAlphaInput & INPUT_CHAR_W) { vVelocity.y += 1.0f; } if (dwAlphaInput & INPUT_CHAR_S) { vVelocity.y -= 1.0f; } if (dwAlphaInput & INPUT_CHAR_D) { vVelocity.x += 1.0f; } if (dwAlphaInput & INPUT_CHAR_A) { vVelocity.x -= 1.0f; } float fMagnitudeSquared = MagnitudeSquaredVECTOR3(vVelocity); bool bNoChange = false; if (fMagnitudeSquared > 0.0f) { NormalizeVECTOR3(vVelocity); vVelocity.x *= m_fSpeed; vVelocity.y *= m_fSpeed; vVelocity.z *= m_fSpeed; } else if (fMagnitudeSquared == 0.0f) { bNoChange = true; } vector<PhysicalObject *>::iterator iter; PhysicalObject *pPhysObject = 0; for (iter = m_vControlledObjects.begin(); iter != m_vControlledObjects.end(); iter++) { pPhysObject = *iter; if (pPhysObject) { if (bNoChange) { vVelocity.x *= 0.0f; vVelocity.y *= 0.0f; vVelocity.z *= 0.0f; } pPhysObject->SetVelocity(vVelocity); } } } }
void MapMode::_UpdateExplore() { // First go to menu mode if the user requested it if(_menu_enabled && InputManager->MenuPress()) { MenuMode *MM = new MenuMode(); ModeManager->Push(MM); return; } // Only update the status effect supervisor in Exploration mode // and if they are allowed. if (_status_effects_enabled) _status_effect_supervisor.UpdateEffects(); // Update the running state of the camera object. Check if the character is running and if so, // update the stamina value if the operation is permitted _camera->is_running = false; if(_camera->moved_position && !_running_disabled && InputManager->CancelState() && (InputManager->UpState() || InputManager->DownState() || InputManager->LeftState() || InputManager->RightState())) { if(_unlimited_stamina) { _camera->is_running = true; } else if(_run_stamina > SystemManager->GetUpdateTime() * 2) { _run_stamina -= (SystemManager->GetUpdateTime() * 2); _camera->is_running = true; } else { _run_stamina = 0; } } // Regenerate the stamina at 1/2 the consumption rate else if(_run_stamina < 10000) { _run_stamina += SystemManager->GetUpdateTime(); if(_run_stamina > 10000) _run_stamina = 10000; } // If the user requested a confirm event, check if there is a nearby object that the player may interact with // Interactions are currently limited to dialogue with sprites and opening of treasures if(InputManager->ConfirmPress()) { MapObject *obj = _object_supervisor->FindNearestInteractionObject(_camera); if(obj != NULL) { if(obj->GetType() == PHYSICAL_TYPE) { PhysicalObject *phs = reinterpret_cast<PhysicalObject *>(obj); if(!phs->GetEventIdWhenTalking().empty()) { _camera->moving = false; _camera->is_running = false; if (!_event_supervisor->IsEventActive(phs->GetEventIdWhenTalking())) _event_supervisor->StartEvent(phs->GetEventIdWhenTalking()); return; } } else if(obj->GetType() == SPRITE_TYPE) { MapSprite *sp = reinterpret_cast<MapSprite *>(obj); if(sp->HasAvailableDialogue()) { _camera->moving = false; _camera->is_running = false; sp->InitiateDialogue(); return; } } else if(obj->GetType() == TREASURE_TYPE) { TreasureObject *treasure_object = reinterpret_cast<TreasureObject *>(obj); if(!treasure_object->GetTreasure()->IsTaken()) { _camera->moving = false; treasure_object->Open(); } } else if(obj->GetType() == SAVE_TYPE && _save_points_enabled) { // Make sure the character will be centered in the save point SaveMode *save_mode = new SaveMode(true, obj->GetXPosition(), obj->GetYPosition() - 1.0f); ModeManager->Push(save_mode, false, false); } } } // Detect movement input from the user if(InputManager->UpState() || InputManager->DownState() || InputManager->LeftState() || InputManager->RightState()) { _camera->moving = true; } else { _camera->moving = false; } // Determine the direction of movement. Priority of movement is given to: up, down, left, right. // In the case of diagonal movement, the direction that the sprite should face also needs to be deduced. if(_camera->moving == true) { if(InputManager->UpState()) { if(InputManager->LeftState()) _camera->SetDirection(MOVING_NORTHWEST); else if(InputManager->RightState()) _camera->SetDirection(MOVING_NORTHEAST); else _camera->SetDirection(NORTH); } else if(InputManager->DownState()) { if(InputManager->LeftState()) _camera->SetDirection(MOVING_SOUTHWEST); else if(InputManager->RightState()) _camera->SetDirection(MOVING_SOUTHEAST); else _camera->SetDirection(SOUTH); } else if(InputManager->LeftState()) { _camera->SetDirection(WEST); } else if(InputManager->RightState()) { _camera->SetDirection(EAST); } } // if (_camera->moving == true) } // void MapMode::_UpdateExplore()
/** Updates the physics simulation and handles all collisions. * \param dt Time step. */ void Physics::update(float dt) { PROFILER_PUSH_CPU_MARKER("Physics", 0, 0, 0); m_physics_loop_active = true; // Bullet can report the same collision more than once (up to 4 // contact points per collision). Additionally, more than one internal // substep might be taken, resulting in potentially even more // duplicates. To handle this, all collisions (i.e. pair of objects) // are stored in a vector, but only one entry per collision pair // of objects. m_all_collisions.clear(); // Maximum of three substeps. This will work for framerate down to // 20 FPS (bullet default frequency is 60 HZ). m_dynamics_world->stepSimulation(dt, 3); // Now handle the actual collision. Note: flyables can not be removed // inside of this loop, since the same flyables might hit more than one // other object. So only a flag is set in the flyables, the actual // clean up is then done later in the projectile manager. std::vector<CollisionPair>::iterator p; for(p=m_all_collisions.begin(); p!=m_all_collisions.end(); ++p) { // Kart-kart collision // -------------------- if(p->getUserPointer(0)->is(UserPointer::UP_KART)) { KartKartCollision(p->getUserPointer(0)->getPointerKart(), p->getContactPointCS(0), p->getUserPointer(1)->getPointerKart(), p->getContactPointCS(1) ); continue; } // if kart-kart collision if(p->getUserPointer(0)->is(UserPointer::UP_PHYSICAL_OBJECT)) { // Kart hits physical object // ------------------------- PhysicalObject *obj = p->getUserPointer(0) ->getPointerPhysicalObject(); if(obj->isCrashReset()) { AbstractKart *kart = p->getUserPointer(1)->getPointerKart(); new RescueAnimation(kart); } else if (obj->isExplodeKartObject()) { AbstractKart *kart = p->getUserPointer(1)->getPointerKart(); ExplosionAnimation::create(kart); } else if (obj->isFlattenKartObject()) { AbstractKart *kart = p->getUserPointer(1)->getPointerKart(); const KartProperties* kp = kart->getKartProperties(); kart->setSquash(kp->getSquashDuration(), kp->getSquashSlowdown()); } else if(obj->isSoccerBall()) { int kartId = p->getUserPointer(1)->getPointerKart()->getWorldKartId(); SoccerWorld* soccerWorld = (SoccerWorld*)World::getWorld(); soccerWorld->setLastKartTohitBall(kartId); } continue; } if(p->getUserPointer(0)->is(UserPointer::UP_ANIMATION)) { // Kart hits animation ThreeDAnimation *anim=p->getUserPointer(0)->getPointerAnimation(); if(anim->isCrashReset()) { AbstractKart *kart = p->getUserPointer(1)->getPointerKart(); new RescueAnimation(kart); } else if (anim->isExplodeKartObject()) { AbstractKart *kart = p->getUserPointer(1)->getPointerKart(); ExplosionAnimation::create(kart); } else if (anim->isFlattenKartObject()) { AbstractKart *kart = p->getUserPointer(1)->getPointerKart(); const KartProperties* kp = kart->getKartProperties(); kart->setSquash(kp->getSquashDuration(), kp->getSquashSlowdown()); } continue; } // now the first object must be a projectile // ========================================= if(p->getUserPointer(1)->is(UserPointer::UP_TRACK)) { // Projectile hits track // --------------------- p->getUserPointer(0)->getPointerFlyable()->hitTrack(); } else if(p->getUserPointer(1)->is(UserPointer::UP_PHYSICAL_OBJECT)) { // Projectile hits physical object // ------------------------------- p->getUserPointer(0)->getPointerFlyable() ->hit(NULL, p->getUserPointer(1)->getPointerPhysicalObject()); PhysicalObject* obj = p->getUserPointer(1)->getPointerPhysicalObject(); if(obj->isSoccerBall()) { int kartId = p->getUserPointer(0)->getPointerFlyable()->getOwnerId(); SoccerWorld* soccerWorld = (SoccerWorld*)World::getWorld(); soccerWorld->setLastKartTohitBall(kartId); } } else if(p->getUserPointer(1)->is(UserPointer::UP_KART)) { // Projectile hits kart // -------------------- // Only explode a bowling ball if the target is // not invulnerable AbstractKart* target_kart = p->getUserPointer(1)->getPointerKart(); PowerupManager::PowerupType type = p->getUserPointer(0)->getPointerFlyable()->getType(); if(type != PowerupManager::POWERUP_BOWLING || !target_kart->isInvulnerable()) { p->getUserPointer(0)->getPointerFlyable()->hit(target_kart); if ( type ==PowerupManager::POWERUP_BOWLING ) ((SingleAchievement *) AchievementsManager::get()->getActive()->getAchievement(2))->increase(1); } } else { // Projectile hits projectile // -------------------------- p->getUserPointer(0)->getPointerFlyable()->hit(NULL); p->getUserPointer(1)->getPointerFlyable()->hit(NULL); } } // for all p in m_all_collisions m_physics_loop_active = false; // Now remove the karts that were removed while the above loop // was active. Now we can safely call removeKart, since the loop // is finished and m_physics_world_active is not set anymore. for(unsigned int i=0; i<m_karts_to_delete.size(); i++) removeKart(m_karts_to_delete[i]); m_karts_to_delete.clear(); PROFILER_POP_CPU_MARKER(); } // update
void VirtualSprite::_SetNextPosition() { // Next sprite's position holders float next_pos_x = GetXPosition(); float next_pos_y = GetYPosition(); float distance_moved = CalculateDistanceMoved(); // Move the sprite the appropriate distance in the appropriate Y and X direction if(_direction & (NORTH | MOVING_NORTHWEST | MOVING_NORTHEAST)) next_pos_y -= distance_moved; else if(_direction & (SOUTH | MOVING_SOUTHWEST | MOVING_SOUTHEAST)) next_pos_y += distance_moved; if(_direction & (WEST | MOVING_NORTHWEST | MOVING_SOUTHWEST)) next_pos_x -= distance_moved; else if(_direction & (EAST | MOVING_NORTHEAST | MOVING_SOUTHEAST)) next_pos_x += distance_moved; // When not moving, do not check anything else. if(next_pos_x == GetXPosition() && next_pos_y == GetYPosition()) return; // We've got the next position, let's check whether the next position // should be revised. // Used to know whether we could fall back to a straight move // in case of collision. bool moving_diagonally = (_direction & (MOVING_NORTHWEST | MOVING_NORTHEAST | MOVING_SOUTHEAST | MOVING_SOUTHWEST)); // Handle collision with the first object encountered MapObject* collision_object = nullptr; MapMode* map_mode = MapMode::CurrentInstance(); ObjectSupervisor* object_supervisor = map_mode->GetObjectSupervisor(); COLLISION_TYPE collision_type = object_supervisor->DetectCollision(this, next_pos_x, next_pos_y, &collision_object); // Try to fall back to straight direction if(moving_diagonally && collision_type != NO_COLLISION) { // Try on x axis if(object_supervisor->DetectCollision(this, _tile_position.x, next_pos_y, &collision_object) == NO_COLLISION) { next_pos_x = _tile_position.x; collision_type = NO_COLLISION; } // and then on y axis else if(object_supervisor->DetectCollision(this, next_pos_x, _tile_position.y, &collision_object) == NO_COLLISION) { next_pos_y = _tile_position.y; collision_type = NO_COLLISION; } } // Handles special collision handling first if(_control_event) { switch(_control_event->GetEventType()) { // Don't stuck the player's character or a sprite being controlled by a prepared path. // Plus, it's better not to change a path with encountered beings once started // for simplification purpose. case PATH_MOVE_SPRITE_EVENT: collision_type = NO_COLLISION; break; // Change the direction whenever something blocking is in the way. case RANDOM_MOVE_SPRITE_EVENT: if(collision_type != NO_COLLISION) { SetRandomDirection(); return; } default: break; } } // Try to handle wall and physical collisions after a failed straight or diagonal move switch(collision_type) { case NO_COLLISION: default: break; case WALL_COLLISION: // When being blocked and moving diagonally, the npc is stuck. if(moving_diagonally) return; // Don't consider physical objects with an event to avoid sliding on their edges, // making them harder to "talk with". if (collision_object && this == map_mode->GetCamera()) { PhysicalObject *phs = reinterpret_cast<PhysicalObject *>(collision_object); if(phs && !phs->GetEventIdWhenTalking().empty()) return; } // Fix the direction and destination to walk-around obstacles if (_HandleWallEdges(next_pos_x, next_pos_y, distance_moved, collision_object)) break; // We don't do any other checks for the player sprite. else if (this == map_mode->GetCamera()) return; // NPC sprites: // When it's a true wall, try against the collision grid if(!collision_object) { // Try a random diagonal to avoid the wall in straight direction if(_direction & (NORTH | SOUTH)) _direction |= vt_utils::RandomBoundedInteger(0, 1) ? EAST : WEST; else if(_direction & (EAST | WEST)) _direction |= vt_utils::RandomBoundedInteger(0, 1) ? NORTH : SOUTH; return; } // Physical and treasure objects are the only other matching "fake" walls else { // Try a diagonal to avoid the sprite in straight direction by comparing // each one coords. float diff_x = GetXPosition() - collision_object->GetXPosition(); float diff_y = GetYPosition() - collision_object->GetYPosition(); if(_direction & (NORTH | SOUTH)) _direction |= diff_x >= 0.0f ? EAST : WEST; else if(_direction & (EAST | WEST)) _direction |= diff_y >= 0.0f ? SOUTH : NORTH; return; } // Other cases shouldn't happen. break; case ENEMY_COLLISION: // Check only whether the player has collided with a monster if(this == map_mode->GetCamera() && collision_object && collision_object->GetObjectType() == ENEMY_TYPE) { EnemySprite* enemy = reinterpret_cast<EnemySprite *>(collision_object); // Check whether the player is actually playing. If not, we don't want to start a battle. if (map_mode->CurrentState() == STATE_EXPLORE) map_mode->StartEnemyEncounter(enemy); return; } break; case CHARACTER_COLLISION: // Check whether the sprite is tangled with another character, even without moving // For instance, when colliding with a path follower npc. // And let it through in that case. if(object_supervisor->CheckObjectCollision(GetGridCollisionRectangle(), collision_object)) { collision_type = NO_COLLISION; break; } // When the sprite is controlled by the camera, let the player handle the position correction. if(this == map_mode->GetCamera()) return; // Check whether an enemy has collided with the player if(this->GetType() == ENEMY_TYPE && collision_object == map_mode->GetCamera()) { EnemySprite* enemy = reinterpret_cast<EnemySprite *>(this); // Check whether the player is actually playing. If not, we don't want to start a battle. if (map_mode->CurrentState() == STATE_EXPLORE) map_mode->StartEnemyEncounter(enemy, false, true); // The enemy gets a boost in stamina. return; } // When being blocked and moving diagonally, the npc is stuck. if(moving_diagonally) return; if(!collision_object) // Should never happen return; // Try a diagonal to avoid the sprite in straight direction by comparing // each one coords. float diff_x = GetXPosition() - collision_object->GetXPosition(); float diff_y = GetYPosition() - collision_object->GetYPosition(); if(_direction & (NORTH | SOUTH)) _direction |= diff_x >= 0.0f ? EAST : WEST; else if(_direction & (EAST | WEST)) _direction |= diff_y >= 0.0f ? SOUTH : NORTH; return; } // Inform the overlay system of the parallax movement done if needed if(this == map_mode->GetCamera()) { float x_parallax = !map_mode->IsCameraXAxisInMapCorner() ? (GetXPosition() - next_pos_x) / SCREEN_GRID_X_LENGTH * vt_video::VIDEO_STANDARD_RES_WIDTH : 0.0f; float y_parallax = !map_mode->IsCameraYAxisInMapCorner() ? (GetYPosition() - next_pos_y) / SCREEN_GRID_Y_LENGTH * vt_video::VIDEO_STANDARD_RES_HEIGHT : 0.0f; map_mode->GetEffectSupervisor().AddParallax(x_parallax, y_parallax); map_mode->GetIndicatorSupervisor().AddParallax(x_parallax, y_parallax); } // Make the sprite advance at the end SetPosition(next_pos_x, next_pos_y); _moved_position = true; }
/** Updates the physics simulation and handles all collisions. * \param dt Time step. */ void Physics::update(float dt) { PROFILER_PUSH_CPU_MARKER("Physics", 0, 0, 0); m_physics_loop_active = true; // Bullet can report the same collision more than once (up to 4 // contact points per collision). Additionally, more than one internal // substep might be taken, resulting in potentially even more // duplicates. To handle this, all collisions (i.e. pair of objects) // are stored in a vector, but only one entry per collision pair // of objects. m_all_collisions.clear(); // Maximum of three substeps. This will work for framerate down to // 20 FPS (bullet default frequency is 60 HZ). m_dynamics_world->stepSimulation(dt, 3); // Now handle the actual collision. Note: flyables can not be removed // inside of this loop, since the same flyables might hit more than one // other object. So only a flag is set in the flyables, the actual // clean up is then done later in the projectile manager. std::vector<CollisionPair>::iterator p; for(p=m_all_collisions.begin(); p!=m_all_collisions.end(); ++p) { // Kart-kart collision // -------------------- if(p->getUserPointer(0)->is(UserPointer::UP_KART)) { KartKartCollision(p->getUserPointer(0)->getPointerKart(), p->getContactPointCS(0), p->getUserPointer(1)->getPointerKart(), p->getContactPointCS(1) ); Scripting::ScriptEngine* script_engine = World::getWorld()->getScriptEngine(); int kartid1 = p->getUserPointer(0)->getPointerKart()->getWorldKartId(); int kartid2 = p->getUserPointer(1)->getPointerKart()->getWorldKartId(); script_engine->runFunction("void onKartKartCollision(int, int)", [=](asIScriptContext* ctx) { ctx->SetArgDWord(0, kartid1); ctx->SetArgDWord(1, kartid2); }); continue; } // if kart-kart collision if(p->getUserPointer(0)->is(UserPointer::UP_PHYSICAL_OBJECT)) { // Kart hits physical object // ------------------------- Scripting::ScriptEngine* script_engine = World::getWorld()->getScriptEngine(); AbstractKart *kart = p->getUserPointer(1)->getPointerKart(); int kartId = kart->getWorldKartId(); PhysicalObject* obj = p->getUserPointer(0)->getPointerPhysicalObject(); std::string obj_id = obj->getID(); std::string scripting_function = obj->getOnKartCollisionFunction(); if (scripting_function.size() > 0) { script_engine->runFunction("void " + scripting_function + "(int, const string)", [&](asIScriptContext* ctx) { ctx->SetArgDWord(0, kartId); ctx->SetArgObject(1, &obj_id); }); } if (obj->isCrashReset()) { new RescueAnimation(kart); } else if (obj->isExplodeKartObject()) { ExplosionAnimation::create(kart); } else if (obj->isFlattenKartObject()) { const KartProperties* kp = kart->getKartProperties(); kart->setSquash(kp->getSquashDuration() * kart->getPlayerDifficulty()->getSquashDuration(), kp->getSquashSlowdown() * kart->getPlayerDifficulty()->getSquashSlowdown()); } else if(obj->isSoccerBall() && race_manager->getMinorMode() == RaceManager::MINOR_MODE_SOCCER) { SoccerWorld* soccerWorld = (SoccerWorld*)World::getWorld(); soccerWorld->setLastKartTohitBall(kartId); } continue; } if (p->getUserPointer(0)->is(UserPointer::UP_ANIMATION)) { // Kart hits animation ThreeDAnimation *anim=p->getUserPointer(0)->getPointerAnimation(); if(anim->isCrashReset()) { AbstractKart *kart = p->getUserPointer(1)->getPointerKart(); new RescueAnimation(kart); } else if (anim->isExplodeKartObject()) { AbstractKart *kart = p->getUserPointer(1)->getPointerKart(); ExplosionAnimation::create(kart); } else if (anim->isFlattenKartObject()) { AbstractKart *kart = p->getUserPointer(1)->getPointerKart(); const KartProperties* kp = kart->getKartProperties(); kart->setSquash(kp->getSquashDuration() * kart->getPlayerDifficulty()->getSquashDuration(), kp->getSquashSlowdown() * kart->getPlayerDifficulty()->getSquashSlowdown()); } continue; } // now the first object must be a projectile // ========================================= if(p->getUserPointer(1)->is(UserPointer::UP_TRACK)) { // Projectile hits track // --------------------- p->getUserPointer(0)->getPointerFlyable()->hitTrack(); } else if(p->getUserPointer(1)->is(UserPointer::UP_PHYSICAL_OBJECT)) { // Projectile hits physical object // ------------------------------- Scripting::ScriptEngine* script_engine = World::getWorld()->getScriptEngine(); Flyable* flyable = p->getUserPointer(0)->getPointerFlyable(); PhysicalObject* obj = p->getUserPointer(1)->getPointerPhysicalObject(); std::string obj_id = obj->getID(); std::string scripting_function = obj->getOnItemCollisionFunction(); if (scripting_function.size() > 0) { script_engine->runFunction("void " + scripting_function + "(int, int, const string)", [&](asIScriptContext* ctx) { ctx->SetArgDWord(0, (int)flyable->getType()); ctx->SetArgDWord(1, flyable->getOwnerId()); ctx->SetArgObject(2, &obj_id); }); } flyable->hit(NULL, obj); if (obj->isSoccerBall() && race_manager->getMinorMode() == RaceManager::MINOR_MODE_SOCCER) { int kartId = p->getUserPointer(0)->getPointerFlyable()->getOwnerId(); SoccerWorld* soccerWorld = (SoccerWorld*)World::getWorld(); soccerWorld->setLastKartTohitBall(kartId); } } else if(p->getUserPointer(1)->is(UserPointer::UP_KART)) { // Projectile hits kart // -------------------- // Only explode a bowling ball if the target is // not invulnerable AbstractKart* target_kart = p->getUserPointer(1)->getPointerKart(); PowerupManager::PowerupType type = p->getUserPointer(0)->getPointerFlyable()->getType(); if(type != PowerupManager::POWERUP_BOWLING || !target_kart->isInvulnerable()) { Flyable *f = p->getUserPointer(0)->getPointerFlyable(); f->hit(target_kart); // Check for achievements AbstractKart * kart = World::getWorld()->getKart(f->getOwnerId()); PlayerController *c = dynamic_cast<PlayerController*>(kart->getController()); // Check that it's not a kart hitting itself (this can // happen at the time a flyable is shot - release too close // to the kart, and it's the current player. At this stage // only the current player can get achievements. if (target_kart != kart && c && c->getPlayer()->getConstProfile() == PlayerManager::getCurrentPlayer()) { // Compare the current value of hits with the 'hit' goal value // (otherwise it would be compared with the kart id goal value, // which doesn't exist. PlayerManager::increaseAchievement(AchievementInfo::ACHIEVE_ARCH_ENEMY, target_kart->getIdent(), 1, "hit"); if (type == PowerupManager::POWERUP_BOWLING) { PlayerManager::increaseAchievement(AchievementInfo::ACHIEVE_STRIKE, "ball", 1); } // is bowling ball } // if target_kart != kart && is a player kart and is current player } } else { // Projectile hits projectile // -------------------------- p->getUserPointer(0)->getPointerFlyable()->hit(NULL); p->getUserPointer(1)->getPointerFlyable()->hit(NULL); } } // for all p in m_all_collisions m_physics_loop_active = false; // Now remove the karts that were removed while the above loop // was active. Now we can safely call removeKart, since the loop // is finished and m_physics_world_active is not set anymore. for(unsigned int i=0; i<m_karts_to_delete.size(); i++) removeKart(m_karts_to_delete[i]); m_karts_to_delete.clear(); PROFILER_POP_CPU_MARKER(); } // update
EnkiPlayground(World *world, QWidget *parent = 0) : ViewerWidget(world, parent), subjectiveView(false) { #define PROBLEM_GENERIC_TOY #define PROBLEM_BALL_LINE //#define PROBLEM_LONE_EPUCK #ifdef PROBLEM_GENERIC_TOY { const double amount = 9; const double radius = 5; const double height = 20; Polygone p; for (double a = 0; a < 2*M_PI; a += 2*M_PI/amount) p.push_back(Point(radius * cos(a), radius * sin(a))); PhysicalObject* o = new PhysicalObject; PhysicalObject::Hull hull(Enki::PhysicalObject::Part(p, height)); o->setCustomHull(hull, -1); o->setColor(Color(0.4,0.6,0.8)); o->pos = Point(100, 100); world->addObject(o); } for (int i = 0; i < 20; i++) { PhysicalObject* o = new PhysicalObject; o->pos = Point(UniformRand(20, 100)(), UniformRand(20, 100)()); o->setCylindric(1, 1, 10); o->setColor(Color(0.9, 0.2, 0.2)); o->dryFrictionCoefficient = 0.01; world->addObject(o); } Polygone p2; p2.push_back(Point(5,1)); p2.push_back(Point(-5,1)); p2.push_back(Point(-5,-1)); p2.push_back(Point(5,-1)); for (int i = 0; i < 5; i++) { PhysicalObject* o = new PhysicalObject; PhysicalObject::Hull hull(Enki::PhysicalObject::Part(p2, 3)); o->setCustomHull(hull, 30); o->setColor(Color(0.2, 0.1, 0.6)); o->collisionElasticity = 0.2; o->pos = Point(UniformRand(20, 100)(), UniformRand(20, 100)()); world->addObject(o); } // cross shape { PhysicalObject* o = new PhysicalObject; PhysicalObject::Hull hull; hull.push_back(Enki::PhysicalObject::Part(Polygone() << Point(5,1) << Point(-5,1) << Point(-5,-1) << Point(5,-1), 2)); hull.push_back(Enki::PhysicalObject::Part(Polygone() << Point(1,5) << Point(-1,5) << Point(-1,-5) << Point(1,-5), 4)); o->setCustomHull(hull, 60); o->setColor(Color(0.2, 0.4, 0.6)); o->collisionElasticity = 0.2; o->pos = Point(UniformRand(20, 100)(), UniformRand(20, 100)()); world->addObject(o); } #endif // PROBLEM_GENERIC_TOY #ifdef PROBLEM_BALL_LINE for (double d = 40; d < 60; d += 8) { PhysicalObject* o = new PhysicalObject; o->pos = Point(d, 20); o->setCylindric(4, 2, 10); o->setColor(Color(0.2, 0.2, 0.6)); o->dryFrictionCoefficient = 0.; world->addObject(o); } #endif // PROBLEM_BALL_LINE #ifdef PROBLEM_LONE_EPUCK addDefaultsRobots(world); #endif // PROBLEM_LONE_EPUCK Marxbot *marxbot = new Marxbot; marxbot->pos = Point(60, 50); marxbot->leftSpeed = 8; marxbot->rightSpeed = 2; world->addObject(marxbot); #ifdef USE_SDL if((SDL_Init(SDL_INIT_JOYSTICK)==-1)) { cerr << "Error : Could not initialize SDL: " << SDL_GetError() << endl; addDefaultsRobots(world); return; } int joystickCount = SDL_NumJoysticks(); for (int i = 0; i < joystickCount; ++i) { SDL_Joystick* joystick = SDL_JoystickOpen(i); if (!joystick) { cerr << "Error: Can't open joystick " << i << endl; continue; } if (SDL_JoystickNumAxes(joystick) < 2) { cerr << "Error: not enough axis on joystick" << i<< endl; SDL_JoystickClose(joystick); continue; } joysticks.push_back(joystick); EPuck *epuck = new EPuck; //epuck->pos = Point(UniformRand(20, 100)(), UniformRand(20, 100)()); epuck->pos = Point(20, 20); epucks.push_back(epuck); world->addObject(epuck); } cout << "Added " << joystickCount << " controlled e-pucks." << endl; #else // USE_SDL addDefaultsRobots(world); #endif // USE_SDL camera.altitude = 150; camera.pos = QPointF(0,-60); }
bool PhysicsSim::loadPhysicalObjects(PhysicalStructure &structure, stringc mesh_filename, Vector3D position, bool lock2d) { stringc physics_filename = mesh_filename; physics_filename.remove(".dae"); physics_filename.append(".bullet"); physics_filename = mediaDirectory + physics_filename; if(smgr->getFileSystem()->existFile(physics_filename)) { stringw collada_filename = smgr->getFileSystem()->getAbsolutePath(mediaDirectory) + mesh_filename; if(smgr->getFileSystem()->existFile(collada_filename)) { btBlenderImporter* fileLoader = new btBlenderImporter(position); fileLoader->loadFile(physics_filename.c_str()); smgr->getMesh(collada_filename); for(int i = 0; i < fileLoader->getNumRigidBodies(); i++) { btRigidBody* rb = (btRigidBody*)fileLoader->getRigidBodyByIndex(i); if(lock2d) { rb->setLinearFactor(btVector3(1,0,1)); rb->setAngularFactor(btVector3(0,1,0)); } stringc meshname(fileLoader->getNameForPointer(rb)); stringc bodyname = meshname; stringc tex_file = meshname; s32 underline = tex_file.findFirst('_'); if(underline < 0) underline = tex_file.findFirst('.'); if(underline > -1) tex_file = tex_file.subString(0, underline+1); tex_file = mediaDirectory + tex_file + ".jpg"; if(fileLoader->getNumRigidBodies() > 1) meshname = collada_filename + "#" + meshname + "-mesh"; else meshname = collada_filename; IAnimatedMesh *mesh = smgr->getMeshCache()->getMeshByName(meshname); if(mesh){ IAnimatedMeshSceneNode* node = smgr->addAnimatedMeshSceneNode(mesh, smgr->getRootSceneNode()); node->setMaterialFlag(EMF_LIGHTING, true); node->setMaterialFlag(EMF_TEXTURE_WRAP, false); node->setMaterialFlag(EMF_BACK_FACE_CULLING, false); node->addShadowVolumeSceneNode(0,-1,false); if(smgr->getFileSystem()->existFile(tex_file)) { node->setMaterialTexture(0, driver->getTexture(tex_file)); } PhysicalObject* pobj = new PhysicalObject(node, rb, bodyname); objects_list.push_back(pobj); structure.bodies.push_back(pobj); dynamicsWorld->addRigidBody(pobj->getRigidBody()); } } for(int i = 0; i < fileLoader->getNumConstraints(); i++) { Joint* jt = new Joint(fileLoader->getConstraintByIndex(i)); joints_list.push_back(jt); structure.joints.push_back(jt); btTypedConstraint* constr = jt->getConstraint(); dynamicsWorld->addConstraint(constr, true); } delete fileLoader; updateObjects(); return true; } } return false; }
void PhysicalObject::antigravitate(const PhysicalObject &other) { Vector distance(getPosition()-other.getPosition()); force(Vector(Mag_t<double>(Mass::GetGravityForce(getMass(), other.getMass(), distance.mag())/getMass()), distance.theta())); }
/** Updates the physics simulation and handles all collisions. * \param ticks Number of physics steps to simulate. */ void Physics::update(int ticks) { PROFILER_PUSH_CPU_MARKER("Physics", 0, 0, 0); m_physics_loop_active = true; // Bullet can report the same collision more than once (up to 4 // contact points per collision). Additionally, more than one internal // substep might be taken, resulting in potentially even more // duplicates. To handle this, all collisions (i.e. pair of objects) // are stored in a vector, but only one entry per collision pair // of objects. m_all_collisions.clear(); // Since the world update (which calls physics update) is called at the // fixed frequency necessary for the physics update, we need to do exactly // one physic step only. double start; if(UserConfigParams::m_physics_debug) start = StkTime::getRealTime(); m_dynamics_world->stepSimulation(stk_config->ticks2Time(1), 1, stk_config->ticks2Time(1) ); if (UserConfigParams::m_physics_debug) { Log::verbose("Physics", "At %d physics duration %12.8f", World::getWorld()->getTicksSinceStart(), StkTime::getRealTime() - start); } // Now handle the actual collision. Note: flyables can not be removed // inside of this loop, since the same flyables might hit more than one // other object. So only a flag is set in the flyables, the actual // clean up is then done later in the projectile manager. std::vector<CollisionPair>::iterator p; for(p=m_all_collisions.begin(); p!=m_all_collisions.end(); ++p) { // Kart-kart collision // -------------------- if(p->getUserPointer(0)->is(UserPointer::UP_KART)) { KartKartCollision(p->getUserPointer(0)->getPointerKart(), p->getContactPointCS(0), p->getUserPointer(1)->getPointerKart(), p->getContactPointCS(1) ); Scripting::ScriptEngine* script_engine = Scripting::ScriptEngine::getInstance(); int kartid1 = p->getUserPointer(0)->getPointerKart()->getWorldKartId(); int kartid2 = p->getUserPointer(1)->getPointerKart()->getWorldKartId(); script_engine->runFunction(false, "void onKartKartCollision(int, int)", [=](asIScriptContext* ctx) { ctx->SetArgDWord(0, kartid1); ctx->SetArgDWord(1, kartid2); }); continue; } // if kart-kart collision if(p->getUserPointer(0)->is(UserPointer::UP_PHYSICAL_OBJECT)) { // Kart hits physical object // ------------------------- Scripting::ScriptEngine* script_engine = Scripting::ScriptEngine::getInstance(); AbstractKart *kart = p->getUserPointer(1)->getPointerKart(); int kartId = kart->getWorldKartId(); PhysicalObject* obj = p->getUserPointer(0)->getPointerPhysicalObject(); std::string obj_id = obj->getID(); std::string scripting_function = obj->getOnKartCollisionFunction(); TrackObject* to = obj->getTrackObject(); TrackObject* library = to->getParentLibrary(); std::string lib_id; std::string* lib_id_ptr = NULL; if (library != NULL) lib_id = library->getID(); lib_id_ptr = &lib_id; if (scripting_function.size() > 0) { script_engine->runFunction(true, "void " + scripting_function + "(int, const string, const string)", [&](asIScriptContext* ctx) { ctx->SetArgDWord(0, kartId); ctx->SetArgObject(1, lib_id_ptr); ctx->SetArgObject(2, &obj_id); }); } if (obj->isCrashReset()) { new RescueAnimation(kart); } else if (obj->isExplodeKartObject()) { ExplosionAnimation::create(kart); if (kart->getKartAnimation() != NULL) { World::getWorld()->kartHit(kart->getWorldKartId()); } } else if (obj->isFlattenKartObject()) { const KartProperties *kp = kart->getKartProperties(); // Count squash only once from original state bool was_squashed = kart->isSquashed(); if (kart->setSquash(kp->getSwatterSquashDuration(), kp->getSwatterSquashSlowdown()) && !was_squashed) { World::getWorld()->kartHit(kart->getWorldKartId()); } } else if(obj->isSoccerBall() && race_manager->getMinorMode() == RaceManager::MINOR_MODE_SOCCER) { SoccerWorld* soccerWorld = (SoccerWorld*)World::getWorld(); soccerWorld->setBallHitter(kartId); } continue; } if (p->getUserPointer(0)->is(UserPointer::UP_ANIMATION)) { // Kart hits animation ThreeDAnimation *anim=p->getUserPointer(0)->getPointerAnimation(); if(anim->isCrashReset()) { AbstractKart *kart = p->getUserPointer(1)->getPointerKart(); new RescueAnimation(kart); } else if (anim->isExplodeKartObject()) { AbstractKart *kart = p->getUserPointer(1)->getPointerKart(); ExplosionAnimation::create(kart); if (kart->getKartAnimation() != NULL) { World::getWorld()->kartHit(kart->getWorldKartId()); } } else if (anim->isFlattenKartObject()) { AbstractKart *kart = p->getUserPointer(1)->getPointerKart(); const KartProperties *kp = kart->getKartProperties(); // Count squash only once from original state bool was_squashed = kart->isSquashed(); if (kart->setSquash(kp->getSwatterSquashDuration(), kp->getSwatterSquashSlowdown()) && !was_squashed) { World::getWorld()->kartHit(kart->getWorldKartId()); } } continue; } // now the first object must be a projectile // ========================================= if(p->getUserPointer(1)->is(UserPointer::UP_TRACK)) { // Projectile hits track // --------------------- p->getUserPointer(0)->getPointerFlyable()->hitTrack(); } else if(p->getUserPointer(1)->is(UserPointer::UP_PHYSICAL_OBJECT)) { // Projectile hits physical object // ------------------------------- Scripting::ScriptEngine* script_engine = Scripting::ScriptEngine::getInstance(); Flyable* flyable = p->getUserPointer(0)->getPointerFlyable(); PhysicalObject* obj = p->getUserPointer(1)->getPointerPhysicalObject(); std::string obj_id = obj->getID(); std::string scripting_function = obj->getOnItemCollisionFunction(); if (scripting_function.size() > 0) { script_engine->runFunction(true, "void " + scripting_function + "(int, int, const string)", [&](asIScriptContext* ctx) { ctx->SetArgDWord(0, (int)flyable->getType()); ctx->SetArgDWord(1, flyable->getOwnerId()); ctx->SetArgObject(2, &obj_id); }); } flyable->hit(NULL, obj); if (obj->isSoccerBall() && race_manager->getMinorMode() == RaceManager::MINOR_MODE_SOCCER) { int kartId = p->getUserPointer(0)->getPointerFlyable()->getOwnerId(); SoccerWorld* soccerWorld = (SoccerWorld*)World::getWorld(); soccerWorld->setBallHitter(kartId); } } else if(p->getUserPointer(1)->is(UserPointer::UP_KART)) { // Projectile hits kart // -------------------- // Only explode a bowling ball if the target is // not invulnerable AbstractKart* target_kart = p->getUserPointer(1)->getPointerKart(); PowerupManager::PowerupType type = p->getUserPointer(0)->getPointerFlyable()->getType(); if(type != PowerupManager::POWERUP_BOWLING || !target_kart->isInvulnerable()) { Flyable *f = p->getUserPointer(0)->getPointerFlyable(); f->hit(target_kart); // Check for achievements AbstractKart * kart = World::getWorld()->getKart(f->getOwnerId()); LocalPlayerController *lpc = dynamic_cast<LocalPlayerController*>(kart->getController()); // Check that it's not a kart hitting itself (this can // happen at the time a flyable is shot - release too close // to the kart, and it's the current player. At this stage // only the current player can get achievements. if (target_kart != kart && lpc && lpc->canGetAchievements()) { if (type == PowerupManager::POWERUP_BOWLING) { PlayerManager::increaseAchievement(AchievementsStatus::BOWLING_HIT, 1); if (race_manager->isLinearRaceMode()) PlayerManager::increaseAchievement(AchievementsStatus::BOWLING_HIT_1RACE, 1); } // is bowling ball } // if target_kart != kart && is a player kart and is current player } } else { // Projectile hits projectile // -------------------------- p->getUserPointer(0)->getPointerFlyable()->hit(NULL); p->getUserPointer(1)->getPointerFlyable()->hit(NULL); } } // for all p in m_all_collisions m_physics_loop_active = false; // Now remove the karts that were removed while the above loop // was active. Now we can safely call removeKart, since the loop // is finished and m_physics_world_active is not set anymore. for(unsigned int i=0; i<m_karts_to_delete.size(); i++) removeKart(m_karts_to_delete[i]); m_karts_to_delete.clear(); PROFILER_POP_CPU_MARKER(); } // update
bool PhysicalObject::isIntersecting(PhysicalObject &physicalObject) { return !(getPolygonShape().intersected(physicalObject.getPolygonShape()).isEmpty()); }
void Player::initCommands() { std::function<void (std::vector<std::string> commandWords, std::function<bool(const std::vector<std::string> &)>)> addCommands = [this](std::vector<std::string> commandWords, std::function<bool(const std::vector<std::string> &)> operation){ if(commandWords.size() < 1) { throw std::invalid_argument("You must at least have one word associated with the command"); } uniqueCommands.push_back(commandWords.front()); for(std::string word: commandWords){ if(commands.find(word) != commands.end()) { throw std::invalid_argument("The word: " + word + " is associated with more than one command"); } commands[word] = operation; } }; std::function<bool (const std::vector<std::string> & commands, const std::string & helpText, const std::string & usageCommands)> isHelp = [](const std::vector<std::string> & commands, const std::string & helpText, const std::string & usageCommands){ if(commands.size() != 2){ return false; }; if(commands[1] != "help"){ return false; }; std::cout << TEXT_DIVIDER << " HELP: " << commands[0] << " " << TEXT_DIVIDER << std::endl; if(helpText != "") { std::cout << helpText << std::endl; } std::cout << "Usage: " << commands[0] << " " << usageCommands << std::endl; return true; }; addCommands({"go", "move", "goto"}, [this, isHelp](const std::vector<std::string> & commands) -> bool { if(isHelp(commands, "Used for navigating through the world.", "LOCATION")) { return false; } if(commands.size() != 2) { std::cout << "You forgot to write where you wanna go." << std::endl; return false; } int num = -1; try { num = atoi(commands[1].c_str()) - 1; } catch(int) { std::cout << "That is not an option. Write one of the numbers given as option." << std::endl; return false; } auto dirs = getEnvironment()->getDirections(); if(num >= dirs.size()) { std::cout << "That is not an option. Write one of the numbers given as option." << std::endl; return false; } if(!this->move(dirs[num])) { std::cout << "That is not an option. Write one of the numbers given as option." << std::endl; return false; } return true; }); addCommands({"look"}, [this, isHelp](const std::vector<std::string> & commands) -> bool { if(isHelp(commands, "Look for example at different characters or on items to get more information. You can look at almost anything in the world.", "[CONTAINER] [OBJECT]")) { return false;} Environment * env = getEnvironment(); if(commands.size() == 1) { printUpdateInfo(); } else if(commands.size() == 2) { if(isCommandInventory(commands[1])) { std::cout << getInventory()->getDescription() << std::endl; return false; } if(isCommandEquipment(commands[1])) { std::cout << getEquipment()->getDescription() << std::endl; return false; } PhysicalObject * physicalObject = env->find(commands[1]); if(physicalObject == NULL) { std::cout << "Found no item named: " << commands[1] << std::endl; } else { std::cout << physicalObject->getDescription() << std::endl; } } else if(commands.size() == 3) { Item * item = NULL; if(isCommandInventory(commands[1])) { Inventory * inv = getInventory(); item = inv->find(commands[2]); if(item == NULL) { std::cout << "Found no item named: " << commands[2] << " in your inventory." << std::endl; return false; } } else if(isCommandEquipment(commands[1])) { Equipment * eq = getEquipment(); item = eq->find(commands[2]); if(item == NULL) { std::cout << "Found no item named: " << commands[2] << " in your equipment." << std::endl; return false; } } else { Container * con = env->find<Container>(OBJECT_TYPE_CONTAINER, commands[2]); if(con == NULL) { std::cout << "Found no container named: " <<commands[1] << std::endl; return false; } else { item = con->find(commands[2]); if(item == NULL) { std::cout << "Found no item named: " << commands[2] << " in container: " << con->getName() << std::endl; return false; } } } std::cout << item->getDescription() << std::endl; } return false; }); addCommands({"stats"}, [this, isHelp](const std::vector<std::string> & commands) -> bool { if(isHelp(commands,"Get information about you.", "")) { return false;} std::cout << getDescription() << std::endl; return false; }); addCommands({"inventory", "backpack", "inv"}, [this, isHelp](const std::vector<std::string> & commands) -> bool { if(isHelp(commands, "Get information about your inventory that contains items.", "")) { return false;} Inventory * inv = getInventory(); std::cout << inv->getDescription() << std::endl; return false; }); addCommands({"equipment"}, [this, isHelp](const std::vector<std::string> & commands) -> bool { if(isHelp(commands, "Get information about your current equipment.", "")) { return false;} Equipment * eq = getEquipment(); std::cout << eq->getDescription() << std::endl; return false; }); addCommands({"pick"}, [this, isHelp](const std::vector<std::string> & commands) -> bool { if(isHelp(commands,"Pick up items from the ground or from containers like for example Chests.", "[CONTAINER] ITEM")) { return false;} if(commands.size() < 2) { std::cout << "You forgot to write what you wanted to pick up." << std::endl; return false; } Environment * env = getEnvironment(); if(commands.size() == 2) { Item * item = env->find<Item>(OBJECT_TYPE_ITEM, commands[1]); if(item == NULL) { std::cout << "Found no item named: " << commands[1] << std::endl; return false; } if(!pickItem(item)) { std::cout << "You can't pick up item: " << commands[1] << std::endl; return false; } std::cout << "You picked up item: " << commands[1] << std::endl; return false; } else if(commands.size() == 3) { Container * container = env->find<Container>(OBJECT_TYPE_CONTAINER, commands[1]); if(container == NULL) { std::cout << "Found no container named: " <<commands[1] << std::endl; return false; } Item * item = container->find<Item>(OBJECT_TYPE_ITEM, commands[2]); if(item == NULL) { std::cout << "Found no item named: " << commands[2] << " in container: " << commands[1] << std::endl; return false; } if(!pickItem(item, container)) { std::cout << "You can't pick up item: " << commands[2] << " in container: " << commands[1] << std::endl; return false; } std::cout << "You picked up item: " << commands[2] << " from container: " << commands[1]<< std::endl; return false; } std::cout << "Invalid command syntax. Usage: pick [CONTAINER] ITEM" << std::endl; return false; }); addCommands({"drop", "put"}, [this, isHelp](const std::vector<std::string> & commands) -> bool { if(isHelp(commands, "Drop items on the ground or drop them into containers.", "[CONTAINER] ITEM")) { return false;} if(commands.size() < 2) { std::cout << "You forgot to write what you wanted to drop." << std::endl; return false; } Inventory * inv = getInventory(); if(commands.size() == 2) { Item * item = inv->find(commands[1]); if(item == NULL) { std::cout << "Found no item named: " << commands[1] << " in your inventory." << std::endl; return false; } if(!dropItem(item)) { std::cout << "You can't drop item: " << commands[1] << " from your inventory. " << std::endl; return false; } std::cout << "You dropped item: " << commands[1] << " from your inventory. " << std::endl; return false; } else if(commands.size() == 3) { Environment * env = getEnvironment(); Container * container = env->find<Container>(OBJECT_TYPE_CONTAINER, commands[1]); if(container == NULL) { std::cout << "Found no container named: " <<commands[1] << std::endl; return false; } Item * item = inv->find(commands[2]); if(item == NULL) { std::cout << "Found no item named: " << commands[2] << " in your inventory." << std::endl; return false; } if(!putItem(item, container)) { std::cout << "You can't put item: " << commands[2] << " in container: " << commands[1] << std::endl; return false; } std::cout << "You put item: " << commands[2] << " in container: " << commands[1] << std::endl; return false; } std::cout << "Invalid command syntax. Usage: drop [CONTAINER] ITEM" << std::endl; return false; }); addCommands({"open"}, [this, isHelp](const std::vector<std::string> & commands) -> bool { if(isHelp(commands,"The same as 'look CONTAINER'.", "CONTAINER")) { return false;} if(commands.size() != 2) { std::cout << "You forgot to write what you wanted to open." << std::endl; return false; } Environment * env = getEnvironment(); Container * container = env->find<Container>(OBJECT_TYPE_CONTAINER, commands[1]); if(container == NULL) { std::cout << "Found no container named: " <<commands[1] << std::endl; return false; } int takenSpace = container->getTakenSpace(); std::string takenSpaceText = unsignedValToString(takenSpace); std::cout << container->getDescription() << std::endl; return false; }); addCommands({"unlock"}, [this, isHelp](const std::vector<std::string> & commands) -> bool { if(isHelp(commands, "Unlock containers or items using this command.", "[CONTAINER] LOCKED_OBJECT KEY")) { return false;} Environment * env = getEnvironment(); Inventory * inv = getInventory(); if(commands.size() < 3 || commands.size() > 4) { std::cout << "Invalid command syntax. Usage: unlock [CONTAINER] LOCKED_OBJECT KEY" << std::endl; return false; } KeyLock * lock = NULL; std::string containerString; std::string lockString; std::string keyString; if(commands.size() == 4) { lockString = commands[2]; keyString = commands[3]; Container * con; if(isCommandInventory(commands[1])) { con = inv; } else { con = env->find<Container>(OBJECT_TYPE_CONTAINER, commands[1]); } if(con == NULL) { std::cout << "Found no container named: " << commands[1] << std::endl; return false; } lock = dynamic_cast<KeyLock *>(con->find(commands[1])); containerString = " in container named: " + con->getName(); } else if(commands.size() == 3) { containerString = ""; lockString = commands[1]; keyString = commands[2]; lock = dynamic_cast<KeyLock *>(env->find(commands[1])); } if(lock == NULL) { std::cout << "Found no lockable object named: " << lockString << containerString << std::endl; return false; } Key * key = inv->find<Key>(OBJECT_TYPE_ITEM, ITEM_TYPE_KEY, keyString); if(key == NULL) { std::cout << "Found no key named: " << keyString << " in your inventory."<< std::endl; return false; } std::string keyName = key->getName(); PhysicalObject * test = dynamic_cast<PhysicalObject*>(lock); // Needed because not strictly if(test == nullptr) { throw std::runtime_error("The lockable item was not a PhysicalObject. Should not be possible."); } std::string lockName = test->getName(); if(lock->unlock(key, *inv)) { std::cout << "You unlocked: " << lockName << containerString << " using key: " << keyName << std::endl; return false; } else { std::cout << "You can't unlock: " << lockName << containerString << " using key: " << keyName << std::endl; return false; } }); addCommands({"eat", "drink"}, [this, isHelp](const std::vector<std::string> & commands) -> bool { if(isHelp(commands,"Use this command to consume items. Tip: Write 'drink' so you don't accidentally chew liquids.", "ITEM")) { return false;} if(commands.size() != 2) { std::cout << "Invalid command syntax. Usage: eat FOOD" << std::endl; return false; } Consumable * cItem = getInventory()->find<Consumable>(OBJECT_TYPE_ITEM, ITEM_TYPE_CONSUMABLE, commands[1]); if(cItem == NULL) { std::cout << "Found no consumable item named: " << commands[1] << " in your inventory."<< std::endl; return false; } std::string consumableName = cItem->getName(); std::string response = cItem->consume(this); std::cout << "You digested " << consumableName << " and " << response << std::endl; return false; }); addCommands({"equip", "eq"}, [this, isHelp](const std::vector<std::string> & commands) -> bool { if(isHelp(commands, "Used for equipping items. You can only equip one of each type of equippable item.", "[ITEM]")) { return false;} if(commands.size() != 2) { std::cout << "Invalid command syntax. Usage: equip ITEM" << std::endl; return false; } Inventory * inv = getInventory(); Item * item = inv->find(commands[1]); if(item == NULL) { std::cout << "Found no equipable item named: " << commands[1] << std::endl; return false; } BreakableItem * bItem = dynamic_cast<BreakableItem*>(item); if(bItem == nullptr) { std::cout << "The item: " << item->getName() << " is not equipable." << std::endl; return false; } if(equip(bItem)) { std::cout << "You equipeed item: " << bItem->getName() << std::endl; return false; } else { std::cout << "You failed to equip: " << bItem->getName() << std::endl; return false; } }); addCommands({"unequip", "uneq", "ueq"}, [this, isHelp](const std::vector<std::string> & commands) -> bool { if(isHelp(commands,"Used for removing equipped items and putting them back to your inventory, if you have enough space.", "ITEM")) { return false;} if(commands.size() != 2) { std::cout << "Invalid command syntax. Usage: equip ITEM" << std::endl; return false; } Equipment * eq = getEquipment(); BreakableItem * bItem = eq->find(commands[1]); if(bItem == NULL) { std::cout << "Found no equiped item named: " << commands[1] << std::endl; return false; } if(unEquip(bItem)) { std::cout << "You unequiped item: " << bItem->getName() << std::endl; return false; } else { std::cout << "You failed to unequip: " << bItem->getName() << std::endl; return false; } }); addCommands({"attack", "att"}, [this, isHelp](const std::vector<std::string> & commands) -> bool { if(isHelp(commands, "KILL!", "CHARACTER")) { return false;} if(commands.size() != 2) { std::cout << "You forgot to write what you wanted to attack." << std::endl; return false; } Character * character = getEnvironment()->find<Character>(OBJECT_TYPE_CHARACTER, commands[1], {this}); if(character == NULL) { std::cout << "There is no " + commands[1] << " in the area." << std::endl; return false; } if(!character->startInteraction(this)) { std::cout << "The " << character->getName() << " busy fighting already." << std::endl; return false; } std::cout << std::endl << "You are initiating a fight with " << character->getName() << "!" << std::endl; interact(character); character->endInteraction(this); endInteraction(character); return true; }); addCommands({"pass", "wait", "skip"}, [isHelp](const std::vector<std::string> & commands) -> bool { if(isHelp(commands,"Wait a moment and let others take their turn.", "")) { return false;} return true; }); addCommands({"exit"}, [this, isHelp](const std::vector<std::string> & commands) -> bool { if(isHelp(commands,"Exit the game. No turning back after this.", "")) { return false;} this->getEngine()->kill(); return true; }); addCommands({"help"}, [this, isHelp](const std::vector<std::string> & commands) -> bool { if(isHelp(commands,"Helpception?", "")) { return false;} std::cout << std::endl; std::cout << TEXT_DIVIDER << " HELP START " << TEXT_DIVIDER << std::endl; std::cout << "For more help on individual commands, write: COMMAND help" << std::endl; std::cout << "COMMANDS" << std::endl; std::cout << TEXT_DIVIDER << std::endl; for(auto command : getUniqueCommands()) { std::cout << command << std::endl; } std::cout << TEXT_DIVIDER << " HELP END " << TEXT_DIVIDER << std::endl; return false; }); }
virtual void timerEvent(QTimerEvent * event) { static int fireCounter = 0; #ifdef USE_SDL SDL_JoystickUpdate(); doDumpFrames = false; for (int i = 0; i < joysticks.size(); ++i) { EPuck* epuck = epucks[i]; if (world->hasGroundTexture()) cout << "Robot " << i << " is on ground of colour " << world->getGroundColor(epuck->pos) << endl; #define SPEED_MAX 13. //cout << "S " << epuck->infraredSensor2.getRayDist(0) << " " << epuck->infraredSensor2.getRayDist(1) << " " << epuck->infraredSensor2.getRayDist(2) << endl; #if 0 epuck->leftSpeed = - SDL_JoystickGetAxis(joysticks[i], 1) / (32767. / SPEED_MAX); epuck->rightSpeed = - SDL_JoystickGetAxis(joysticks[i], 4) / (32767. / SPEED_MAX); #else double x = SDL_JoystickGetAxis(joysticks[i], 0) / (32767. / SPEED_MAX); double y = -SDL_JoystickGetAxis(joysticks[i], 1) / (32767. / SPEED_MAX); epuck->leftSpeed = y + x; epuck->rightSpeed = y - x; #endif if ((SDL_JoystickGetButton(joysticks[i], 6) || SDL_JoystickGetButton(joysticks[i], 7)) && (++fireCounter % 2) == 0) { PhysicalObject* o = new PhysicalObject; Vector delta(cos(epuck->angle), sin(epuck->angle)); o->pos = epuck->pos + delta * 6; o->speed = epuck->speed + delta * 10; o->setCylindric(0.5, 0.5, 10); o->dryFrictionCoefficient = 0.01; o->setColor(Color(0.4, 0, 0)); o->collisionElasticity = 1; bullets[o] = 300; world->addObject(o); } doDumpFrames |= SDL_JoystickGetButton(joysticks[i], 0); } if (joysticks.size() > 0 && subjectiveView) { const EPuck* epuck = epucks[0]; Vector p(epuck->pos); camera.pos.setX(p.x+cos(camera.yaw)*7); camera.pos.setY(p.y+sin(camera.yaw)*7); camera.yaw = epuck->angle; camera.altitude = 11; } #endif QMap<PhysicalObject*, int>::iterator i = bullets.begin(); while (i != bullets.end()) { QMap<PhysicalObject*, int>::iterator oi = i; ++i; if (oi.value()) { oi.value()--; } else { PhysicalObject* o = oi.key(); world->removeObject(o); bullets.erase(oi); delete o; } } ViewerWidget::timerEvent(event); }
void SimObjectRenderer::draw() { // update a moving camera if(moving) { unsigned int now = System::getTime(); int x = 0; int y = 0; if(movingLeftStartTime) { x -= now - movingLeftStartTime; movingLeftStartTime = now; } if(movingRightStartTime) { x += now - movingRightStartTime; movingRightStartTime = now; } if(movingUpStartTime) { y -= now - movingUpStartTime; movingUpStartTime = now; } if(movingDownStartTime) { y += now - movingDownStartTime; movingDownStartTime = now; } moveCamera(float(x) * 0.001f, float(y) * 0.002f); } // set flags if(renderFlags & enableLights) glEnable(GL_LIGHTING); else glDisable(GL_LIGHTING); if(renderFlags & enableMultisample) glEnable(GL_MULTISAMPLE); else glDisable(GL_MULTISAMPLE); if(renderFlags & enableTextures) glEnable(GL_TEXTURE_2D); else glDisable(GL_TEXTURE_2D); // clear glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // load camera position glLoadMatrixf(cameraTransformation); // make sure transformations of movable bodies are up-to-date // note: a not-physical-object has a constant offset pose relative its parent. hence there is no transformation update required to draw not-physical-objects PhysicalObject* physicalObject = dynamic_cast<PhysicalObject*>(&simObject); GraphicalObject* graphicalObject = dynamic_cast<GraphicalObject*>(&simObject); if(physicalObject) Simulation::simulation->scene->updateTransformations(); // since each object will be drawn relative to its parent we need to shift the coordinate system when we want the object to be in the center if(&simObject != Simulation::simulation->scene && !(renderFlags & showAsGlobalView)) { const float* transformation = simObject.transformation; Pose3<> pose(Matrix3x3<>(Vector3<>(transformation[0], transformation[1], transformation[2]), Vector3<>(transformation[4], transformation[5], transformation[6]), Vector3<>(transformation[8], transformation[9], transformation[10])), Vector3<>(transformation[12], transformation[13], transformation[14])); float invTrans[16]; OpenGLTools::convertTransformation(pose.invert(), invTrans); glMultMatrixf(invTrans); } // draw origin if(renderFlags & showCoordinateSystem) { Simulation::simulation->scene->defaultSurface->set(); glBegin(GL_LINES); glNormal3f (0,0,1); glColor3f(1, 0, 0); glVertex3f(0, 0, 0); glVertex3f(1, 0, 0); glColor3f(0, 1, 0); glVertex3f(0, 0, 0); glVertex3f(0, 1, 0); glColor3f(0, 0, 1); glVertex3f(0, 0, 0); glVertex3f(0, 0, 1); glEnd(); Simulation::simulation->scene->defaultSurface->unset(); } // draw object / scene appearance if(graphicalObject && surfaceShadeMode != noShading) { switch(surfaceShadeMode) { case flatShading: glPolygonMode(GL_FRONT, GL_FILL); glShadeModel(GL_FLAT); break; case wireframeShading: glPolygonMode(GL_FRONT, GL_LINE); glShadeModel(GL_FLAT); break; case smoothShading: glPolygonMode(GL_FRONT, GL_FILL); glShadeModel(GL_SMOOTH); break; default: ASSERT(false); break; } graphicalObject->drawAppearances(); // check matrix stack size #ifdef _DEBUG int stackDepth; glGetIntegerv(GL_MODELVIEW_STACK_DEPTH, &stackDepth); ASSERT(stackDepth == 1); #endif } // draw object / scene physics if(physicalObject && (physicsShadeMode != noShading || renderFlags & showSensors)) { Simulation::simulation->scene->defaultSurface->set(); unsigned int renderFlags = (this->renderFlags | showPhysics) & ~showControllerDrawings; switch(physicsShadeMode) { case noShading: glPolygonMode(GL_FRONT, GL_LINE); glShadeModel(GL_FLAT); renderFlags &= ~showPhysics; break; case flatShading: glPolygonMode(GL_FRONT, GL_FILL); glShadeModel(GL_FLAT); break; case wireframeShading: glPolygonMode(GL_FRONT, GL_LINE); glShadeModel(GL_FLAT); break; case smoothShading: glPolygonMode(GL_FRONT, GL_FILL); glShadeModel(GL_SMOOTH); break; default: ASSERT(false); break; } physicalObject->drawPhysics(renderFlags); Simulation::simulation->scene->defaultSurface->unset(); // check matrix stack size #ifdef _DEBUG int stackDepth; glGetIntegerv(GL_MODELVIEW_STACK_DEPTH, &stackDepth); ASSERT(stackDepth == 1); #endif } // draw drag plane if(dragging && dragSelection) { Simulation::simulation->scene->defaultSurface->set(); glPolygonMode(GL_FRONT, GL_FILL); glShadeModel(GL_FLAT); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_SRC_ALPHA); glPushMatrix(); if(dragType == dragRotate || dragType == dragNormalObject) glMultMatrixf(dragSelection->transformation); else glTranslatef(dragSelection->pose.translation.x, dragSelection->pose.translation.y, dragSelection->pose.translation.z); switch(dragPlane) { case xyPlane: break; // do nothing case xzPlane: glRotatef(90.f, 1.f, 0.f, 0.f); break; case yzPlane: glRotatef(90.f, 0.f, 1.f, 0.f); break; } GLUquadricObj* q = gluNewQuadric(); glColor4f(0.5f, 0.5f, 0.5f, 0.5f); glNormal3f(0,0,1); gluDisk(q, 0.003f, 0.5f, 30, 1); glRotatef(180.f, 1.f, 0.f, 0.f); gluDisk(q, 0.003f, 0.5f, 30, 1); gluDeleteQuadric(q); glPopMatrix(); glDisable(GL_BLEND); Simulation::simulation->scene->defaultSurface->unset(); } // draw controller drawings if(physicalObject && drawingsShadeMode != noShading) { Simulation::simulation->scene->defaultSurface->set(); switch(drawingsShadeMode) { case flatShading: glPolygonMode(GL_FRONT, GL_FILL); glShadeModel(GL_FLAT); break; case wireframeShading: glPolygonMode(GL_FRONT, GL_LINE); glShadeModel(GL_FLAT); break; case smoothShading: glPolygonMode(GL_FRONT, GL_FILL); glShadeModel(GL_SMOOTH); break; default: ASSERT(false); break; } if(renderFlags & (enableDrawingsTransparentOcclusion | enableDrawingsOcclusion)) { physicalObject->drawPhysics(showControllerDrawings); if(renderFlags & enableDrawingsTransparentOcclusion) { glAccum(GL_LOAD, 0.5f); glClear(GL_DEPTH_BUFFER_BIT); physicalObject->drawPhysics(showControllerDrawings); glAccum(GL_ACCUM, 0.5f); glAccum(GL_RETURN, 1.f); } } else { glClear(GL_DEPTH_BUFFER_BIT); physicalObject->drawPhysics(showControllerDrawings); } Simulation::simulation->scene->defaultSurface->unset(); // check matrix stack size #ifdef _DEBUG int stackDepth; glGetIntegerv(GL_MODELVIEW_STACK_DEPTH, &stackDepth); ASSERT(stackDepth == 1); #endif } }
void Weapon::Fire() { if (m_fCurrentCooldown <= 0.0f) { m_fCurrentCooldown = m_fCooldown; PhysicalObject *pOwner = GetOwner(); if (pOwner) { Node *pSourceNode = pOwner->GetNode(); if (pSourceNode) { Projectile *pNewProjectile = new Projectile(GetNode()); VECTOR3 vDirection; Matrix44 mat = pSourceNode->m_PosQuat.quat.ToMatrix(); float yDisp = -(pSourceNode->m_vScale.y / 2.0f + pNewProjectile->GetNode()->m_vScale.y / 2.0f); if (pSourceNode->GetNodeFlags() & NODE_RENDER_UPSIDEDOWN) { yDisp *= -1.0f; } pNewProjectile->GetNode()->m_PosQuat.pos.x = mat.m[4] * yDisp + pSourceNode->m_PosQuat.pos.x; pNewProjectile->GetNode()->m_PosQuat.pos.y = mat.m[5] * yDisp + pSourceNode->m_PosQuat.pos.y; pNewProjectile->GetNode()->m_PosQuat.pos.z = mat.m[6] * yDisp + pSourceNode->m_PosQuat.pos.z; //calculate actual firing direction based on aim, and weapon spread int dwRandom = GenerateRandomInt(9); float fSpread = 0.0f; if (dwRandom < 7) { fSpread = GenerateRandomFloat(0.05f); } else if (dwRandom < 9) { fSpread = GenerateRandomFloat(0.15f) + 0.05f; } else { fSpread = GenerateRandomFloat(0.30f) + 0.2f; } if (GenerateRandomInt(1)) { fSpread = -fSpread; } fSpread = fSpread * m_fFiringSpread; float fCos = cos(fSpread); float fSin = sin(fSpread); //vDirection.x = fCos * m_vAim.x + fSin * m_vAim.x; //vDirection.y = fCos * m_vAim.y - fSin * m_vAim.y; vDirection.x = fCos * m_vAim.x - fSin * m_vAim.y; vDirection.y = fSin * m_vAim.x + fCos * m_vAim.y; vDirection.z = 0.0f; NormalizeVECTOR3(vDirection); pNewProjectile->GetNode()->m_PosQuat.pos.z = pSourceNode->m_PosQuat.pos.z; pNewProjectile->SetMaxSpeed(m_fSpeed); pNewProjectile->SetVelocity(VECTOR3(m_fSpeed * vDirection.x, m_fSpeed * vDirection.y, m_fSpeed * vDirection.z)); pNewProjectile->SetCreator(pOwner); pNewProjectile->SetWeapon(this); Quat *quat = &(pNewProjectile->GetNode()->m_PosQuat.quat); Quat rotation; rotation.CreateFromRotationRADIANS(fSpread, 0.0f, 0.0f, 1.0f); *quat = rotation * *quat; TestFireEvent *pTestFireEvent = new TestFireEvent(); pTestFireEvent->SetProjectile(pNewProjectile); gEventManager()->AddEvent(pTestFireEvent); pTestFireEvent->Release(); pNewProjectile->Release(); } } } }