Degree wrapAngle(Degree angle) { if (angle.valueDegrees() < -360.0f) angle += Degree(360.0f); if (angle.valueDegrees() > 360.0f) angle -= Degree(360.0f); return angle; }
void SkyManager::update(float duration) { if (!mEnabled) return; const MWWorld::Fallback* fallback=MWBase::Environment::get().getWorld()->getFallback(); if (!mParticle.isNull()) { for (unsigned int i=0; i<mParticle->mControllers.size(); ++i) mParticle->mControllers[i].update(); } updateRain(duration); // UV Scroll the clouds mCloudAnimationTimer += duration * mCloudSpeed; sh::Factory::getInstance().setSharedParameter ("cloudAnimationTimer", sh::makeProperty<sh::FloatValue>(new sh::FloatValue(mCloudAnimationTimer))); /// \todo improve this mMasser->setPhase( static_cast<Moon::Phase>( (int) ((mDay % 32)/4.f)) ); mSecunda->setPhase ( static_cast<Moon::Phase>( (int) ((mDay % 32)/4.f)) ); mSecunda->setColour ( mMoonRed ? fallback->getFallbackColour("Moons_Script_Color") : ColourValue(1,1,1,1)); mMasser->setColour (ColourValue(1,1,1,1)); if (mSunEnabled) { // take 1/10 sec for fading the glare effect from invisible to full if (mGlareFade > mGlare) { mGlareFade -= duration*10; if (mGlareFade < mGlare) mGlareFade = mGlare; } else if (mGlareFade < mGlare) { mGlareFade += duration*10; if (mGlareFade > mGlare) mGlareFade = mGlare; } // increase the strength of the sun glare effect depending // on how directly the player is looking at the sun Vector3 sun = mSunGlare->getPosition(); Vector3 cam = mCamera->getRealDirection(); const Degree angle = sun.angleBetween( cam ); float val = 1- (angle.valueDegrees() / 180.f); val = (val*val*val*val)*6; mSunGlare->setSize(val * mGlareFade); } mSunGlare->setVisible(mSunEnabled); mSun->setVisible(mSunEnabled); mMasser->setVisible(mMasserEnabled); mSecunda->setVisible(mSecundaEnabled); // rotate the stars by 360 degrees every 4 days mAtmosphereNight->roll(Degree(MWBase::Environment::get().getWorld()->getTimeScaleFactor()*duration*360 / (3600*96.f))); }
void SkyManager::update(float duration) { if (!mEnabled) return; mCamera->getParentSceneNode ()->needUpdate (); mRootNode->setPosition(mCamera->getDerivedPosition()); // UV Scroll the clouds mCloudAnimationTimer += duration * mCloudSpeed * (MWBase::Environment::get().getWorld()->getTimeScaleFactor()/30.f); sh::Factory::getInstance().setSharedParameter ("cloudAnimationTimer", sh::makeProperty<sh::FloatValue>(new sh::FloatValue(mCloudAnimationTimer))); /// \todo improve this mMasser->setPhase( static_cast<Moon::Phase>( (int) ((mDay % 32)/4.f)) ); mSecunda->setPhase ( static_cast<Moon::Phase>( (int) ((mDay % 32)/4.f)) ); mSecunda->setColour ( mMoonRed ? ColourValue(1.0, 0.0784, 0.0784) : ColourValue(1,1,1,1)); mMasser->setColour (ColourValue(1,1,1,1)); if (mSunEnabled) { // take 1/10 sec for fading the glare effect from invisible to full if (mGlareFade > mGlare) { mGlareFade -= duration*10; if (mGlareFade < mGlare) mGlareFade = mGlare; } else if (mGlareFade < mGlare) { mGlareFade += duration*10; if (mGlareFade > mGlare) mGlareFade = mGlare; } // increase the strength of the sun glare effect depending // on how directly the player is looking at the sun Vector3 sun = mSunGlare->getPosition(); sun = Vector3(sun.x, sun.z, -sun.y); Vector3 cam = mCamera->getRealDirection(); const Degree angle = sun.angleBetween( cam ); float val = 1- (angle.valueDegrees() / 180.f); val = (val*val*val*val)*2; mSunGlare->setSize(val * mGlareFade); } mSunGlare->setVisible(mSunEnabled); mSun->setVisible(mSunEnabled); mMasser->setVisible(mMasserEnabled); mSecunda->setVisible(mSecundaEnabled); // rotate the stars by 360 degrees every 4 days mAtmosphereNight->roll(Degree(MWBase::Environment::get().getWorld()->getTimeScaleFactor()*duration*360 / (3600*96.f))); }
void SkyManager::update(float duration) { if (!mEnabled) return; // UV Scroll the clouds mCloudMaterial->getTechnique(0)->getPass(0)->getFragmentProgramParameters()->setNamedConstantFromTime("time", MWBase::Environment::get().getWorld()->getTimeScaleFactor()/30.f); /// \todo improve this mMasser->setPhase( static_cast<Moon::Phase>( (int) ((mDay % 32)/4.f)) ); mSecunda->setPhase ( static_cast<Moon::Phase>( (int) ((mDay % 32)/4.f)) ); if (mSunEnabled) { // take 1/5 sec for fading the glare effect from invisible to full if (mGlareFade > mGlare) { mGlareFade -= duration*5; if (mGlareFade < mGlare) mGlareFade = mGlare; } else if (mGlareFade < mGlare) { mGlareFade += duration*5; if (mGlareFade > mGlare) mGlareFade = mGlare; } // increase the strength of the sun glare effect depending // on how directly the player is looking at the sun Vector3 sun = mSunGlare->getPosition(); sun = Vector3(sun.x, sun.z, -sun.y); Vector3 cam = mCamera->getRealDirection(); const Degree angle = sun.angleBetween( cam ); float val = 1- (angle.valueDegrees() / 180.f); val = (val*val*val*val)*2; mSunGlare->setSize(val * mGlareFade); } mSunGlare->setVisible(mSunEnabled); mSun->setVisible(mSunEnabled); mMasser->setVisible(mMasserEnabled); mSecunda->setVisible(mSecundaEnabled); // rotate the stars by 360 degrees every 4 days mAtmosphereNight->roll(Degree(MWBase::Environment::get().getWorld()->getTimeScaleFactor()*duration*360 / (3600*96.f))); }
void TreeLoader2D::addTree(Entity *entity, const Vector3 &position, Degree yaw, Real scale, void* userData) { //First convert the coordinate to PagedGeometry's local system #ifdef PAGEDGEOMETRY_ALTERNATE_COORDSYSTEM Vector3 pos = geom->_convertToLocal(position); #else Vector3 pos = position; #endif //Check that the tree is within bounds (DEBUG) #ifdef _DEBUG const Real smallVal = 0.01f; if (pos.x < actualBounds.left-smallVal || pos.x > actualBounds.right+smallVal || pos.z < actualBounds.top-smallVal || pos.z > actualBounds.bottom+smallVal) OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Tree position is out of bounds", "TreeLoader::addTree()"); if (scale < minimumScale || scale > maximumScale) OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Tree scale out of range", "TreeLoader::addTree()"); #endif //If the tree is slightly out of bounds (due to imprecise coordinate conversion), fix it if (pos.x < actualBounds.left) pos.x = actualBounds.left; else if (pos.x > actualBounds.right) pos.x = actualBounds.right; if (pos.z < actualBounds.top) pos.z = actualBounds.top; else if (pos.z > actualBounds.bottom) pos.z = actualBounds.bottom; Real x = pos.x; Real z = pos.z; //Find the appropriate page grid for the entity PageGridListIterator i; i = pageGridList.find(entity); std::vector<TreeDef> *pageGrid; if (i != pageGridList.end()) { //If it exists, get the page grid pageGrid = i->second; } else { //If it does not exist, create a new page grid pageGrid = new std::vector<TreeDef>[pageGridX * pageGridZ]; //Register the new page grid in the pageGridList for later retrieval pageGridList.insert(PageGridListValue(entity, pageGrid)); } //Calculate the gridbounds-relative position of the tree Real xrel = x - gridBounds.left; Real zrel = z - gridBounds.top; //Get the appropriate grid element based on the new tree's position int pageX = Math::Floor(xrel / pageSize); int pageZ = Math::Floor(zrel / pageSize); std::vector<TreeDef> &treeList = _getGridPage(pageGrid, pageX, pageZ); //Create the new tree TreeDef tree; tree.xPos = 65535 * (xrel - (pageX * pageSize)) / pageSize; tree.zPos = 65535 * (zrel - (pageZ * pageSize)) / pageSize; tree.rotation = 255 * (yaw.valueDegrees() / 360.0f); tree.scale = 255 * ((scale - minimumScale) / maximumScale); #ifdef PAGEDGEOMETRY_USER_DATA tree.userData = userData; #endif //Add it to the tree list treeList.push_back(tree); //Rebuild geometry if necessary geom->reloadGeometryPage(Vector3(x, 0, z)); }
void Turboprop::updateForces(float dt, int doUpdate) { if (doUpdate) { //tropospheric model valid up to 11.000m (33.000ft) float altitude=nodes[noderef].AbsPosition.y; //float sea_level_temperature=273.15+15.0; //in Kelvin float sea_level_pressure=101325; //in Pa //float airtemperature=sea_level_temperature-altitude*0.0065; //in Kelvin float airpressure=sea_level_pressure*pow(1.0-0.0065*altitude/288.15, 5.24947); //in Pa airdensity=airpressure*0.0000120896;//1.225 at sea level #ifdef USE_OPENAL //sound update SoundScriptManager::getSingleton().modulate(trucknum, mod_id, rpm); #endif //OPENAL } timer+=dt; //evaluate the rotation speed float velacc=0; for (int i=0; i<numblades; i++) velacc+=(nodes[nodep[i]].Velocity-nodes[noderef].Velocity).length(); rpm=(velacc/numblades) * RAD_PER_SEC_TO_RPM / radius; //check for broken prop Vector3 avg=Vector3::ZERO; for (int i=0; i<numblades; i++) avg+=nodes[nodep[i]].RelPosition; avg=avg/numblades; if ((avg-nodes[noderef].RelPosition).length()>0.4) { failed=true; } //evaluate engine power float enginepower=0; //in kilo-Watt float warmupfactor=1.0; if (warmup) { warmupfactor=(timer-warmupstart)/warmuptime; if (warmupfactor>=1.0) warmup=false; } float revpenalty=1.0; if (reverse) revpenalty=0.5; if (!failed && ignition) enginepower=(0.0575+throtle*revpenalty*0.9425)*fullpower*warmupfactor; //the magic formula float enginecouple=0.0; //in N.m if (rpm>10.0) enginecouple=9549.3*enginepower/rpm; else enginecouple=9549.3*enginepower/10.0; indicated_torque=enginecouple; if (torquenode!=-1) { Vector3 along=nodes[noderef].RelPosition-nodes[nodeback].RelPosition; Plane ppl=Plane(along, 0); Vector3 orth=ppl.projectVector(nodes[noderef].RelPosition)-ppl.projectVector(nodes[torquenode].RelPosition); Vector3 cdir=orth.crossProduct(along); cdir.normalise(); nodes[torquenode].Forces+=(enginecouple/torquedist)*cdir; } float tipforce=(enginecouple/radius)/numblades; //okay, now we know the contribution from the engine //pitch if (fixed_pitch>0) pitch=fixed_pitch; else { if (!reverse) { if (throtle<0.01) { //beta range if (pitch>0 && rpm<regspeed*1.4) pitch-=pitchspeed*dt; if (rpm>regspeed*1.4) pitch+=pitchspeed*dt; } else { float dpitch=rpm-regspeed; if (dpitch>pitchspeed) dpitch=pitchspeed; if (dpitch<-pitchspeed) dpitch=-pitchspeed; if (!(dpitch<0 && pitch<0) && !(dpitch>0 && pitch>45)) pitch+=dpitch*dt; } } else { if (rpm<regspeed*1.1) { if (pitch<-4.0) pitch+=pitchspeed*dt; else pitch-=pitchspeed*dt; } if (rpm>regspeed*1.11) { pitch-=pitchspeed*dt; } } } if (!failed) { axis=nodes[noderef].RelPosition-nodes[nodeback].RelPosition; axis.normalise(); } //estimate amount of energy float estrotenergy=0.5*numblades*nodes[nodep[0]].mass*radius*radius*(rpm/RAD_PER_SEC_TO_RPM)*(rpm/RAD_PER_SEC_TO_RPM); //for each blade float totthrust=0; float tottorque=0; for (int i=0; i<numblades; i++) { if (!failed && ignition) { Vector3 totaltipforce=Vector3::ZERO; //span vector, left to right Vector3 spanv=(nodes[nodep[i]].RelPosition-nodes[noderef].RelPosition); spanv.normalise(); //chord vector, front to back Vector3 refchordv=-axis.crossProduct(spanv); //grab this for propulsive forces Vector3 tipf=-refchordv; totaltipforce+=(tipforce-rpm/10.0)*tipf; //add a bit of mechanical friction //for each blade segment (there are 6 elements) for (int j=0; j<5; j++) //outer to inner, the 6th blade element is ignored { //proportion float proport=((float)j+0.5)/6.0; //evaluate wind direction Vector3 wind=-(nodes[nodep[i]].Velocity*(1.0-proport)+nodes[noderef].Velocity*proport); float wspeed=wind.length(); Vector3 liftv=spanv.crossProduct(-wind); liftv.normalise(); //rotate according to pitch Vector3 chordv=Quaternion(Degree(pitch+twistmap[j]-7.0), spanv)*refchordv; //wing normal Vector3 normv=chordv.crossProduct(spanv); //calculate angle of attack Vector3 pwind=Plane(Vector3::ZERO, normv, chordv).projectVector(wind); Vector3 dumb; Degree daoa; chordv.getRotationTo(pwind).ToAngleAxis(daoa, dumb); float aoa=daoa.valueDegrees(); float raoa=daoa.valueRadians(); if (dumb.dotProduct(spanv)>0) {aoa=-aoa; raoa=-raoa;}; //get airfoil data float cz, cx, cm; airfoil->getparams(aoa, 1.0, 0.0, &cz, &cx, &cm); //surface computation float s=radius*bladewidth/6.0; //drag //wforce=(8.0*cx+cx*cx/(3.14159*radius/0.4))*0.5*airdensity*wspeed*s*wind; Vector3 eforce=(4.0*cx+cx*cx/(3.14159*radius/bladewidth))*0.5*airdensity*wspeed*s*wind; //lift float lift=cz*0.5*airdensity*wspeed*wspeed*s; eforce+=lift*liftv; totthrust+=eforce.dotProduct(axis); //apply forces nodes[noderef].Forces+=eforce*proport; totaltipforce+=eforce*(1.0-proport); // if (i==0) sprintf(debug, "rend %.4i%%, wind %.3i kts, aoa %.3i, power %.5ihp, thrust %.6ilbf, torque %.6ilbft, pitch %.3i, propwash %.3i kts", (int)(100.0*wforce.dotProduct(axis)*numblades*nodes[noderef].Velocity.length()/(rpm*0.10471976*2.0*3.14159*enginecouple)), (int)(wspeed*1.9438), (int)aoa, (int)(enginepower*1.34), (int)(wforce.dotProduct(axis)*numblades*0.2248), (int)(enginecouple/1.35582), (int)pitch, (int)(propwash*1.9438)); // if (i==0) sprintf(debug, "lfx=%f lfy=%f lfz=%f vx=%f vy=%f vz=%f cx=%f cz=%f lift=%f", liftv.x, liftv.y, liftv.z, wind.x, wind.y, wind.z, cx, cz, lift); } tottorque+=tipf.dotProduct(totaltipforce)*radius; //correct amount of energy float correctfactor=0; if (rpm>100) correctfactor=(rotenergy-estrotenergy)/(numblades*radius*dt*rpm/RAD_PER_SEC_TO_RPM); if (correctfactor>1000.0) correctfactor=1000.0; if (correctfactor<-1000.0) correctfactor=-1000.0; nodes[nodep[i]].Forces+=totaltipforce+correctfactor*tipf; } else { //failed case //add drag Vector3 wind=-nodes[nodep[i]].Velocity; // determine nodes speed and divide by engines speed (with some magic numbers for tuning) to keep it rotating longer when shutoff in flight and stop after a while when plane is stopped (on the ground) float wspeed= (wind.length()/15.0f) / (nodes[noderef].Velocity.length()/2.0f); nodes[nodep[i]].Forces+=airdensity*wspeed*wind; } } //compute the next energy level rotenergy+=(double)tottorque*dt*rpm/RAD_PER_SEC_TO_RPM; // sprintf(debug, "pitch %i thrust %i totenergy=%i apparentenergy=%i", (int)pitch, (int)totthrust, (int)rotenergy, (int)estrotenergy); //prop wash float speed=nodes[noderef].Velocity.length(); float thrsign=1.0; if (totthrust<0) {thrsign=-0.1; totthrust=-totthrust;}; if (!failed) propwash=thrsign*sqrt(totthrust/(0.5*airdensity*proparea)+speed*speed)-speed; else propwash=0; if (propwash<0) propwash=0; }
void FlexAirfoil::updateForces() { if(!airfoil) return; if (broken) return; // if (innan) {LOG("STEP "+TOSTRING(innan)+" "+TOSTRING(nblu));innan++;} //evaluate wind direction Vector3 wind=-(nodes[nfld].Velocity+nodes[nfrd].Velocity)/2.0; //add wash int i; for (i=0; i<free_wash; i++) wind-=(0.5*washpropratio[i]*aeroengines[washpropnum[i]]->getpropwash())*aeroengines[washpropnum[i]]->getAxis(); float wspeed=wind.length(); //chord vector, front to back Vector3 chordv=((nodes[nbld].RelPosition-nodes[nfld].RelPosition)+(nodes[nbrd].RelPosition-nodes[nfrd].RelPosition))/2.0; float chord=chordv.length(); //span vector, left to right Vector3 spanv=((nodes[nfrd].RelPosition-nodes[nfld].RelPosition)+(nodes[nbrd].RelPosition-nodes[nbld].RelPosition))/2.0; float span=spanv.length(); //lift vector //if (_isnan(spanv.x) || _isnan(spanv.y) || _isnan(spanv.z)) LOG("spanv is NaN "+TOSTRING(nblu)); //if (_isnan(wind.x) || _isnan(wind.y) || _isnan(wind.z)) LOG("wind is NaN "+TOSTRING(nblu)); Vector3 liftv=spanv.crossProduct(-wind); //if (_isnan(liftv.x) || _isnan(liftv.y) || _isnan(liftv.z)) LOG("liftv0 is NaN "+TOSTRING(nblu)); //if (_isnan(liftv.x) || _isnan(liftv.y) || _isnan(liftv.z)) LOG("liftv1 is NaN "+TOSTRING(nblu)); //wing normal float s=span*chord; Vector3 normv=chordv.crossProduct(spanv); normv.normalise(); //calculate angle of attack Vector3 pwind; pwind=Plane(Vector3::ZERO, normv, chordv).projectVector(-wind); Vector3 dumb; Degree daoa; chordv.getRotationTo(-pwind).ToAngleAxis(daoa, dumb); aoa=daoa.valueDegrees(); float raoa=daoa.valueRadians(); if (dumb.dotProduct(spanv)>0) {aoa=-aoa; raoa=-raoa;}; //if (_isnan(aoa)) LOG("aoa is NaN "+TOSTRING(nblu)); //get airfoil data float cz, cx, cm; if (isstabilator) airfoil->getparams(aoa-deflection, chordratio, 0, &cz, &cx, &cm); else airfoil->getparams(aoa, chordratio, deflection, &cz, &cx, &cm); //compute surface //if (_isnan(cz)) LOG("cz is NaN "+TOSTRING(nblu)); //float fs=span*(fabs(thickness*cos(raoa))+fabs(chord*sin(raoa))); //float ts=span*(fabs(chord*cos(raoa))+fabs(thickness*sin(raoa))); //tropospheric model valid up to 11.000m (33.000ft) float altitude=nodes[nfld].AbsPosition.y; //float sea_level_temperature=273.15+15.0; //in Kelvin (not used) float sea_level_pressure=101325; //in Pa //float airtemperature=sea_level_temperature-altitude*0.0065; //in Kelvin (not used) float airpressure=sea_level_pressure*approx_pow(1.0-0.0065*altitude/288.15, 5.24947); //in Pa float airdensity=airpressure*0.0000120896;//1.225 at sea level Vector3 wforce=Vector3::ZERO; //drag wforce=(cx*0.5*airdensity*wspeed*s)*wind; //if (_isnan(wforce.x) || _isnan(wforce.y) || _isnan(wforce.z)) LOG("wforce1 is NaN "+TOSTRING(nblu)); //induced drag if (useInducedDrag) { Vector3 idf=(cx*cx*0.25*airdensity*wspeed*idArea*idArea/(3.14159*idSpan*idSpan))*wind; //if (_isnan(idf.length())) LOG("idf is NaN "+TOSTRING(nblu)); if (idLeft) { nodes[nblu].Forces+=idf; nodes[nbld].Forces+=idf; } else { nodes[nbru].Forces+=idf; nodes[nbrd].Forces+=idf; } } //if (_isnan(wforce.x) || _isnan(wforce.y) || _isnan(wforce.z)) LOG("wforce1a is NaN "+TOSTRING(nblu)); //if (_isnan(cz)) LOG("cz is NaN "+TOSTRING(nblu)); //if (_isnan(wspeed)) LOG("wspeed is NaN "+TOSTRING(nblu)); //if (_isnan(airdensity)) LOG("airdensity is NaN "+TOSTRING(nblu)); //if (_isnan(s)) LOG("s is NaN "+TOSTRING(nblu)); //if (_isnan(liftv.x) || _isnan(liftv.y) || _isnan(liftv.z)) LOG("liftv is NaN "+TOSTRING(nblu)); //lift wforce+=(cz*0.5*airdensity*wspeed*chord)*liftv; /*if (_isnan(wforce.x) || _isnan(wforce.y) || _isnan(wforce.z)) { if (innan==0) innan=1; LOG("wforce2 is NaN "+TOSTRING(nblu)); } */ //moment float moment=-cm*0.5*airdensity*wspeed*wspeed*s;//*chord; //apply forces Vector3 f1=wforce*(liftcoef * 0.75/4.0f)+normv*(liftcoef *moment/(4.0f*0.25f)); Vector3 f2=wforce*(liftcoef *0.25/4.0f)-normv*(liftcoef *moment/(4.0f*0.75f)); //focal at 0.25 chord nodes[nfld].Forces+=f1; nodes[nflu].Forces+=f1; nodes[nfrd].Forces+=f1; nodes[nfru].Forces+=f1; nodes[nbld].Forces+=f2; nodes[nblu].Forces+=f2; nodes[nbrd].Forces+=f2; nodes[nbru].Forces+=f2; // sprintf(debug, "wind %i kts, aoa %i, cz %f, vf %f ", (int)(wspeed*1.9438), (int)aoa, cz, normv.y); }
void LandVehicleSimulation::UpdateVehicle(Beam* curr_truck, float seconds_since_last_frame) { using namespace Ogre; if (!curr_truck->replaymode) { if (RoR::Application::GetInputEngine()->getEventBoolValueBounce(EV_TRUCK_LEFT_MIRROR_LEFT)) curr_truck->leftMirrorAngle-=0.001; if (RoR::Application::GetInputEngine()->getEventBoolValueBounce(EV_TRUCK_LEFT_MIRROR_RIGHT)) curr_truck->leftMirrorAngle+=0.001; if (RoR::Application::GetInputEngine()->getEventBoolValueBounce(EV_TRUCK_RIGHT_MIRROR_LEFT)) curr_truck->rightMirrorAngle-=0.001; if (RoR::Application::GetInputEngine()->getEventBoolValueBounce(EV_TRUCK_RIGHT_MIRROR_RIGHT)) curr_truck->rightMirrorAngle+=0.001; } // end of (!curr_truck->replaymode) block #ifdef USE_ANGELSCRIPT if (!curr_truck->replaymode && !curr_truck->vehicle_ai->IsActive()) #else if (!curr_truck->replaymode) #endif // USE_ANGELSCRIPT { // steering float tmp_left_digital = RoR::Application::GetInputEngine()->getEventValue(EV_TRUCK_STEER_LEFT, false, InputEngine::ET_DIGITAL); float tmp_right_digital = RoR::Application::GetInputEngine()->getEventValue(EV_TRUCK_STEER_RIGHT, false, InputEngine::ET_DIGITAL); float tmp_left_analog = RoR::Application::GetInputEngine()->getEventValue(EV_TRUCK_STEER_LEFT, false, InputEngine::ET_ANALOG); float tmp_right_analog = RoR::Application::GetInputEngine()->getEventValue(EV_TRUCK_STEER_RIGHT, false, InputEngine::ET_ANALOG); float sum = -std::max(tmp_left_digital,tmp_left_analog)+ std::max(tmp_right_digital,tmp_right_analog); if (sum < -1) sum = -1; if (sum > 1) sum = 1; curr_truck->hydrodircommand = sum; if ((tmp_left_digital < tmp_left_analog) || (tmp_right_digital < tmp_right_analog)) { curr_truck->hydroSpeedCoupling = false; } else { curr_truck->hydroSpeedCoupling = true; } if (curr_truck->engine) { static bool arcadeControls = BSETTING("ArcadeControls", false); float accl = RoR::Application::GetInputEngine()->getEventValue(EV_TRUCK_ACCELERATE); float brake = RoR::Application::GetInputEngine()->getEventValue(EV_TRUCK_BRAKE); if (RoR::Application::GetInputEngine()->getEventValue(EV_TRUCK_ACCELERATE_MODIFIER_25) || RoR::Application::GetInputEngine()->getEventValue(EV_TRUCK_ACCELERATE_MODIFIER_50)) { float acclModifier = 0.0f; if (RoR::Application::GetInputEngine()->getEventValue(EV_TRUCK_ACCELERATE_MODIFIER_25)) { acclModifier += 0.25f; } if (RoR::Application::GetInputEngine()->getEventValue(EV_TRUCK_ACCELERATE_MODIFIER_50)) { acclModifier += 0.50f; } accl *= acclModifier; } if (RoR::Application::GetInputEngine()->getEventValue(EV_TRUCK_BRAKE_MODIFIER_25) || RoR::Application::GetInputEngine()->getEventValue(EV_TRUCK_BRAKE_MODIFIER_50)) { float brakeModifier = 0.0f; if (RoR::Application::GetInputEngine()->getEventValue(EV_TRUCK_BRAKE_MODIFIER_25)) { brakeModifier += 0.25f; } if (RoR::Application::GetInputEngine()->getEventValue(EV_TRUCK_BRAKE_MODIFIER_50)) { brakeModifier += 0.50f; } brake *= brakeModifier; } // arcade controls are only working with auto-clutch! if (!arcadeControls || curr_truck->engine->getAutoMode() > BeamEngine::SEMIAUTO) { // classic mode, realistic curr_truck->engine->autoSetAcc(accl); curr_truck->brake = brake * curr_truck->brakeforce; } else { // start engine if (curr_truck->engine->hasContact() && !curr_truck->engine->isRunning() && (accl > 0 || brake > 0)) { curr_truck->engine->start(); } // arcade controls: hey - people wanted it x| ... <- and it's convenient if (curr_truck->engine->getGear() >= 0) { // neutral or drive forward, everything is as its used to be: brake is brake and accel. is accel. curr_truck->engine->autoSetAcc(accl); curr_truck->brake = brake * curr_truck->brakeforce; } else { // reverse gear, reverse controls: brake is accel. and accel. is brake. curr_truck->engine->autoSetAcc(brake); curr_truck->brake = accl * curr_truck->brakeforce; } // only when the truck really is not moving anymore if (fabs(curr_truck->WheelSpeed) <= 1.0f) { Vector3 hdir = curr_truck->getDirection(); float velocity = hdir.dotProduct(curr_truck->nodes[0].Velocity); // switching point, does the user want to drive forward from backward or the other way round? change gears? if (velocity < 1.0f && brake > 0.5f && accl < 0.5f && curr_truck->engine->getGear() > 0) { // we are on the brake, jump to reverse gear if (curr_truck->engine->getAutoMode() == BeamEngine::AUTOMATIC) { curr_truck->engine->autoShiftSet(BeamEngine::REAR); } else { curr_truck->engine->setGear(-1); } } else if (velocity > -1.0f && brake < 0.5f && accl > 0.5f && curr_truck->engine->getGear() < 0) { // we are on the gas pedal, jump to first gear when we were in rear gear if (curr_truck->engine->getAutoMode() == BeamEngine::AUTOMATIC) { curr_truck->engine->autoShiftSet(BeamEngine::DRIVE); } else { curr_truck->engine->setGear(1); } } } } // IMI // gear management -- it might, should be transferred to a standalone function of Beam or RoRFrameListener if (curr_truck->engine->getAutoMode() == BeamEngine::AUTOMATIC) { if (RoR::Application::GetInputEngine()->getEventBoolValueBounce(EV_TRUCK_AUTOSHIFT_UP)) { curr_truck->engine->autoShiftUp(); } if (RoR::Application::GetInputEngine()->getEventBoolValueBounce(EV_TRUCK_AUTOSHIFT_DOWN)) { curr_truck->engine->autoShiftDown(); } } if (RoR::Application::GetInputEngine()->getEventBoolValueBounce(EV_TRUCK_TOGGLE_CONTACT)) { curr_truck->engine->toggleContact(); } if (RoR::Application::GetInputEngine()->getEventBoolValue(EV_TRUCK_STARTER) && curr_truck->engine->hasContact() && !curr_truck->engine->isRunning()) { // starter curr_truck->engine->setstarter(1); #ifdef USE_OPENAL SoundScriptManager::getSingleton().trigStart(curr_truck, SS_TRIG_STARTER); #endif // OPENAL } else { curr_truck->engine->setstarter(0); #ifdef USE_OPENAL SoundScriptManager::getSingleton().trigStop(curr_truck, SS_TRIG_STARTER); #endif // OPENAL } if (RoR::Application::GetInputEngine()->getEventBoolValueBounce(EV_TRUCK_SWITCH_SHIFT_MODES)) { // toggle Auto shift curr_truck->engine->toggleAutoMode(); // force gui update curr_truck->triggerGUIFeaturesChanged(); #ifdef USE_MYGUI switch(curr_truck->engine->getAutoMode()) { case BeamEngine::AUTOMATIC: RoR::Application::GetConsole()->putMessage(Console::CONSOLE_MSGTYPE_INFO, Console::CONSOLE_SYSTEM_NOTICE, _L("Automatic shift"), "cog.png", 3000); RoR::Application::GetGuiManager()->PushNotification("Gearbox Mode:", "Automatic shift"); break; case BeamEngine::SEMIAUTO: RoR::Application::GetConsole()->putMessage(Console::CONSOLE_MSGTYPE_INFO, Console::CONSOLE_SYSTEM_NOTICE, _L("Manual shift - Auto clutch"), "cog.png", 3000); RoR::Application::GetGuiManager()->PushNotification("Gearbox Mode:", "Manual shift - Auto clutch"); break; case BeamEngine::MANUAL: RoR::Application::GetConsole()->putMessage(Console::CONSOLE_MSGTYPE_INFO, Console::CONSOLE_SYSTEM_NOTICE, _L("Fully Manual: sequential shift"), "cog.png", 3000); RoR::Application::GetGuiManager()->PushNotification("Gearbox Mode:", "Fully Manual: sequential shift"); break; case BeamEngine::MANUAL_STICK: RoR::Application::GetConsole()->putMessage(Console::CONSOLE_MSGTYPE_INFO, Console::CONSOLE_SYSTEM_NOTICE, _L("Fully manual: stick shift"), "cog.png", 3000); RoR::Application::GetGuiManager()->PushNotification("Gearbox Mode:", "Fully manual: stick shift"); break; case BeamEngine::MANUAL_RANGES: RoR::Application::GetConsole()->putMessage(Console::CONSOLE_MSGTYPE_INFO, Console::CONSOLE_SYSTEM_NOTICE, _L("Fully Manual: stick shift with ranges"), "cog.png", 3000); RoR::Application::GetGuiManager()->PushNotification("Gearbox Mode:", "Fully Manual: stick shift with ranges"); break; } #endif //USE_MYGUI } // joy clutch float cval = RoR::Application::GetInputEngine()->getEventValue(EV_TRUCK_MANUAL_CLUTCH); curr_truck->engine->setManualClutch(cval); int shiftmode = curr_truck->engine->getAutoMode(); if (shiftmode <= BeamEngine::MANUAL) // auto, semi auto and sequential shifting { if (RoR::Application::GetInputEngine()->getEventBoolValueBounce(EV_TRUCK_SHIFT_UP)) { curr_truck->engine->shift(1); } else if (RoR::Application::GetInputEngine()->getEventBoolValueBounce(EV_TRUCK_SHIFT_DOWN)) { if (shiftmode > BeamEngine::SEMIAUTO || shiftmode == BeamEngine::SEMIAUTO && !arcadeControls || shiftmode == BeamEngine::SEMIAUTO && curr_truck->engine->getGear() > 0 || shiftmode == BeamEngine::AUTOMATIC) { curr_truck->engine->shift(-1); } } else if (shiftmode != BeamEngine::AUTOMATIC && RoR::Application::GetInputEngine()->getEventBoolValueBounce(EV_TRUCK_SHIFT_NEUTRAL)) { curr_truck->engine->shiftTo(0); } } else //if (shiftmode > BeamEngine::MANUAL) // h-shift or h-shift with ranges shifting { bool gear_changed = false; bool found = false; int curgear = curr_truck->engine->getGear(); int curgearrange = curr_truck->engine->getGearRange(); int gearoffset = std::max(0, curgear - curgearrange * 6); // one can select range only if in neutral if (shiftmode==BeamEngine::MANUAL_RANGES && curgear == 0) { // maybe this should not be here, but should experiment if (RoR::Application::GetInputEngine()->getEventBoolValueBounce(EV_TRUCK_SHIFT_LOWRANGE) && curgearrange != 0) { curr_truck->engine->setGearRange(0); gear_changed = true; #ifdef USE_MYGUI RoR::Application::GetConsole()->putMessage(Console::CONSOLE_MSGTYPE_INFO, Console::CONSOLE_SYSTEM_NOTICE, _L("Low range selected"), "cog.png", 3000); #endif //USE_MYGUI } else if (RoR::Application::GetInputEngine()->getEventBoolValueBounce(EV_TRUCK_SHIFT_MIDRANGE) && curgearrange != 1 && curr_truck->engine->getNumGearsRanges()>1) { curr_truck->engine->setGearRange(1); gear_changed = true; #ifdef USE_MYGUI RoR::Application::GetConsole()->putMessage(Console::CONSOLE_MSGTYPE_INFO, Console::CONSOLE_SYSTEM_NOTICE, _L("Mid range selected"), "cog.png", 3000); #endif //USE_MYGUI } else if (RoR::Application::GetInputEngine()->getEventBoolValueBounce(EV_TRUCK_SHIFT_HIGHRANGE) && curgearrange != 2 && curr_truck->engine->getNumGearsRanges()>2) { curr_truck->engine->setGearRange(2); gear_changed = true; #ifdef USE_MYGUI RoR::Application::GetConsole()->putMessage(Console::CONSOLE_MSGTYPE_INFO, Console::CONSOLE_SYSTEM_NOTICE, _L("High range selected"), "cog.png", 3000); #endif // USE_MYGUI } } //zaxxon if (curgear == -1) { gear_changed = !RoR::Application::GetInputEngine()->getEventBoolValue(EV_TRUCK_SHIFT_GEAR_REVERSE); } else if (curgear > 0 && curgear < 19) { if (shiftmode==BeamEngine::MANUAL) { gear_changed = !RoR::Application::GetInputEngine()->getEventBoolValue(EV_TRUCK_SHIFT_GEAR01 + curgear -1); } else { gear_changed = !RoR::Application::GetInputEngine()->getEventBoolValue(EV_TRUCK_SHIFT_GEAR01 + gearoffset-1); // range mode } } if (gear_changed || curgear == 0) { if (RoR::Application::GetInputEngine()->getEventBoolValue(EV_TRUCK_SHIFT_GEAR_REVERSE)) { curr_truck->engine->shiftTo(-1); found = true; } else if (RoR::Application::GetInputEngine()->getEventBoolValue(EV_TRUCK_SHIFT_NEUTRAL)) { curr_truck->engine->shiftTo(0); found = true; } else { if (shiftmode == BeamEngine::MANUAL_STICK) { for (int i=1; i < 19 && !found; i++) { if (RoR::Application::GetInputEngine()->getEventBoolValue(EV_TRUCK_SHIFT_GEAR01 + i - 1)) { curr_truck->engine->shiftTo(i); found = true; } } } else // BeamEngine::MANUALMANUAL_RANGES { for (int i=1; i < 7 && !found; i++) { if (RoR::Application::GetInputEngine()->getEventBoolValue(EV_TRUCK_SHIFT_GEAR01 + i - 1)) { curr_truck->engine->shiftTo(i + curgearrange * 6); found = true; } } } } if (!found) { curr_truck->engine->shiftTo(0); } } // end of if (gear_changed) } // end of shitmode > BeamEngine::MANUAL if (curr_truck->engine->hasContact() && curr_truck->engine->getAutoMode() == BeamEngine::AUTOMATIC && curr_truck->engine->getAutoShift() != BeamEngine::NEUTRAL && std::abs(curr_truck->WheelSpeed) < 0.1f) { Vector3 dirDiff = curr_truck->getDirection(); Degree pitchAngle = Radian(asin(dirDiff.dotProduct(Vector3::UNIT_Y))); if (std::abs(pitchAngle.valueDegrees()) > 1.0f) { if (curr_truck->engine->getAutoShift() > BeamEngine::NEUTRAL && curr_truck->WheelSpeed < +0.1f && pitchAngle.valueDegrees() > +1.0f || curr_truck->engine->getAutoShift() < BeamEngine::NEUTRAL && curr_truck->WheelSpeed > -0.1f && pitchAngle.valueDegrees() < -1.0f) { // anti roll back in BeamEngine::AUTOMATIC (DRIVE, TWO, ONE) mode // anti roll forth in BeamEngine::AUTOMATIC (REAR) mode float downhill_force = std::abs(sin(pitchAngle.valueRadians()) * curr_truck->getTotalMass()); float engine_force = std::abs(curr_truck->engine->getTorque()); float ratio = std::max(0.0f, 1.0f - (engine_force / downhill_force) / 2.0f); curr_truck->brake = curr_truck->brakeforce * sqrt(ratio); } } else if (brake == 0.0f && accl == 0.0f && curr_truck->parkingbrake == 0) { float ratio = std::max(0.0f, 0.1f - std::abs(curr_truck->WheelSpeed)) * 5.0f; curr_truck->brake = curr_truck->brakeforce * ratio; } } } // end of ->engine #ifdef USE_OPENAL if (curr_truck->brake > curr_truck->brakeforce / 6.0f) { SoundScriptManager::getSingleton().trigStart(curr_truck, SS_TRIG_BRAKE); } else { SoundScriptManager::getSingleton().trigStop(curr_truck, SS_TRIG_BRAKE); } #endif // USE_OPENAL } // end of ->replaymode if (RoR::Application::GetInputEngine()->getEventBoolValueBounce(EV_TRUCK_TOGGLE_AXLE_LOCK)) { // toggle auto shift if (!curr_truck->getAxleLockCount()) { #ifdef USE_MYGUI RoR::Application::GetConsole()->putMessage(Console::CONSOLE_MSGTYPE_INFO, Console::CONSOLE_SYSTEM_NOTICE, _L("No differential installed on current vehicle!"), "warning.png", 3000); RoR::Application::GetGuiManager()->PushNotification("Differential:", "No differential installed on current vehicle!"); #endif // USE_MYGUI } else { curr_truck->toggleAxleLock(); #ifdef USE_MYGUI RoR::Application::GetConsole()->putMessage(Console::CONSOLE_MSGTYPE_INFO, Console::CONSOLE_SYSTEM_NOTICE, _L("Differentials switched to: ") + curr_truck->getAxleLockName(), "cog.png", 3000); RoR::Application::GetGuiManager()->PushNotification("Differential:", "Differentials switched to: " + curr_truck->getAxleLockName()); #endif // USE_MYGUI } } #ifdef USE_OPENAL if (curr_truck->ispolice) { if (RoR::Application::GetInputEngine()->getEventBoolValueBounce(EV_TRUCK_HORN)) { SoundScriptManager::getSingleton().trigToggle(curr_truck, SS_TRIG_HORN); } } else { if (RoR::Application::GetInputEngine()->getEventBoolValue(EV_TRUCK_HORN) && !curr_truck->replaymode) { SoundScriptManager::getSingleton().trigStart(curr_truck, SS_TRIG_HORN); } else { SoundScriptManager::getSingleton().trigStop(curr_truck, SS_TRIG_HORN); } } #endif // OPENAL if (RoR::Application::GetInputEngine()->getEventBoolValueBounce(EV_TRUCK_PARKING_BRAKE)) { curr_truck->parkingbrakeToggle(); } if (RoR::Application::GetInputEngine()->getEventBoolValueBounce(EV_TRUCK_ANTILOCK_BRAKE)) { if (curr_truck->alb_present && !curr_truck->alb_notoggle) { curr_truck->antilockbrakeToggle(); } } if (RoR::Application::GetInputEngine()->getEventBoolValueBounce(EV_TRUCK_TRACTION_CONTROL)) { if (!curr_truck->tc_notoggle) curr_truck->tractioncontrolToggle(); } if (RoR::Application::GetInputEngine()->getEventBoolValueBounce(EV_TRUCK_CRUISE_CONTROL)) { curr_truck->cruisecontrolToggle(); } if (curr_truck->cc_mode) { LandVehicleSimulation::UpdateCruiseControl(curr_truck, seconds_since_last_frame); } LandVehicleSimulation::CheckSpeedLimit(curr_truck, seconds_since_last_frame); }
tAction TeacherFollowTheLineLineRoom::computeNextAction() { // Determine if a change of state is possible if (state == STATE_FORWARD_1) { if (target.x < 0) { target.x = m_pMap->properties.get("spot1_x")->toInt(); target.y = m_pMap->properties.get("spot1_y")->toInt(); } else { if ((m_robot_position.x >= target.x - 1) && (m_robot_position.x <= target.x + 1) && (m_robot_position.y >= target.y - 1) && (m_robot_position.y <= target.y + 1)) { target.x = m_pMap->properties.get("spot2_x")->toInt(); target.y = m_pMap->properties.get("spot2_y")->toInt(); state = STATE_FORWARD_2; } } } else if (state == STATE_FORWARD_2) { if ((m_robot_position.x >= target.x - 1) && (m_robot_position.x <= target.x + 1) && (m_robot_position.y >= target.y - 1) && (m_robot_position.y <= target.y + 1)) { target.x = -1; target.y = -1; state = STATE_LOOK_FOR_FLAG; } } else if (state == STATE_LOOK_FOR_FLAG) { if (!m_detected_targets.empty()) { target = m_detected_targets[0]; state = STATE_GO_TOWARD_FLAG; } } // Select the action to perform if (state == STATE_LOOK_FOR_FLAG) { if (m_pMap->properties.get("haxis")->toBool()) return ACTION_TURN_RIGHT; else return ACTION_TURN_LEFT; } else if (target.x >= 0) { Degree angle = getAngleToTarget(target); if (angle.valueDegrees() >= 3.0f) return ACTION_TURN_RIGHT; else if (angle.valueDegrees() <= -3.0f) return ACTION_TURN_LEFT; else return ACTION_GO_FORWARD; } return ACTION_TURN_LEFT; }
String toString(Degree val, unsigned short precision, unsigned short width, char fill, std::ios::fmtflags flags) { return toString(val.valueDegrees(), precision, width, fill, flags); }
void SGModel::updateBone(int64_t time, ObjectPtr skeleton) { BonePtr bone = smart_pointer_cast<Bone>(skeleton); ActionDataPtr actionData = smart_pointer_cast<ActionData>(mCurActionData); KeyFrameDataPtr kf1, kf2; // 平移变换数据 Vector3 translation; auto itrT = actionData->mBonesTranslation.find(bone->getName()); if (itrT != actionData->mBonesTranslation.end()) { ActionData::KeyFrames &keyframesT = itrT->second; if (searchKeyframe(keyframesT, time, actionData->mDuration, mCurKeyFrameT, kf1, kf2, mIsLoop)) { KeyFrameDataTPtr keyframe1 = smart_pointer_cast<KeyFrameDataT>(kf1); KeyFrameDataTPtr keyframe2 = smart_pointer_cast<KeyFrameDataT>(kf2); double t = double(time - keyframe1->mTimestamp) / double(keyframe2->mTimestamp - keyframe1->mTimestamp); Vector3 &base = keyframe1->mTranslation; translation = (base + (keyframe2->mTranslation - base) * t); T3D_LOG_INFO("Keyframe #1 T(%f, %f, %f)", keyframe1->mTranslation[0], keyframe1->mTranslation[1], keyframe1->mTranslation[2]); T3D_LOG_INFO("Keyframe #2 T(%f, %f, %f)", keyframe2->mTranslation[0], keyframe2->mTranslation[1], keyframe2->mTranslation[2]); T3D_LOG_INFO("Bone : %s [%f], T(%f, %f, %f)", bone->getName().c_str(), t, translation[0], translation[1], translation[2]); bone->setTranslation(translation); } } // 旋转变换数据 Quaternion orientation; auto itrR = actionData->mBonesRotation.find(bone->getName()); if (itrR != actionData->mBonesRotation.end()) { ActionData::KeyFrames &keyframesR = itrR->second; if (searchKeyframe(keyframesR, time, actionData->mDuration, mCurKeyFrameR, kf1, kf2, mIsLoop)) { KeyFrameDataRPtr keyframe1 = smart_pointer_cast<KeyFrameDataR>(kf1); KeyFrameDataRPtr keyframe2 = smart_pointer_cast<KeyFrameDataR>(kf2); double t = double(time - keyframe1->mTimestamp) / double(keyframe2->mTimestamp - keyframe1->mTimestamp); orientation.lerp(keyframe1->mOrientation, keyframe2->mOrientation, t/* / 1000*/); T3D_LOG_INFO("Keyframe #1 R(%f, %f, %f, %f)", keyframe1->mOrientation[0], keyframe1->mOrientation[1], keyframe1->mOrientation[2], keyframe1->mOrientation[3]); T3D_LOG_INFO("Keyframe #2 R(%f, %f, %f, %f)", keyframe2->mOrientation[0], keyframe2->mOrientation[1], keyframe2->mOrientation[2], keyframe2->mOrientation[3]); Degree deg; Vector3 axis; orientation.toAngleAxis(deg, axis); T3D_LOG_INFO("Bone : %s [%d], R(%f, %f, %f, %f), deg=%f, Axis(%f, %f, %f)", bone->getName().c_str(), time, orientation[0], orientation[1], orientation[2], orientation[3], deg.valueDegrees(), axis[0], axis[1], axis[2]); bone->setOrientation(orientation); } } // 缩放变换数据 Vector3 scaling; auto itrS = actionData->mBonesScaling.find(bone->getName()); if (itrS != actionData->mBonesScaling.end()) { ActionData::KeyFrames &keyframesS = itrS->second; if (searchKeyframe(keyframesS, time, actionData->mDuration, mCurKeyFrameS, kf1, kf2, mIsLoop)) { KeyFrameDataSPtr keyframe1 = smart_pointer_cast<KeyFrameDataS>(kf1); KeyFrameDataSPtr keyframe2 = smart_pointer_cast<KeyFrameDataS>(kf2); double t = double(time - keyframe1->mTimestamp) / double(keyframe2->mTimestamp - keyframe1->mTimestamp); Vector3 &base = keyframe1->mScaling; scaling = (base * (keyframe2->mScaling - base) * t); T3D_LOG_INFO("Keyframe #1 S(%f, %f, %f)", keyframe1->mScaling[0], keyframe1->mScaling[1], keyframe1->mScaling[2]); T3D_LOG_INFO("Keyframe #2 S(%f, %f, %f)", keyframe2->mScaling[0], keyframe2->mScaling[1], keyframe2->mScaling[2]); T3D_LOG_INFO("Bone : %s [%f], S(%f, %f, %f)", bone->getName().c_str(), t, scaling[0], scaling[1], scaling[2]); bone->setScaling(scaling); } } bone->updateBone(); auto itr = bone->getChildren().begin(); while (itr != bone->getChildren().end()) { updateBone(time, *itr); ++itr; } }
bool StepRecognitionMovement::run(Ogre::Real elapsedTime, Ogre::Vector3 direction, Ogre::Vector3 rotation) { Vector3 vel = mMovingCreature->getCreature()->getActor()->getPhysicalThing()->getVelocity(); Real velY = vel.y; vel.y = 0; // raycast in the direction we should move to Vector3 globalDir = mMovingCreature->getCreature()->getOrientation() * direction; // the direction in global space if( globalDir == Vector3::ZERO ) return true; // the materials that are triggered here PhysicsMaterialRaycast::MaterialVector materialVector; materialVector.push_back(PhysicsManager::getSingleton().getMaterialID("character")); // should we perhaps only use level here? materialVector.push_back(PhysicsManager::getSingleton().getMaterialID("camera")); // first of all check if we are not standing in front of a wall or sth like this PhysicalThing *thing = mMovingCreature->getCreature()->getActor()->getPhysicalThing(); Real height = thing->_getBody()->getCollision()->getAABB().getSize().y; Vector3 start = mMovingCreature->getCreature()->getPosition() + Vector3(0,height/2,0); Vector3 end = start + globalDir * 0.5; RaycastInfo info; info = mRaycast.execute( PhysicsManager::getSingleton()._getNewtonWorld(), &materialVector, start, end, true); if(info.mBody) { mMoveToNextTarget = false; return false; } if( !mMoveToNextTarget ) // check if we need to move up for a step { Real raylen = vel.length() / 3; // use longer ray, if higher velocity if ( raylen < 0.5 ) raylen = 0.4; //std::ostringstream oss; //oss << "StepRecognition Raylen: " << raylen; //LOG_MESSAGE(Logger::RULES, oss.str()); // raycasts Vector3 start = mMovingCreature->getCreature()->getPosition() + Vector3::UNIT_Y * 0.1f; globalDir.y = 0; globalDir.normalise(); Vector3 end = start + globalDir*raylen; bool foundbody = false; Real foundDistance = 0; RaycastInfo info; do { info = mRaycast.execute( PhysicsManager::getSingleton()._getNewtonWorld(), &materialVector, start, end, true); // do we need to check bodies left and right of this ray? (step width?) // already found nearer body if( foundbody ) { if( info.mBody && (info.mDistance*raylen >= foundDistance*raylen + 0.19) || // step deep enough !info.mBody ) { // found a step mMoveToNextTarget = true; mNextTarget = start + globalDir*raylen*foundDistance + 0.1 * globalDir; std::ostringstream oss; Vector3 stepInLocalCoords = mNextTarget - mMovingCreature->getCreature()->getPosition(); Quaternion ori = mMovingCreature->getCreature()->getOrientation(); stepInLocalCoords = ori.Inverse() * stepInLocalCoords; oss << "Step-Recognition: Next Step: " << stepInLocalCoords; LOG_MESSAGE(Logger::RULES, oss.str()); break; } } if( info.mBody ) { foundbody = true; foundDistance = info.mDistance; } start += Vector3::UNIT_Y * 0.05f; end += Vector3::UNIT_Y * 0.05f; } while( info.mBody && (start - mMovingCreature->getCreature()->getPosition()).y <= 0.5 ); } // check if the target is still needed // perform check also to verify found step if( mMoveToNextTarget ) { Vector3 diffToTarget = mNextTarget - mMovingCreature->getCreature()->getPosition(); Real diffToTargetY = diffToTarget.y; diffToTarget.y = 0; // different direction Vector3 globalDir = mMovingCreature->getCreature()->getOrientation() * direction; // the direction in global space globalDir.y = 0; if( globalDir == Vector3::ZERO ) { mMoveToNextTarget = false; LOG_MESSAGE(Logger::RULES, "Testing Step-Recognition: Step direction null"); return false; } // target reached if( diffToTarget.squaredLength() < 0.01) { mMoveToNextTarget = false; LOG_MESSAGE(Logger::RULES, "Testing Step-Recognition: Step reached"); return false; } // different direction Quaternion oriDiff = diffToTarget.getRotationTo(globalDir, Vector3::UNIT_Y); Degree angleDiff; Vector3 axis = Vector3::UNIT_Y; oriDiff.ToAngleAxis(angleDiff, axis); Real f = angleDiff.valueDegrees(); //std::ostringstream oss; //oss << "Step-Recognition: angle: " << f << " axis: " << axis; //LOG_MESSAGE(Logger::RULES, oss.str()); //if( !diffToTarget.directionEquals(globalDir, Degree(15)) ) if( f > 2.0f ) { mMoveToNextTarget = false; //LOG_MESSAGE(Logger::RULES, "Testing Step-Recognition: Step direction wrong"); return false; } // already above target, but slow velocity if( diffToTargetY < 0 && fabs(velY) < 0.01 ) { mMoveToNextTarget = false; //LOG_MESSAGE(Logger::RULES, "Testing Step-Recognition: slow and abov target-height!"); return false; } } return mMoveToNextTarget; }