void PointArrayParticleSystem::setParticleVelocity(Vector& vel, const Vector& dir, float speed, const GenParticleSystemEditables& eds) { if(m_parray.get()==NULL) return; bool forceDirection = !use_explosion && (eds.launchDirectionType == GenParticleSystemEditables::DIRECTION_EXPLOSION || eds.launchDirectionType == GenParticleSystemEditables::DIRECTION_NEGATIVE_EXPLOSION); if(m_eds->useNormalsAsDirection || forceDirection) { if(m_eds->useBinormalsAsDirection) { //VC3 up = VC3(0,1,0); VC3 up = VC3((rand() % 1000) / 1000.0f, (rand() % 1000) / 1000.0f, (rand() % 1000) / 1000.0f); VC3 binormal = up.GetCrossWith(m_parray->normals[m_index]); vel = binormal * speed; m_rotation.RotateVector(vel); } else { vel = m_parray->normals[m_index] * speed; m_rotation.RotateVector(vel); } } else vel = dir * speed; }
void ClawUnitActor::actDirectClawControls(Unit *unit) { int weapTypeNum = 0; static int rotating = 0; static bool claw_near = true; UnitType *unitType = unit->getUnitType(); if (rotating) rotating--; // For longer claw -> 5.5, 5.0 const game::ControlSettings &controlSettings = game->getClawController()->getControlSettings(); if(game->getClawController()->hasActor()) { if(game->getClawController()->getTargetPosition(TARGET_ADVANCE_TICKS).GetRangeTo(unit->getPosition()) > controlSettings.animationSwitchFarPoseRange) claw_near = false; if(game->getClawController()->getTargetPosition(TARGET_ADVANCE_TICKS).GetRangeTo(unit->getPosition()) < controlSettings.animationSwitchNearPoseRange && !rotating) claw_near = true; } else { if(game->getClawController()->getTargetPosition(TARGET_ADVANCE_TICKS).GetRangeTo(unit->getPosition()) > controlSettings.animationSwitchFarPoseRange) claw_near = false; if(game->getClawController()->getTargetPosition(TARGET_ADVANCE_TICKS).GetRangeTo(unit->getPosition()) < controlSettings.animationSwitchNearPoseRange && !rotating) claw_near = true; } //bool sprint_key = game->gameUI->isLocalPlayerDirectControlOn(DIRECT_CTRL_SPRINT, unit); bool sprint = false; // TODO: ask the clawcontroller if we should sprint - if claw (= pad aiming/mouse) is not moving? // if sprint key is pressed, then force the claw not to move static int thefoocounter = 0; if (!game->getClawController()->hasActor() && !game->getClawController()->isClawMoving()) { thefoocounter++; if (thefoocounter > 67) { sprint = true; } } else { thefoocounter = 0; } // SPRINT DISABLED FOR NOW! sprint = false; if (game->getClawController()->getPrepareAction() != ClawController::ActionNone) { weapTypeNum = 6; } else { if(sprint) { weapTypeNum = 5; } else { if(!claw_near) { if(game->getClawController()->hasActor()) { weapTypeNum = 4; } else { weapTypeNum = 2; } } else { if(game->getClawController()->hasActor()) { weapTypeNum = 3; } else { weapTypeNum = 1; } } } } bool weaponAnimationTypeChanged = false; // HACK: hack hack hack static! static int lastWeapTypeNum = -1; static int weaponChanging = 0; if (weapTypeNum != lastWeapTypeNum) { lastWeapTypeNum = weapTypeNum; weaponAnimationTypeChanged = true; weaponChanging = GAME_TICKS_PER_SECOND; } if (weaponChanging) weaponChanging--; int anim = ANIM_STAND_TYPE0 + weapTypeNum; // get the controls... bool up = game->gameUI->isLocalPlayerDirectControlOn(DIRECT_CTRL_FORWARD, unit); bool left = game->gameUI->isLocalPlayerDirectControlOn(DIRECT_CTRL_LEFT, unit); bool right = game->gameUI->isLocalPlayerDirectControlOn(DIRECT_CTRL_RIGHT, unit); bool down = game->gameUI->isLocalPlayerDirectControlOn(DIRECT_CTRL_BACKWARD, unit); // initial control coord system (controls in camera coord sys) VC3 upvec = VC3(0,1,0); VC3 controlFrontVec = VC3(0,0,-1); VC3 controlSideVec = controlFrontVec.GetCrossWith(upvec); // HACK: hack hack hack static! // (if we haven't moved, this is the last moved direction) static VC3 controlDirVec = VC3(1,0,0); bool doMovement = false; if (up || down || left || right) { VC3 newControlDirVec = VC3(0,0,0); if(!game::SimpleOptions::getBool(DH_OPT_B_CLAW_MOUSE)) { int jx = 0; int jy = 0; Keyb3_ReadJoystick(0, &jx, &jy, 0, 0, 0, 0); //if(abs(jx) < 4) // jx = 0; //if(abs(jy) < 4) // jy = 0; newControlDirVec -= controlSideVec * float(jx); newControlDirVec -= controlFrontVec * float(jy); } else { if (up) newControlDirVec += controlFrontVec; if (down) newControlDirVec -= controlFrontVec; if (left) newControlDirVec += controlSideVec; if (right) newControlDirVec -= controlSideVec; } if (newControlDirVec.x != 0 || newControlDirVec.y != 0 || newControlDirVec.z != 0) { newControlDirVec.Normalize(); controlDirVec = newControlDirVec; doMovement = true; } } // camera front/side vectors (height is flattened off) VC3 cameraFrontVec = game->gameUI->getGameCamera()->getTargetPosition() - game->gameUI->getGameCamera()->getPosition(); cameraFrontVec.y = 0.0f; if (cameraFrontVec.GetSquareLength() < 0.0001f) { cameraFrontVec = controlFrontVec; } cameraFrontVec.Normalize(); VC3 cameraSideVec = cameraFrontVec.GetCrossWith(upvec); // translate movement direction from camera coord system to global ocoord. system // this is the actual movement direction vector. VC3 globalDirVec = (cameraFrontVec * controlDirVec.GetDotWith(controlFrontVec)) + (cameraSideVec * controlDirVec.GetDotWith(controlSideVec)); VC3 velocity = unit->getVelocity(); // move if (doMovement) { float accel = unitType->getAcceleration() / GAME_TICKS_PER_SECOND; velocity += globalDirVec * accel; float maxspeed = unitType->getMaxSpeed() / GAME_TICKS_PER_SECOND; if (sprint) { maxspeed = unitType->getSprintSpeed() / GAME_TICKS_PER_SECOND; } if (weapTypeNum == 6) maxspeed = unitType->getSlowSpeed() / GAME_TICKS_PER_SECOND; float velTotalSq = velocity.GetSquareLength(); if (velTotalSq > maxspeed*maxspeed) { velocity *= maxspeed / (float)sqrtf(velTotalSq); } } // friction... frictionVelocity(&velocity, unitType->getFriction() * GAME_TICK_MSEC); unit->setVelocity(velocity); // where do we move to? float moveAngle = util::PositionDirectionCalculator::calculateDirection(VC3(0,0,0), globalDirVec); float rotateToAngle = moveAngle; bool doStrafeLeftAnim = false; bool doStrafeRightAnim = false; bool doStrafeBackAnim = false; static float standAngle = 0; // where do we aim? float aimDestAngle = moveAngle; char *aimBone = unitType->getAimBone(); if (aimBone != NULL) { VC3 unitPos = unit->getPosition(); /* static VC3 aimPos = VC3(0,0,0); VC3 aimDiff = game->getClawController()->getClawPosition() - unitPos; if (aimDiff.GetSquareLength() > 2.0f * 2.0f) { aimPos = game->getClawController()->getClawPosition(); }*/ // VC3 aimPos = game->getClawController()->getClawPosition(); VC3 aimPos = game->getClawController()->getTargetPosition(TARGET_ADVANCE_TICKS); aimDestAngle = util::PositionDirectionCalculator::calculateDirection(unitPos, aimPos); if (doMovement) { // --- THE HORRIBLE STRAFE LOGIC BEGINS --- float insideFwd = util::AngleRotationCalculator::getRotationForAngles(moveAngle, aimDestAngle, 45.0f); if (insideFwd == 0) { rotateToAngle = moveAngle; } else { float insideFwdDiag = util::AngleRotationCalculator::getRotationForAngles(moveAngle, aimDestAngle, 90.0f+45.0f); if (insideFwdDiag == 0) { if (insideFwd < 0) { rotateToAngle = moveAngle - 90.0f; if (rotateToAngle < 0.0f) rotateToAngle += 360.0f; doStrafeRightAnim = true; } else { rotateToAngle = moveAngle + 90.0f; if (rotateToAngle >= 360.0f) rotateToAngle -= 360.0f; doStrafeLeftAnim = true; } } else { rotateToAngle = moveAngle + 180.0f; if (rotateToAngle >= 360.0f) rotateToAngle -= 360.0f; doStrafeBackAnim = true; } } // --- THE HORRIBLE STRAFE LOGIC ENDS --- } else { if (weaponAnimationTypeChanged) { standAngle = aimDestAngle; } rotateToAngle = standAngle; // HACK: ... float maxTwist = 45.0f; if (weapTypeNum == 6) { maxTwist = 10.0f; } while (true) { float tooFarTwist = util::AngleRotationCalculator::getRotationForAngles(rotateToAngle, aimDestAngle, maxTwist+10); if (tooFarTwist > 0) { rotateToAngle += maxTwist*2; if (rotateToAngle >= 360.0f) rotateToAngle -= 360.0f; } else if (tooFarTwist < 0) { rotateToAngle -= maxTwist*2; if (rotateToAngle < 0.0f) rotateToAngle += 360.0f; } else { break; } } } } // When aiming, force rotation to dest. if (weapTypeNum == 6) { rotateToAngle = util::PositionDirectionCalculator::calculateDirection( unit->getPosition(), game->getClawController()->getTargetPosition(0)); } if (doMovement) { standAngle = moveAngle; weaponChanging = GAME_TICKS_PER_SECOND / 4; } // rotate towards movement/strafe/whatever we just decided VC3 rot = unit->getRotation(); float turnAccuracy = unitType->getTurningAccuracy(); float turnSpeed = unitType->getTurning(); // HACK, if unit is walking, slow it's turning speed down if (doMovement) { turnSpeed *= 0.7f; } float turnDir = util::AngleRotationCalculator::getRotationForAngles(rot.y, rotateToAngle, turnAccuracy); //Logger::getInstance()->error(int2str((int)turnDir)); rot.y += turnSpeed / GAME_TICKS_PER_SECOND * turnDir; // Logger::getInstance()->warning(int2str(rot.y)); // Logger::getInstance()->warning(int2str(aimDestAngle)); if (rotateToAngle - rot.y < -180) rotateToAngle +=360; if (rotateToAngle - rot.y > 180) rotateToAngle -=360; if (turnDir > 0 && rot.y > rotateToAngle) { rot.y = rotateToAngle; } if (turnDir < 0 && rot.y < rotateToAngle) { rot.y = rotateToAngle; } if (rot.y >= 360.0f) rot.y -= 360.0f; if (rot.y < 0.0f) rot.y += 360.0f; unit->setRotation(rot.x, rot.y, rot.z); // aim towards final aim direction... if (aimBone != NULL) { float aimAngle = aimDestAngle - rot.y; if (aimAngle < 0) aimAngle += 360.0f; unit->setLastBoneAimDirection(aimAngle); if (unit->getVisualObject() != NULL) { unit->getVisualObject()->rotateBone(aimBone, aimAngle, 0); } } // TODO: select correct animation if (doMovement) { if (doStrafeLeftAnim) { anim = ANIM_STRAFE_LEFT_TYPE0 + weapTypeNum; } else if (doStrafeRightAnim) { anim = ANIM_STRAFE_RIGHT_TYPE0 + weapTypeNum; } else if (doStrafeBackAnim) { anim = ANIM_RUN_BACKWARD_TYPE0 + weapTypeNum; } else { anim = ANIM_RUN_TYPE0 + weapTypeNum; } } else if (!weaponChanging) { // HACK: ... total hack! bool nappi = game->gameUI->getController(0)->isKeyDown(DH_CTRL_ATTACK_SECONDARY); if (turnDir < 0) { if (nappi && weapTypeNum == 4) { anim = ANIM_SPECIAL2; } else { anim = ANIM_TURN_LEFT_TYPE0 + weapTypeNum; } rotating = int(0.5*GAME_TICKS_PER_SECOND); } if (turnDir > 0) { if (nappi && weapTypeNum == 4) { anim = ANIM_SPECIAL1; } else { anim = ANIM_TURN_RIGHT_TYPE0 + weapTypeNum; } rotating = int(0.5*GAME_TICKS_PER_SECOND); } } //Logger::getInstance()->error(int2str(anim)); // apply the animation... if (unit->getAnimationSet() != NULL) { if (unit->getAnimationSet()->isAnimationInSet(anim)) { unit->getAnimationSet()->animate(unit, anim); if (unit->getAnimationSet()->isAnimationStaticFactored(anim)) { float fact = unit->getAnimationSet()->getAnimationStaticFactor(anim); ui::Animator::setAnimationSpeedFactor(unit, fact); } else { ui::Animator::setAnimationSpeedFactor(unit, 1.0f); } } else { Logger::getInstance()->warning("ClawUnitActor::actDirectClawControls - Requested anim not found in animation set."); Logger::getInstance()->debug("anim id number follows:"); Logger::getInstance()->debug(int2str(anim)); } } else { Logger::getInstance()->warning("ClawUnitActor::actDirectClawControls - Unit has null animation set."); } }
// return true if position ok and decal should be added // false, if position NOT ok and decal should NOT be added bool DecalPositionCalculator::calculateDecalPosition( game::GameScene *gameScene, const VC3 &origin, const VC3 &velocity, DECAL_POSITIONING positioning, int positionRandom, VC3 *resultPosition, QUAT *resultRotation) { assert(positioning != DecalPositionCalculator::DECAL_POSITIONING_INVALID); game::GameMap *gameMap = gameScene->getGameMap(); bool hitWall = false; *resultPosition = origin; *resultRotation = QUAT((-3.1415926f / 2.0f),0,0); // if velocity positioning... if (positioning == DecalPositionCalculator::DECAL_POSITIONING_VELOCITY) { VC3 velocityRandomized; if (positionRandom > 0) { velocityRandomized = velocity * GAME_TICKS_PER_SECOND; // TEMP //char buf[64]; //sprintf(buf, "%f,%f,%f", velocity.x, velocity.y, velocity.z); //Logger::getInstance()->error(buf); // TODO: add positionRandom to velocity _angle_... // (or maybe just do a quick hack and add it to xz-coordinates?) velocityRandomized.x += float((SystemRandom::getInstance()->nextInt() % (positionRandom * 2 + 1)) - positionRandom) / 100.0f; velocityRandomized.z += float((SystemRandom::getInstance()->nextInt() % (positionRandom * 2 + 1)) - positionRandom) / 100.0f; // add to y too? maybe should add downward only? // NOTE: biased downward velocityRandomized.y += float((SystemRandom::getInstance()->nextInt() % (positionRandom * 2 + 1)) - positionRandom) / 100.0f; velocityRandomized.y -= float(positionRandom) / 100.0f * 0.5f; } else { velocityRandomized = velocity; } velocityRandomized *= 2.0f; IStorm3D_Scene *scene = gameScene->getStormScene(); VC3 dir = velocityRandomized.GetNormalized(); VC3 rayOrigin = origin; float rayLen = velocityRandomized.GetLength(); Storm3D_CollisionInfo sceneColl; sceneColl.includeTerrainObjects = false; scene->RayTrace(rayOrigin, dir, rayLen, sceneColl, true); /* if (sceneColl.hit) { VC3 hitNormal = sceneColl.plane_normal; // make a "wall" hit if normal-y is not nearly 1 //if (fabs(hitNormal.y) < 0.8f) { hitWall = true; VC3 x(rand() % 1000 / 999.f, 0, rand() % 1000 / 999.f); x.Normalize(); x -= hitNormal * x.GetDotWith(hitNormal); VC3 y = -x.GetCrossWith(hitNormal); assert(fabsf(x.GetDotWith(y)) < 0.0001f); assert(fabsf(x.GetDotWith(hitNormal)) < 0.0001f); MAT tm; tm.Set(0, x.x); tm.Set(1, x.y); tm.Set(2, x.z); tm.Set(4, y.x); tm.Set(5, y.y); tm.Set(6, y.z); tm.Set(8, hitNormal.x); tm.Set(9, hitNormal.y); tm.Set(10, hitNormal.z); *resultRotation = tm.GetRotation(); } *resultPosition = sceneColl.position; } else { *resultPosition += velocityRandomized; } */ // New version { VC3 hitNormal(0, 1.f, 0); if(sceneColl.hit) { hitNormal = sceneColl.plane_normal; *resultPosition = sceneColl.position; } else { *resultPosition += velocityRandomized; VC2 p2(resultPosition->x, resultPosition->z); hitNormal = gameScene->getTerrain()->getFaceNormal(p2); } { if(sceneColl.hit) hitWall = true; /* VC3 y = dir; VC3 z = hitNormal; y -= hitNormal * y.GetDotWith(hitNormal); VC3 x = z.GetCrossWith(y); */ VC3 x = dir; x.y = 0.f; x.Normalize(); x -= hitNormal * x.GetDotWith(hitNormal); VC3 y = -x.GetCrossWith(hitNormal); VC3 z = hitNormal; MAT tm; tm.Set(0, x.x); tm.Set(1, x.y); tm.Set(2, x.z); tm.Set(4, y.x); tm.Set(5, y.y); tm.Set(6, y.z); tm.Set(8, z.x); tm.Set(9, z.y); tm.Set(10, z.z); resultRotation->MakeFromAngles(0.f, 0.f, -PI*0.5f); *resultRotation = (*resultRotation) * tm.GetRotation(); /* VC3 x(rand() % 1000 / 999.f, 0, rand() % 1000 / 999.f); x.Normalize(); x -= hitNormal * x.GetDotWith(hitNormal); VC3 y = -x.GetCrossWith(hitNormal); assert(fabsf(x.GetDotWith(y)) < 0.0001f); assert(fabsf(x.GetDotWith(hitNormal)) < 0.0001f); MAT tm; tm.Set(0, x.x); tm.Set(1, x.y); tm.Set(2, x.z); tm.Set(4, y.x); tm.Set(5, y.y); tm.Set(6, y.z); tm.Set(8, hitNormal.x); tm.Set(9, hitNormal.y); tm.Set(10, hitNormal.z); *resultRotation = tm.GetRotation(); */ } } // TODO: some kind of terrain raytrace maybe...? // should collide to walls, etc. } // if downward positioning... if (positioning == DecalPositionCalculator::DECAL_POSITIONING_DOWNWARD) { if (positionRandom > 0) { // TODO: add a random xz-offset to result position //*resultPosition += randomizedOffset; resultPosition->x += float((SystemRandom::getInstance()->nextInt() % (positionRandom * 2 + 1)) - positionRandom) / 100.0f; resultPosition->z += float((SystemRandom::getInstance()->nextInt() % (positionRandom * 2 + 1)) - positionRandom) / 100.0f; } /* // psd { VC2 p2(resultPosition->x, resultPosition->z); VC3 hitNormal = gameScene->getTerrain()->getFaceNormal(p2); VC3 x(rand() % 1000 / 999.f, 0, rand() % 1000 / 999.f); x.Normalize(); x -= hitNormal * x.GetDotWith(hitNormal); VC3 y = -x.GetCrossWith(hitNormal); assert(fabsf(x.GetDotWith(y)) < 0.0001f); assert(fabsf(x.GetDotWith(hitNormal)) < 0.0001f); MAT tm; tm.Set(0, x.x); tm.Set(1, x.y); tm.Set(2, x.z); tm.Set(4, y.x); tm.Set(5, y.y); tm.Set(6, y.z); tm.Set(8, hitNormal.x); tm.Set(9, hitNormal.y); tm.Set(10, hitNormal.z); *resultRotation = tm.GetRotation(); } */ VC3 fooNormal; calculateDecalRotation(gameScene, *resultPosition, *resultRotation, 0.f, fooNormal); } // now check that we're still inside map boundaries if (!gameMap->isWellInScaledBoundaries(resultPosition->x, resultPosition->z)) { // out of map. return false; } // then fix decal height to ground height if (positioning == DecalPositionCalculator::DECAL_POSITIONING_DOWNWARD || positioning == DecalPositionCalculator::DECAL_POSITIONING_VELOCITY) { if (!hitWall) { resultPosition->y = gameMap->getScaledHeightAt(resultPosition->x, resultPosition->z); } } // check that not on top of metal grid area... if (game::MaterialManager::isMaterialUnderPosition(gameMap, *resultPosition, MATERIAL_METAL_GRATE)) { // on top of grid, no decal here. return false; } // TODO: check that not inside a wall, terrainobject, etc. // if so, return false return true; }