void PhysicsEngine::CollisionMapResponse(PowerBall* b, Map* map, Vector3 normalPlane, float dt) { /* simple response Vector3 normal = Vector3(0,1,0); Vector3 vn = normal*(this->mVelocity.GetDotProduct(normal)); Vector3 vp = this->mVelocity - vn; Vector3 vAfter = vp - vn; this->mVelocity = vAfter; */ // normal of the "collision plane" //Vector3 nColl = Vector3(0,-1,0); //this->GetPositionVector3() - p->GetPositionVector3(); Vector3 nColl = normalPlane; // for easy projecting of vector, no div by |n|^2 in proj formula nColl.normalize(); // savning the important stuff for easy acc float m1 = b->GetMass(); float m2 = map->GetMass(); float mSum = m1+m2; Vector3 v1 = b->GetVelocity(); Vector3 v2 = Vector3(0,0,0);//the platform is not moving b1->mVelocity; // projecting the vector v1 on nColl float x1 = nColl.GetDotProduct(v1); // factor in nColl dir Vector3 v1x = nColl*x1; // projetion done Vector3 v1y = v1 - v1x; // perpendicular vector // projecting the vector v2 on nColl nColl = nColl*(-1); // switching direction of "plane normal" float x2 = nColl.GetDotProduct(v2); // factor in nColl dir Vector3 v2x = nColl*x2; // projetion done Vector3 v2y = v2 - v2x; // perpendicular vector if((v1x.GetLength() >1.5f) && b->SoundEnabled()) this->mCollisionWithWall->Play(); //float e = this->mRestitution; float e = map->GetRestitution(); float newdt = dt*0.001f; //v1y -= v1y*pow(this->mFriction, 2)*newdt; if( b->GetPreviousVelocity().GetLength() < b->GetVelocity().GetLength() ) { if( (v1y.GetLength() < 2.0f) && (v1y.GetLength() > 0.0f) ) v1y -= v1y*b->GetFriction()*newdt; if( v1y.GetLength() < 0.1f && (v1y.GetLength() > 0.0f) ) v1y *= b->GetFriction()*newdt; } b->SetVelocity(Vector3( v1x*(m1-e*m2)/(mSum) + v2x*((1+e)*m2)/(mSum) + v1y)); //this->mAcceleration = Vector3(0,0,0); //this->mSumAddedForce += this->mAcceleration*(-1); // use this line if the platform also has a speed. //b1->mVelocity = Vector3( v1x*(2*m1)/(mSum) + v2x*(m2-m1)/(mSum) + v2y ); return; }
bool PhysicsEngine::RayTriIntersect(Vector3 origin, Vector3 direction, Vector3 p0, Vector3 p1, Vector3 p2, float &u, float &v, float &t) { Vector3 e1, e2, q, s, r; u = v = t = 0; float a,f, eps = 0.00001f; e1 = p1 - p0; e2 = p2 - p0; //q = direction.GetCrossProduct(e2); q = e2.GetCrossProduct(direction); a = e1.GetDotProduct(q); if( a > - eps && a < eps) return false; f = 1/a; s = origin - p0; u = f*(s.GetDotProduct(q)); if( u < 0.0f) return false; //r = s.GetCrossProduct(e1); r = e1.GetCrossProduct(s); v = f*(direction.GetDotProduct(r)); if( v < 0.0f || u+v > 1.0f) return false; t = f*(e2.GetDotProduct(q)); return true; }
void CCollisionBody::FindSATMinMax( const std::vector< Vector3< float > > & colOffset, Vector3< float > & pos, Vector3< float > & axis, float * min, float * max ) { unsigned long int offsetCount = colOffset.size(); float * d = new float[offsetCount]; for( int j = 0; j < offsetCount; j++ ) { Vector3< float > np = colOffset[j] + pos; d[j] = np.GetDotProduct( axis ); } *min = d[0]; *max = d[0]; for( int j = 1; j < offsetCount; j++ ) { if( d[j] < *min ) *min = d[j]; else if( d[j] > *max ) *max = d[j]; } delete [] d; }
void Helicopter::Update(float dt) { // Gravity this->direction.y -= GRAVITY * dt; // Air friction float velocity = this->GetVelocity(); float newVelocity = velocity - ((AIR_FRICTION_CONSTANT * (velocity * velocity)) / this->mass) * dt; float dv = newVelocity / velocity; this->direction *= dv; // Collision against terrain float terrY = this->terrain->GetYPositionAt(this->pos.x, this->pos.z); if(this->pos.y + this->direction.y * dt <= terrY) { // Bounce this->direction.y = 0 - this->direction.y * this->elacticity; // Take damage float damage = (abs(this->direction.y * 5) + abs(this->direction.x) + abs(this->direction.z)); if(damage > 5.0f) this->health -= damage; } // Regen health: this->health += dt; if(this->health > 100.0f) this->health = 100.0f; // Friction against terrain here if close to it, simplified calculating only in the XZ plane and not angled terrain. if(this->pos.y - 0.5f < terrY) { float frictionForce = GROUND_FRICTION_CONSTANT * this->mass * GRAVITY; float frictionAcc = (frictionForce / this->mass) * dt; if(frictionAcc > this->GetXZVelocity()) { this->direction.x = 0; this->direction.z = 0; } else { velocity = this->GetVelocity(); newVelocity = velocity - frictionAcc; dv = newVelocity / velocity; this->direction *= dv; } // Reset rolling when touching ground. Vector3 defup = Vector3(0, 1, 0); defup.Normalize(); Vector3 cross = this->up.GetCrossProduct(this->forward); cross.Normalize(); float dotCrossDefup = cross.GetDotProduct(defup); // Roll left if(dotCrossDefup < 0.0f) { this->RollLeft(true); this->RollRight(false); } // Roll right else if(dotCrossDefup > 0.0f) { this->RollLeft(false); this->RollRight(true); } float dotForUp = this->forward.GetDotProduct(defup); // Roll forward if(dotForUp > 0.0f) { this->RollForward(true); this->RollBackward(false); } // Roll backward else if(dotForUp < 0.0f) { this->RollForward(false); this->RollBackward(true); } } if(this->health > 95.0f) this->UpdateChopperSpec(dt); // For funness we need to reset the direction.y a little, it's too hard to handle up&downs otherwise //direction.y *= 1.0f - dt; // AutoHoverEffect this->AutoHover(dt); if(this->health > 95.0f) { this->pos += this->direction * dt; this->chopper->SetPosition(this->pos); this->rotor->SetPosition(this->pos); this->secrotor->SetPosition(this->pos - this->forward * 28 + this->up * 11); // Adding offset for the second rotor. Vector3 lookAt = this->forward; lookAt.y = 0.0f; GetGraphics()->GetCamera()->SetPosition(this->pos + Vector3(0, this->camOffsetHeight, 0) - lookAt * this->camOffsetDistance); GetGraphics()->GetCamera()->LookAt(this->pos + lookAt * 30 + Vector3(0, 10, 0)); // Attune forward to direction. Vector3 xzdir = this->direction; xzdir.y = 0.0f; float xzlen = xzdir.GetLength(); xzdir.Normalize(); Vector3 xzfor = this->forward; xzfor.y = 0.0f; xzfor.Normalize(); float dotDirFor = xzdir.GetDotProduct(xzfor); Vector3 vecRight = xzfor.GetCrossProduct(Vector3(0, 1, 0)); vecRight.y = 0.0f; vecRight.Normalize(); float dotDirRight = xzdir.GetDotProduct(vecRight); // When flying backwards remove the "BAM SNAP" effect when dot product gets 0.0f at the sides. if(dotDirFor < 0.0f) dotDirFor = 0.0f; float angle = dt * xzlen * xzlen * xzlen * xzlen * (1 - abs(dotDirFor)) * 0.000001f; if(dotDirRight < 0.0f) angle *= -1.0f; this->forward.RotateAroundAxis(this->up, -angle); this->chopper->RotateAxis(this->up, -angle); this->rotor->RotateAxis(this->up, angle); } }
bool ProjectileArrowBehavior::Update( float dt ) { if(!zMoving) return true; Vector3 newPos; Vector3 newDir; // Update linear position. newPos = this->zActor->GetPosition(); zVelocity.Normalize(); zVelocity *= zSpeed; newPos += (zVelocity * dt); newDir = zVelocity; newDir.Normalize(); //Rotate Mesh Vector3 ProjectileStartDirection = Vector3(0,0,-1); Vector3 ProjectileMoveDirection = newDir; ProjectileStartDirection.Normalize(); Vector3 around = ProjectileStartDirection.GetCrossProduct(ProjectileMoveDirection); float angle = acos(ProjectileStartDirection.GetDotProduct(ProjectileMoveDirection)); //Set Values this->zActor->SetPosition(newPos, false); this->zActor->SetRotation(Vector4(0.0f, 0.0f, 0.0f, 1.0f)); this->zActor->SetRotation(around, angle); this->zActor->SetDir(newDir); /**Check If the arrow is outside the world.**/ if( !this->zWorld->IsInside(newPos.GetXZ()) ) { Stop(); this->zActor->SetPosition(newPos); return true; } //**Check if the projectile has hit the ground** float yValue = std::numeric_limits<float>::lowest(); try { yValue = this->zWorld->CalcHeightAtWorldPos(newPos.GetXZ()); } catch(...) { Stop(); this->zActor->SetPosition(newPos); return true; } // If true, stop the projectile and return. float middle = zLength * 0.5f; float yTip = newPos.y - middle; if(yTip <= yValue ) { middle += yValue; newPos.y = middle; this->Stop(); this->zActor->SetPosition(newPos); return true; } //**Update Velocity for next update** // Update linear velocity from the acceleration. this->zVelocity += (GRAVITY * dt); // Impose drag. this->zVelocity *= pow(zDamping, dt); //Update-Notify Position this->zActor->SetPosition(newPos); /***Check collisions***/ //Check if the arrow has hit a dynamic actor Actor* collide = RayVsMeshDynamicActorCollision(zLength, newPos); if(collide) { this->Stop(); ProjectileArrowCollide PAC; PAC.zActor = collide; NotifyObservers(&PAC); if( BioActor* bioActor = dynamic_cast<BioActor*>(collide) ) { if( bioActor->IsAlive() ) { ProjectileActor* projActor = dynamic_cast<ProjectileActor*>(this->zActor); bioActor->TakeDamage( projActor->GetDamage(), projActor->GetOwner() ); } } this->zHitTarget = collide; return true; } //Check if the arrow has hit a static actor collide = RayVsMeshStaticActorCollision(zLength, newPos); if(collide) { this->Stop(); ProjectileArrowCollide PAC; PAC.zActor = collide; NotifyObservers(&PAC); this->zHitTarget = collide; return true; } return false; }
bool PhysicsEngine::CollisionWithMapSimple(PowerBall* b, Map* map, Vector3 &normalPlane) { MaloW::Array<MeshStrip*>* temp = map->GetMesh()->GetStrips(); //int sizeMstrip = temp->size(); int sizeVertexS0 = temp->get(0)->getNrOfVerts(); Vertex* verts; //Vector3 origin = this->GetPositionVector3(); Vector3 origin = b->GetTempPosition(); Vector3 dir = b->GetVelocity(); Vector3 dirN = dir/dir.GetLength(); verts = temp->get(0)->getVerts(); /* for(int i = 0;i<sizeMstrip;i++) { } */ Vector3 p0,p1,p2, normal, v1,v2; float smalestTime = -1; bool firstHit = false; float u, v,t; float lengthProjN = 0; Vector3 p0Store, p1Store,p2Store, normalStore; Vector3 pos = Vector3(map->GetMesh()->GetPosition()); Vector3 posS = b->GetTempPosition();//this->GetPositionVector3(); Vector3 rayDirection; Vector3 scalingMesh = map->GetMesh()->GetScaling(); D3DXMATRIX quat; D3DXMatrixRotationQuaternion(&quat, &map->GetMesh()->GetRotation()); Matrix4 rotate(quat); rotate.TransposeThis(); Matrix4 scaling; scaling.SetScale(scalingMesh); Matrix4 translate; translate.SetTranslate(pos); Matrix4 world = translate*rotate*scaling; for(int i =0; i< sizeVertexS0; i+=3) { /* p0 = Vector3(verts[i].pos).GetComponentMultiplication(scalingMesh) + pos; p1 = Vector3(verts[i+1].pos).GetComponentMultiplication(scalingMesh) +pos; p2 = Vector3(verts[i+2].pos).GetComponentMultiplication(scalingMesh) + pos; */ p0 = world*Vector3(verts[i].pos); p1 = world*Vector3(verts[i+1].pos); p2 = world*Vector3(verts[i+2].pos); v1 = p1-p0; v2 = p2-p0; rayDirection = v1.GetCrossProduct(v2); rayDirection.normalize(); float tempLength; Vector3 ny; Vector3 projN; if(RayTriIntersect(origin , rayDirection, p0, p1, p2, u, v, t) ) { normal = rayDirection; ny = origin - p0; projN = normal*ny.GetDotProduct(normal); tempLength = projN.GetLength(); if(!firstHit) { firstHit = true; smalestTime = t; lengthProjN = tempLength; p0Store = p0; p1Store = p1; p2Store = p2; normalStore = normal; } else { if( tempLength < lengthProjN ) { smalestTime = t; lengthProjN = tempLength; p0Store = p0; p1Store = p1; p2Store = p2; normalStore = normal; } } } // check agains all edges Vector3 lineDirection; float scalarProj; Vector3 projOnLine; Vector3 normalToLine; // edge 1: ny = origin - p0; lineDirection = p1 - p0; scalarProj = (ny.GetDotProduct(lineDirection)/lineDirection.GetLengthSquared()); projOnLine = lineDirection * scalarProj; if( (scalarProj >= 0.0f) && (scalarProj <= 1) ) { normalToLine = ny - projOnLine; tempLength = normalToLine.GetLength(); if(!firstHit) { firstHit = true; lengthProjN = tempLength; p0Store = p0; p1Store = p1; p2Store = p2; normalStore = normalToLine; normalStore.normalize(); } else { if( tempLength < lengthProjN ) { lengthProjN = tempLength; p0Store = p0; p1Store = p1; p2Store = p2; normalStore = normalToLine; normalStore.normalize(); } } } // edge 2: ny = origin - p1; lineDirection = p2 - p1; scalarProj = (ny.GetDotProduct(lineDirection)/lineDirection.GetLengthSquared()); projOnLine = lineDirection * scalarProj; if( (scalarProj >= 0.0f) && (scalarProj <= 1) ) { normalToLine = ny - projOnLine; tempLength = normalToLine.GetLength(); if(!firstHit) { firstHit = true; lengthProjN = tempLength; p0Store = p0; p1Store = p1; p2Store = p2; normalStore = normalToLine; normalStore.normalize(); } else { if( tempLength < lengthProjN ) { lengthProjN = tempLength; p0Store = p0; p1Store = p1; p2Store = p2; normalStore = normalToLine; normalStore.normalize(); } } } // edge 3: ny = origin - p2; lineDirection = p0 - p2; scalarProj = (ny.GetDotProduct(lineDirection)/lineDirection.GetLengthSquared()); projOnLine = lineDirection * scalarProj; if( (scalarProj >= 0.0f) && (scalarProj <= 1) ) { normalToLine = ny - projOnLine; tempLength = normalToLine.GetLength(); if(!firstHit) { firstHit = true; lengthProjN = tempLength; p0Store = p0; p1Store = p1; p2Store = p2; normalStore = normalToLine; normalStore.normalize(); } else { if( tempLength < lengthProjN ) { lengthProjN = tempLength; p0Store = p0; p1Store = p1; p2Store = p2; normalStore = normal; } } } } if(firstHit) { // for checking if the ball are in the air not turned on at the moment, float eps = 0.5f; //0.001 if( (lengthProjN < (b->GetRadius() + eps)) && (lengthProjN > (b->GetRadius() - eps)) ) { b->SetNormalContact(normalStore); b->SetHasContact(true); } else { b->SetNormalContact(normalStore); b->SetHasContact(false); } if( lengthProjN <= b->GetRadius()) { Vector3 velNorm = b->GetVelocity(); velNorm.normalize(); if(normalStore.GetDotProduct(velNorm) >=0) return false; float diff = abs(lengthProjN- b->GetRadius()); //Vector3 newPo = origin -dirN*diff; //Vector3 projVel = normalStore * this->mVelocity.GetDotProduct(normalStore); Vector3 newPo = origin + normalStore*diff; /* if( projVel.GetDotProduct(normalStore) < 0.0f) { newPo = origin - normalStore*diff; return false; } else newPo = origin + normalStore*diff; */ //this->SetPosition(newPo); b->SetTempPosition(newPo); normalPlane = normalStore; //this->mNormalContact = normalPlane; //this->mHasContact = true; return true; } else { normalPlane = Vector3(0,0,0); //this->mNormalContact = normalPlane; //this->mHasContact = false; return false; } } normalPlane = Vector3(0,0,0); b->SetNormalContact(normalPlane); //this->mHasContact = false; return false; }
void PhysicsEngine::CollisionSphereResponse(PowerBall* b, PowerBall* b1) { // normal of the "collision plane" //Vector3 nColl = this->GetPositionVector3() - b1->GetPositionVector3(); Vector3 nColl = b->GetTempPosition() - b1->GetTempPosition(); // for easy projecting of vector, no div by |n|^2 in proj formula Vector3 tempa = nColl; nColl.normalize(); // savning the important stuff for easy acc float m1 = b->GetMass(); float m2 = b1->GetMass(); float mSum = m1+m2; Vector3 v1 = b->GetVelocity(); Vector3 v2 = b1->GetVelocity(); // projecting the vector v1 on nColl float x1 = nColl.GetDotProduct(v1); // factor in nColl dir Vector3 v1x = nColl*x1; // projetion done Vector3 v1y = v1 - v1x; // perpendicular vector // projecting the vector v2 on nColl nColl = nColl*(-1); // switching direction of "plane normal" float x2 = nColl.GetDotProduct(v2); // factor in nColl dir Vector3 v2x = nColl*x2; // projetion done Vector3 v2y = v2 - v2x; // perpendicular vector float e1 = b->GetRestitution(); float e2 = b1->GetRestitution(); float e = (e1 + e2)/2.0f; if(((v1x-v2x).GetLength() > 0.6f) && b->SoundEnabled()) this->mCollisionWithBall->Play(); /* this->mVelocity = Vector3( v1x*(m1-m2)/(mSum) + v2x*(2*m2)/(mSum) + v1y ); b1->mVelocity = Vector3( v1x*(2*m1)/(mSum) + v2x*(m2-m1)/(mSum) + v2y ); */ b->SetVelocity(Vector3( v1x*(m1-m2*e)/(mSum) + v2x*((1+e)*m2)/(mSum) + v1y )); b1->SetVelocity(Vector3( v1x*((1+e)*m1)/(mSum) + v2x*(m2-m1*e)/(mSum) + v2y )); /* calculating damage. */ if(b->WarlockMode()) { Vector3 ve1 = b->GetVelocity(); Vector3 ve2 = b1->GetVelocity(); Vector3 relativeV = ve1 - ve2; if( relativeV.GetLength() > 0.6f) { float v1 = ve1.GetLength(); float v2 = ve2.GetLength(); float mass1 = b->GetMass(); float mass2 = b1->GetMass(); float momentum1 = v1 * mass1; float momentum2 = v2 * mass2; float sumMomentum = momentum1 + momentum2; /* to make it clear. if ball 1 has the speed of 10 m/s and ball 2 has ** the speed 0 m/s, ball 1 will not get any damage but ball 2 gets ** his health minus 10* (10 / 10) = 10 so ball 2 has lost 10 in hp. ** this works good because we using momentum as a weighted value. */ float damage1 = 10.0f* (momentum2 / sumMomentum); float damage2 = 10.0f* (momentum1 / sumMomentum); float health1 = b->GetHealth(); health1 -= damage1; b->SetHealth(health1); float health2 = b1->GetHealth(); health2 -= damage2; b1->SetHealth(health2); } } /* informing the spells to the balls that it has been a collision */ Spell** spells = b->GetSpells(); for(int i = 0;i<b->GetNrOfSpells();i++) spells[i]->InformCollision(); spells = b1->GetSpells(); for(int i = 0;i<b1->GetNrOfSpells();i++) spells[i]->InformCollision(); }
bool PhysicsEngine::CollisionWithSphereSimple(PowerBall* b, PowerBall* b1) { Vector3 r = b->GetPositionVector3() - b1->GetPositionVector3(); r = b->GetTempPosition() - b1->GetTempPosition(); float distanceBalls = r.GetLength(); float sumRadius = b->GetRadius() + b1->GetRadius(); if(distanceBalls > sumRadius) return false; /* we have collision but we need to move the balls so they are not inside each other * solve this equation: ((pos1 - t*vel1) - (pos2 - t*vel2)).length = radie1 + radie2 * * this gives ut the following: * d = distance = p1-p2 * rV = relative velocity = v2-v1 * sumR = sumRadius = r1 + r2 * * t = - rV.dot(d)/|rV|^2 +- sqrt( rV.dot(d)^2/|rV|^4 - (sumR^2 - |d|^2) / |rV|^2 * */ Vector3 d = b->GetPositionVector3() - b1->GetPositionVector3(); d = b->GetTempPosition() - b1->GetTempPosition(); Vector3 rV = b1->GetVelocity() - b->GetVelocity(); float sumR = b->GetRadius() + b1->GetRadius(); float tempA = rV.GetDotProduct(d) / rV.GetLengthSquared(); float tempB = tempA*tempA; float tempC = (d.GetLengthSquared() - sumR*sumR) / rV.GetLengthSquared(); float tempSq = tempB - tempC; if( tempSq < 0) // no real solutions return false; else { float t1 = - tempA - sqrt(tempSq); float t2 = - tempA + sqrt(tempSq); Vector3 newPos1, newPos2; if(t1 >= 0) { /* newPos1 = this->GetPositionVector3() - this->mVelocity*t1; newPos2 = b1->GetPositionVector3() - b1->mVelocity*t1; this->SetPosition(newPos1); b1->SetPosition(newPos2); */ newPos1 = b->GetTempPosition() - b->GetVelocity()*t1; newPos2 = b1->GetTempPosition() - b1->GetVelocity()*t1; b->SetTempPosition(newPos1); b1->SetTempPosition(newPos2); } else if(t2 >= 0) { /* newPos1 = this->GetPositionVector3() - this->mVelocity*t2; newPos2 = b1->GetPositionVector3() - b1->mVelocity*t2; this->SetPosition(newPos1); b1->SetPosition(newPos2); */ newPos1 = b->GetTempPosition() - b->GetVelocity()*t2; newPos2 = b1->GetTempPosition() - b1->GetVelocity()*t2; b->SetTempPosition(newPos1); b1->SetTempPosition(newPos2); } else return false; } return true; }
void Game::PlayGameMode2() { GraphicsEngine* mGe = GetGraphics(); GetGraphics()->ShowLoadingScreen("Media/LoadingScreen/LoadingScreenBG2.png", "Media/LoadingScreen/LoadingScreenPB.png", 1.0f, 1.0f); GetGraphics()->ChangeSkyBox("Media/StarMap.dds"); GetGraphics()->GetCamera()->SetUpVector(Vector3(0, 1, 0)); GetGraphics()->GetCamera()->SetForward(Vector3(1, 0, 0)); GetGraphics()->GetCamera()->SetPosition(Vector3(-17.0f, 56.0f, 0)); GetGraphics()->GetCamera()->LookAt(GetGraphics()->GetCamera()->GetPosition() - Vector3(1, 0.3f, 0)); iLight* mLights[5]; mLights[0] = mGe->CreateLight(Vector3(0, 50, 0)); mLights[1] = mGe->CreateLight(Vector3(0, 50, -20)); mLights[2] = mGe->CreateLight(Vector3(0, 50, 20)); mLights[3] = mGe->CreateLight(Vector3(10, 50, 0)); mLights[4] = mGe->CreateLight(Vector3(-10, 50, 0)); for(int i = 0; i < 5; i++) mLights[i]->SetIntensity(30.0f); GetGraphics()->SetSunLightDisabled(); GetGraphics()->SetSceneAmbientLight(Vector3(0.4f, 0.4f, 0.4f)); Vector3 centerPlatform = Vector3(0,20,0); Map* mPlatform = new Map("Media/MazeMapFixed.obj", centerPlatform); Map* mBox = new Map("Media/MazeMapFrame.obj", centerPlatform + Vector3(0,1,0) ); mPlatform->SetShrinkValue(0.0f); /* set so we cant tilt it more than these angles. */ mPlatform->SetMaxAngleX(10.0f*(PI/180.0f)); mPlatform->SetMaxAngleZ(10.0f*(PI/180.0f)); mPlatform->SetRotate(false); mPlatform->SetTargetAngleX(0.5f); mPlatform->SetTargetAngleZ(-0.5f); PowerBall* mBalls = new PowerBall("Media/Ball.obj", START_POS); mBalls->SetForwardVector(Vector3(0,0,1)); mBalls->SetKnockoutMode(); mBalls->SetAcceleration(mBalls->GetAcceleration()*30.0f); iText* timeTxt = GetGraphics()->CreateText("", Vector2(50, 60), 1.0f, "Media/fonts/new"); iText* scoreTxt = GetGraphics()->CreateText("", Vector2(50, 95), 1.0f, "Media/fonts/new"); iImage* guiStar = GetGraphics()->CreateImage(Vector2(200, 90), Vector2(75, 75), "Media/star.png"); guiStar->SetOpacity(0.0f); float starTimer = 0.0f; GetGraphics()->LoadingScreen("Media/LoadingScreen/LoadingScreenBG2.png", "Media/LoadingScreen/LoadingScreenPB.png", 1.0f, 1.0f, 1.0f, 1.0f); this->FlushQueue(); mGe->GetCamera()->SetPosition(centerPlatform + Vector3(0.0f, 30.0f, 20.0f)); mGe->GetCamera()->LookAt(centerPlatform); // Score / results: float time = 0.0f; bool started = false; int score = 0; float delayTimer = 1000.0f; GetGraphics()->GetKeyListener()->SetCursorVisibility(false); go = true; const Vector3 DefaultDir = Vector3(0.0f, 1.0f, 0.0f); int currentPrev = 0; Vector3 prevVectors[NROFPREV]; for(int i = 0; i < NROFPREV; i++) { prevVectors[i] = DefaultDir; } while(delayTimer > 0) { float diff = GetGraphics()->Update(); delayTimer -= diff; } while(GetGraphics()->IsRunning() && go) { if(mGe->GetKeyListener()->IsPressed('1')) { mGe->GetCamera()->SetPosition(centerPlatform+ Vector3(20.0f, 30.0f, 20.0f)); mGe->GetCamera()->LookAt(centerPlatform ); } if(mGe->GetKeyListener()->IsPressed('2')) { mGe->GetCamera()->SetPosition(centerPlatform+ Vector3(20.0f, 30.0f, -20.0f)); mGe->GetCamera()->LookAt(centerPlatform ); } if(mGe->GetKeyListener()->IsPressed('3')) { mGe->GetCamera()->SetPosition(centerPlatform+ Vector3(-20.0f, 30.0f, 20.0f)); mGe->GetCamera()->LookAt(centerPlatform ); } if(mGe->GetKeyListener()->IsPressed('4')) { mGe->GetCamera()->SetPosition(centerPlatform+ Vector3(-20.0f, 30.0f, -20.0f)); mGe->GetCamera()->LookAt(centerPlatform ); } // Updates GFX float diff = GetGraphics()->Update(); // Handle events such as network packets and client connections this->HandleEvent(diff); if(GetGraphics()->GetKeyListener()->IsPressed(VK_ESCAPE)) go = false; if(GetGraphics()->GetKeyListener()->IsPressed('R') || (this->networkController != NULL && this->networkController->needRestart == true)) { if(this->networkController != NULL) { this->networkController->needRestart = false; } delete mBalls; // Spawn at last score - 1; if(score == 0) mBalls = new PowerBall("Media/Ball.obj", scorePos[0]); else mBalls = new PowerBall("Media/Ball.obj", scorePos[score - 1]); mBalls->SetForwardVector(Vector3(0,0,1)); mBalls->SetKnockoutMode(); mBalls->SetAcceleration(mBalls->GetAcceleration()*15.0f); mPlatform->ResetXZAngles(); mPlatform->RotateX(0); } iPhysicsEngine* pe = GetGraphics()->GetPhysicsEngine(); mBalls->UpdateBallParentMode(mPlatform); mBalls->Update(diff); Vector3 normalPlane; if(pe->DoSpecialPhoneCollisionGame(mBalls, mPlatform, normalPlane, diff)) mBalls->collisionPlatformResponse(mPlatform, normalPlane, diff); mBalls->UpdatePost(); mPlatform->Update(diff); if(this->networkController) { mPlatform->SetRotate(true); Vector3 phoneDirr = Vector3(this->networkController->direction.y, this->networkController->direction.z, -this->networkController->direction.x); //Vector3 phoneDirr = this->networkController->direction; phoneDirr.Normalize(); prevVectors[currentPrev] = phoneDirr; float angle = CalcAngle(phoneDirr, DefaultDir, prevVectors, currentPrev); float angleX = acos(DefaultDir.GetDotProduct(Vector3(0, phoneDirr.y , phoneDirr.z).Normalize())); float angleZ = acos(DefaultDir.GetDotProduct(Vector3(phoneDirr.x, phoneDirr.y, 0).Normalize())); if(phoneDirr.z > 0) { angleX *= -1; } if(phoneDirr.x < 0) { angleZ *= -1; } mPlatform->SetTargetAngleX(angleX/4); mPlatform->SetTargetAngleZ(angleZ/4); angle /= 4; currentPrev++; if(currentPrev >= NROFPREV) currentPrev = 0; } if(mGe->GetKeyListener()->IsPressed('W')) { mPlatform->RotateX(-diff); Vector3 tempPos = mBalls->GetPosition() - mPlatform->GetMesh()->GetPosition(); tempPos.RotateAroundAxis(Vector3(1,0,0), (PI/8.0f)*-diff*0.001f); mBalls->SetPosition(mPlatform->GetMesh()->GetPosition() + tempPos); } if(mGe->GetKeyListener()->IsPressed('S')) { mPlatform->RotateX(diff); Vector3 tempPos = mBalls->GetPosition() - mPlatform->GetMesh()->GetPosition(); tempPos.RotateAroundAxis(Vector3(1,0,0), (PI/8.0f)*diff*0.001f); mBalls->SetPosition(mPlatform->GetMesh()->GetPosition() + tempPos); } if(mGe->GetKeyListener()->IsPressed('A')) { mPlatform->RotateZ(-diff); Vector3 tempPos = mBalls->GetPosition() - mPlatform->GetMesh()->GetPosition(); tempPos.RotateAroundAxis(Vector3(0,0,1), (PI/8.0f)*-diff*0.001f); mBalls->SetPosition(mPlatform->GetMesh()->GetPosition() + tempPos); } if(mGe->GetKeyListener()->IsPressed('D')) { mPlatform->RotateZ(diff); Vector3 tempPos = mBalls->GetPosition() - mPlatform->GetMesh()->GetPosition(); tempPos.RotateAroundAxis(Vector3(0,0,1), (PI/8.0f)*diff*0.001f); mBalls->SetPosition(mPlatform->GetMesh()->GetPosition() + tempPos); } ////////////////////////////////////////////////////////////////////////// static bool posb = true; if(GetGraphics()->GetKeyListener()->IsPressed('Q')) { if(posb) { MaloW::Debug(mBalls->GetPosition()); posb = false; } } else posb = true; ////////////////////////////////////////////////////////////////////////// if(started) { for(int i = score + 1; i < 15; i++) { Vector3 toScore = scorePos[i] - mBalls->GetPosition(); toScore.y = 0.0f; float distanceToScore = toScore.GetLength(); if(distanceToScore < 2.0f) { score = i; starTimer = 2.0f; // Do Vibration if(this->networkController) { this->networkController->cc->sendData("VIB: 100"); } } } time += diff * 0.001f; } else { if((mBalls->GetPosition() - Vector3(-13.0f,25,-13)).GetLength() > 3) { started = true; } } starTimer -= diff * 0.001f; if(starTimer < 0.0f) starTimer = 0.0f; guiStar->SetOpacity(starTimer); // print score and time text scoreTxt->SetText(string("SCORE: " + MaloW::convertNrToString(score)).c_str()); timeTxt->SetText(string("TIME: " + MaloW::convertNrToString(time)).c_str()); // End game after 2 mins if(time > 120.0f || score > 13) { this->FinishScreen(score, "2, Labyrinth", time); go = false; } } if(this->networkController) { this->networkController->cc->sendData("QUITTING"); } for(int i = 0; i < 5; i++) mGe->DeleteLight(mLights[i]); delete mPlatform; delete mBalls; delete mBox; mGe->DeleteText(timeTxt); mGe->DeleteText(scoreTxt); GetGraphics()->DeleteImage(guiStar); }
bool AIDeerBehavior::Update( float dt ) { if ( Behavior::Update(dt) ) return true; DeerActor* dActor = dynamic_cast<DeerActor*>(this->zActor); //static float testInterval = 0; //Just for debugging. //testInterval += dt; this->zIntervalCounter += dt; //this->zIntervalCounter += dt; this->zFearIntervalCounter += dt; //this->zAlertnessIntervalCounter += deltaTime; int nrOfPredators = 0; bool nearbyPredatorsExist = false; //Perform checking for entities here. float shortestDistance = 99999; float finalDistance = 0; int maximumNodesTest = 5; //Determine closest threat/target //std::set<Actor*> aSet = this->GetTargets(); for(auto i = this->zNearDynamicActors.cbegin(); i != this->zNearDynamicActors.cend(); i++)//for(auto i = aSet.cbegin(); i != aSet.cend(); i++) { finalDistance = (dActor->GetPosition().GetXZ() - (*i)->GetPosition().GetXZ()).GetLength(); if( finalDistance < this->zMinimumDistance && !dynamic_cast<DeerActor*>((*i)) && dynamic_cast<BioActor*>((*i)) && dynamic_cast<BioActor*>((*i))->IsAlive() ) { dynamic_cast<BioActor*>(*i)->zValid = true; if(finalDistance < shortestDistance) { shortestDistance = finalDistance; this->zMainActorTarget = (*i); //Decide which is the biggest threat here, i.e. the main target. For the moment, proximity is the deciding factor. Could use some more complexity. } nrOfPredators++; } else if( BioActor* bioActor = dynamic_cast<BioActor*>(*i) ) { bioActor->zValid = false; } } //for(int i = 0; i < this->GetCurrentTargets(); i++) //{ // xDistance = dActor->GetPosition().x - this->zTargets[i].position.x; //Math, could use optimization, I think. // //yDistance = this->GetPosition().y - this->zTargets[i].position.y; // zDistance = dActor->GetPosition().z - this->zTargets[i].position.z; // finalDistance = sqrt(xDistance * xDistance + zDistance * zDistance); // if( finalDistance < this->zMinimumDistance && this->zTargets[i].kind != DEER) // { // this->zTargets[i].valid = true; // if(finalDistance < shortestDistance) // { // shortestDistance = finalDistance; // this->zMainTarget = this->zTargets[i]; //Decide which is the biggest threat here, i.e. the main target. For the moment, proximity is the deciding factor. Could use some more complexity. // } // nrOfPredators++; // } // else // { // this->zTargets[i].valid = false; // } //} if(nrOfPredators > 0) { nearbyPredatorsExist = true; } else { nearbyPredatorsExist = false; } //Time to assess threats. if( dActor->GetHealth() < this->GetPreviousHealth() ) //In theory, used to check if the animal has been attacked. { this->SetFearLevel( this->GetFearLevel() + this->zFearAtDamageDone); } this->SetPreviousHealth( dActor->GetHealth() ); if(this->zFearIntervalCounter > this->zFearInterval) //Basically, each amount of fearinterval seconds the fear increases or decreases. { this->zFearIntervalCounter = 0; if(nearbyPredatorsExist) { //Getting values and such, comparing animal health against that of other entities, types and more. //calculate current fear level: float fear = 0; //- for each dangerous entity detected, add some fear, fear could be based on type. Deers are afraid of humans for example. fear += this->zExtraFearWithNumberOfPlayers * nrOfPredators; if(shortestDistance < this->zTooCloseInDistance) //The target is too close. Could expand this to incorporate more than one target. { fear += zExtraFearWithCloseProximity; } //std::set<Actor*> aSet = this->GetTargets(); for(auto i = this->zNearDynamicActors.cbegin(); i != this->zNearDynamicActors.cend(); i++)//for(auto i = aSet.cbegin(); i != aSet.cend(); i++) { if(dynamic_cast<BioActor*>((*i))) { if(dynamic_cast<BioActor*>((*i))->zValid == true) { //Do a mathematical check, see if anyone is right in front of the deer. But... how? http://www.youtube.com/watch?v=gENVB6tjq_M Vector3 actorPosition = dActor->GetPosition(); float dotProduct = dActor->GetDir().GetDotProduct( (*i)->GetPosition() - actorPosition ); if(dotProduct > this->zFieldOfView)//This sight is relatively wide, since it is a deer. If this is true, then the deer sees a player. { //Which means, it is even more afraid. fear += zExtraFearAtSight; } if(dynamic_cast<BioActor*>((*i))->GetVelocity() > this->zThreatMovementSpeedThreshold) { fear += this->zExtraFearAtThreatMovementSpeed; } if(dynamic_cast<BioActor*>((*i))->GetHealth() != 0) // No dbz here! { fear -= (dActor->GetHealth() / dynamic_cast<BioActor*>((*i))->GetHealth()) / nrOfPredators; //If the animal is faced with a very weak player(s), it gets some confidence. This is reduced with each player present. } } } } this->SetFearLevel( this->GetFearLevel() + fear * this->zConfidenceKoef); //5 is unrelated to the movementNoise. Probably not good enough math. The theory is that the animal is constantly getting more afraid. } else //No threat detected. Calming down. { this->SetFearLevel( this->GetFearLevel() - this->zFearDecrease); } } //Change state of mind. if(this->GetFearLevel() == 0.0f && !nearbyPredatorsExist) { this->SetMentalState(CALM); //this->SetScale(Vector3(0.01f, 0.01f, 0.01f)); } else if(this->GetFearLevel() > 0.0f && this->GetFearLevel() <= this->zSupspiciousToAggressiveThreshold) { this->SetMentalState(SUSPICIOUS); //this->SetScale(Vector3(0.03f, 0.03f, 0.03f)); } else if(this->GetFearLevel() > this->zSupspiciousToAggressiveThreshold && this->GetFearLevel() <= zAggressiveToAfraidThreshold && nearbyPredatorsExist) { if(this->GetMentalState() != AGGRESSIVE) { this->zCurrentPath.clear(); this->SetIfNeedPath(true); this->SetMentalState(AGGRESSIVE); //this->SetScale(Vector3(0.05f, 0.05f, 0.05f)); } } else if(this->GetFearLevel() > zAggressiveToAfraidThreshold && this->GetFearLevel() <= this->GetFearMax()) { if(this->GetMentalState() != AFRAID) { this->zCurrentPath.clear(); this->SetIfNeedPath(true); this->SetMentalState(AFRAID); //this->SetScale(Vector3(3.09f, 3.09f, 3.09f)); } } else { this->SetMentalState(SUSPICIOUS); } //Act based on state of mind. if(this->GetMentalState() == CALM) //Relaxed behaviour. No threat detected. { this->zCurrentDistanceFled = 0; this->zPanic = false; if(this->zIntervalCounter > this->zCalmActionInterval && this->GetIfNeedPath()) { this->zIntervalCounter = 0; srand((unsigned int)time(0)); this->zCalmActionInterval = (float)(rand() % this->zCalmRandomInterval + this->zCalmRandomAddition); this->zCurrentPath.clear(); //Since a new path is gotten, and the old one might not have been completed, we clear it just in case. //this->zPathfinder.Pathfinding(this->GetPosition().z, this->GetPosition().x, this->GetPosition().x + rand() % 14 - 7, this->GetPosition().z + rand() % 14 - 7, this->zCurrentPath, 20); //Get a small path to walk, short and does not have to lead anywhere. this->zPathfinder.Pathfinding(dActor->GetPosition().x, dActor->GetPosition().z, dActor->GetPosition().x + rand() % zDistanceToWalkWhenCalm - zDistanceToWalkWhenCalm/2, dActor->GetPosition().z + rand() % zDistanceToWalkWhenCalm - zDistanceToWalkWhenCalm/2, this->zCurrentPath, maximumNodesTest); this->SetIfNeedPath(false); } } else if(this->GetMentalState() == SUSPICIOUS) //Might have heard something, is suspicious. { this->zCurrentDistanceFled = 0; this->zPanic = false; if(this->zIntervalCounter > this->zCalmActionInterval && this->GetIfNeedPath()) //The increase in time is supposed to represent listening, waiting for something to happen. { this->zIntervalCounter = 0; srand((unsigned int)time(0)); this->zCalmActionInterval = (float)(rand() % this->zSupsiciousRandomInterval + this->zSupsiciousAddition); this->zCurrentPath.clear(); //this->zPathfinder.Pathfinding(this->GetPosition().z, this->GetPosition().x, this->GetPosition().x + rand() % 8 - 4, this->GetPosition().z + rand() % 8 - 4, this->zCurrentPath, 20); //Get a small path to walk, quite short (since the animal is nervous) and does not have to lead anywhere. this->zPathfinder.Pathfinding(dActor->GetPosition().x, dActor->GetPosition().z, dActor->GetPosition().x + rand() % zDistanceToWalkWhenSuspicious - zDistanceToWalkWhenSuspicious/2, dActor->GetPosition().z + rand() % zDistanceToWalkWhenSuspicious - zDistanceToWalkWhenSuspicious/2, this->zCurrentPath, maximumNodesTest); this->SetIfNeedPath(false); } } else if(this->GetMentalState() == AGGRESSIVE) //Is outright trying to harm the target. { this->zCurrentDistanceFled = 0; this->zPanic = false; float lastDistance = (dActor->GetPosition().GetXZ() - this->zMainActorTarget->GetPosition().GetXZ()).GetLength(); if( this->GetIfNeedPath() == true ) { this->SetIfNeedPath(false); this->zCurrentPath.clear(); if( !this->zPathfinder.Pathfinding(dActor->GetPosition().x, dActor->GetPosition().z, this->zMainActorTarget->GetPosition().x, this->zMainActorTarget->GetPosition().z, this->zCurrentPath, maximumNodesTest) == false ) //Get the path, with the target that is to be attacked as the goal position. Depending on the animal, make the distance slightly large. //!this->zPathfinder.Pathfinding(this->GetPosition().z, this->GetPosition().x, this->zMainTarget.position.x, this->zMainTarget.position.z, this->zCurrentPath, 40) == false { this->SetIfNeedPath(true); } this->SetLastDistanceCheck( lastDistance ); } if( this->zIntervalCounter > 1.5 && this->GetIfNeedPath() == false ) { this->zIntervalCounter = 0; if( lastDistance < this->GetLastDistanceCheck() / 2) // The animal has traveled towards its goal halfway, at this point, it is safe to asume the goal has moved. { this->zCurrentPath.clear(); this->zPathfinder.Pathfinding(dActor->GetPosition().x, dActor->GetPosition().z, this->zMainActorTarget->GetPosition().x, this->zMainActorTarget->GetPosition().z, this->zCurrentPath, maximumNodesTest); //this->zPathfinder.Pathfinding(this->GetPosition().z, this->GetPosition().x, this->zMainTarget.position.x, this->zMainTarget.position.z, this->zCurrentPath, 40); } float distance; float shortestDistance = 99999; Actor* mostLikelyTarget = this->zMainActorTarget; //std::set<Actor*> aSet = this->GetTargets(); for(auto i = this->zNearDynamicActors.cbegin(); i != this->zNearDynamicActors.cend(); i++)//for(auto i = aSet.cbegin(); i != aSet.cend(); i++) { if(dynamic_cast<BioActor*>((*i))) { if(dynamic_cast<BioActor*>((*i))->zValid == true) { distance = (dActor->GetPosition().GetXZ() - (*i)->GetPosition().GetXZ()).GetLength(); if(distance < shortestDistance) //Something that is a larger threat is based on distance. { shortestDistance = distance; mostLikelyTarget = (*i); } } } } if(shortestDistance < this->GetLastDistanceCheck() / this->zNewTargetCloseByAFactorOf) // The animal has gotten closer to a larger threat, and is now following that target instead. { this->SetIfNeedPath(true); this->zMainActorTarget = mostLikelyTarget; } } } else if(this->GetMentalState() == AFRAID) //Is afraid, need to run. { //if( this->zIntervalCounter > 1.5 && this->GetIfNeedPath() == false ) if(this->GetIfNeedPath() == true) { this->SetIfNeedPath(false); if(nearbyPredatorsExist && this->zIntervalCounter > 2.5) { this->zIntervalCounter = 0.0f; this->zDestination = this->ExaminePathfindingArea(); //this->zCurrentPath.clear(); //if(!this->zPathfinder.Pathfinding(dActor->GetPosition().x, dActor->GetPosition().z, this->zDestination.x, this->zDestination.z,this->zCurrentPath, maximumNodesTest) ) //!this->zPathfinder.Pathfinding(this->GetPosition().z, this->GetPosition().x, awayFromThreatX, awayFromThreatZ,this->zCurrentPath,80) //{ // this->SetIfNeedPath(true); //} } else if(this->zPanic == true) { //Get random direction and run there. float awayFromThreatX; float awayFromThreatZ; int directionX = rand() % 2; int directionZ = rand() % 2; if(directionX == 0) { awayFromThreatX = dActor->GetPosition().x + this->zFleeDistance; } else { awayFromThreatX = dActor->GetPosition().x - this->zFleeDistance; } if(directionZ == 0) { awayFromThreatZ = dActor->GetPosition().z + this->zFleeDistance; } else { awayFromThreatZ = dActor->GetPosition().z - this->zFleeDistance; } this->zDestination.x = awayFromThreatX; this->zDestination.z = awayFromThreatZ; //this->zCurrentPath.clear(); //if( !this->zPathfinder.Pathfinding(dActor->GetPosition().x, dActor->GetPosition().z, awayFromThreatX, awayFromThreatZ,this->zCurrentPath, maximumNodesTest) ) //!this->zPathfinder.Pathfinding(this->GetPosition().z, this->GetPosition().x, awayFromThreatX, awayFromThreatZ,this->zCurrentPath,80) //{ // this->SetIfNeedPath(true); //} } else //It has started to run, but still need to go further. { Vector3 direction = dActor->GetDir(); direction.Normalize(); this->zDestination.x += ( direction.x * this->zFleeDistance ); this->zDestination.z += ( direction.z * this->zFleeDistance ); //this->zCurrentPath.clear(); //if( !this->zPathfinder.Pathfinding(dActor->GetPosition().x, dActor->GetPosition().z, this->zDestination.x, this->zDestination.z,this->zCurrentPath, maximumNodesTest) ) //!this->zPathfinder.Pathfinding(this->GetPosition().z, this->GetPosition().x, awayFromThreatX, awayFromThreatZ,this->zCurrentPath,80) //{ // this->SetIfNeedPath(true); //} } } else//It is already running. { //one or more entities should not collide with each other and stop. (I am not sure this is something to be handled here or elsewhere. } } //Move the animal along path. this->zPreviousVelocity = dActor->GetVelocity(); Vector3 oldPos = dActor->GetPosition(); this->zPanic = false; //this->zPreviousPos = this->GetPosition(); if(this->GetMentalState() == CALM && this->zCurrentPath.size() > 0 || this->GetMentalState() == SUSPICIOUS && this->zCurrentPath.size() > 0) { bool reachedNode = false; if( (dActor->GetPosition().x > this->zCurrentPath.back().x - 0.2 && dActor->GetPosition().x < this->zCurrentPath.back().x + 0.2) && ( dActor->GetPosition().z > this->zCurrentPath.back().y - 0.2 && dActor->GetPosition().z < this->zCurrentPath.back().y + 0.2 ) ) { reachedNode = true; } if(reachedNode) { this->zCurrentPath.pop_back(); //reachedNode = false; } /*double result = atan2( (this->zCurrentPath.back().y - this->GetPosition().z), (this->zCurrentPath.back().x - this->GetPosition().x) ); result = result; this->SetDirection( Vector3( cos(result), 0.0f, sin(result) )); */ if(this->zCurrentPath.size() > 0) { Vector3 goal(this->zCurrentPath.back().x, 0, this->zCurrentPath.back().y); Vector3 direction = goal - dActor->GetPosition(); direction.Normalize(); dActor->SetDir( direction ); Vector2 testProperDirection; testProperDirection.x = dActor->GetDir().x; testProperDirection.y = dActor->GetDir().z; testProperDirection.Normalize(); dActor->SetDir(Vector3(testProperDirection.x, 0.0f, testProperDirection.y)); } /*if(dActor->GetVelocity() > this->zWalkingVelocity) { dActor->SetVelocity(this->zPreviousVelocity - 100 * dt); } else if(dActor->GetVelocity() < this->zWalkingVelocity) { dActor->SetVelocity(this->zPreviousVelocity + 100 * dt); }*/ dActor->SetVelocity(this->zWalkingVelocity); //if(testInterval > 2.0) //Mainly for testing purposes. //{ // testInterval = 0; // dActor->SetPosition(Vector3(this->zCurrentPath.back().x, 0, this->zCurrentPath.back().y) ); //} dynamic_cast<BioActor*>(this->GetActor())->SetState(STATE_WALKING); dActor->SetPosition(dActor->GetPosition() + dActor->GetDir() * dt * dActor->GetVelocity()); } else if(this->GetMentalState() == AGGRESSIVE && this->zCurrentPath.size() > 0) { bool reachedNode = false; if( (dActor->GetPosition().x > this->zCurrentPath.back().x - 0.2 && dActor->GetPosition().x < this->zCurrentPath.back().x + 0.2) && ( dActor->GetPosition().z > this->zCurrentPath.back().y - 0.2 && dActor->GetPosition().z < this->zCurrentPath.back().y + 0.2 ) ) { reachedNode = true; } if(reachedNode) { this->zCurrentPath.pop_back(); //reachedNode = false; } /*double result = atan2( (this->zCurrentPath.back().y - this->GetPosition().z), (this->zCurrentPath.back().x - this->GetPosition().x) ); result = result; this->SetDirection( Vector3( cos(result), 0.0f, sin(result) )); */ if(this->zCurrentPath.size() > 0) { Vector3 goal(this->zCurrentPath.back().x, 0, this->zCurrentPath.back().y); Vector3 direction = goal - dActor->GetPosition(); direction.Normalize(); dActor->SetDir( direction ); Vector2 testProperDirection; testProperDirection.x = dActor->GetDir().x; testProperDirection.y = dActor->GetDir().z; if(testProperDirection.GetLength() > 0.0f) { testProperDirection.Normalize(); } dActor->SetDir(Vector3(testProperDirection.x, 0.0f, testProperDirection.y)); } /* if(dActor->GetVelocity() > this->zAttackingVelocity) { dActor->SetVelocity(this->zPreviousVelocity - 100 * dt); } else if(dActor->GetVelocity() < this->zAttackingVelocity) { dActor->SetVelocity(this->zPreviousVelocity + 100 * dt); }*/ dActor->SetVelocity(this->zAttackingVelocity); dynamic_cast<BioActor*>(this->GetActor())->SetState(STATE_RUNNING); dActor->SetPosition(dActor->GetPosition() + dActor->GetDir() * dt * dActor->GetVelocity()); } else if(this->GetMentalState() == AFRAID /*&& this->zCurrentPath.size() > 0*/) { /*double result = atan2( (this->zCurrentPath.back().y - this->GetPosition().z), (this->zCurrentPath.back().x - this->GetPosition().x) ); result = result; this->SetDirection( Vector3( cos(result), 0.0f, sin(result) )); */ dynamic_cast<BioActor*>(this->GetActor())->SetState(STATE_RUNNING); //Vector3 goal(this->zCurrentPath.back().x, 0, this->zCurrentPath.back().y); //Vector3 direction = goal - dActor->GetPosition(); if(this->zCurrentPath.size() > 0) { bool reachedNode = false; if( (dActor->GetPosition().x > this->zCurrentPath.back().x - 0.2 && dActor->GetPosition().x < this->zCurrentPath.back().x + 0.2) && ( dActor->GetPosition().z > this->zCurrentPath.back().y - 0.2 && dActor->GetPosition().z < this->zCurrentPath.back().y + 0.2 ) ) { reachedNode = true; } if(reachedNode) { this->zCurrentPath.pop_back(); //reachedNode = false; } } if(this->zCurrentPath.size() > 0) { Vector3 goal(this->zCurrentPath.back().x, 0, this->zCurrentPath.back().y); Vector3 direction = goal - dActor->GetPosition(); direction.Normalize(); dActor->SetDir( direction ); } else { Vector3 direction = this->zDestination - dActor->GetPosition(); direction.Normalize(); dActor->SetDir( direction ); } dActor->SetVelocity(this->zFleeingVelocity); Vector3 nextPos = dActor->GetPosition() + dActor->GetDir() * dt * dActor->GetVelocity(); if(!this->zWorld->IsBlockingAt(Vector2(nextPos.x,nextPos.z)) && this->zCurrentPath.size() == 0) { Vector2 testProperDirection; testProperDirection.x = dActor->GetDir().x; testProperDirection.y = dActor->GetDir().z; testProperDirection.Normalize(); dActor->SetDir(Vector3(testProperDirection.x, 0.0f, testProperDirection.y)); dynamic_cast<BioActor*>(this->GetActor())->SetState(STATE_RUNNING); dActor->SetPosition(dActor->GetPosition() + dActor->GetDir() * dt * dActor->GetVelocity()); this->zCurrentDistanceFled += dt * dActor->GetVelocity(); } else if(this->zCurrentPath.size() > 0) { Vector2 testProperDirection; testProperDirection.x = dActor->GetDir().x; testProperDirection.y = dActor->GetDir().z; testProperDirection.Normalize(); dActor->SetDir(Vector3(testProperDirection.x, 0.0f, testProperDirection.y)); dynamic_cast<BioActor*>(this->GetActor())->SetState(STATE_RUNNING); dActor->SetPosition(dActor->GetPosition() + dActor->GetDir() * dt * dActor->GetVelocity()); this->zCurrentDistanceFled += dt * dActor->GetVelocity(); } else if(this->zCurrentPath.size() == 0) { this->zCurrentPath.clear(); this->zPathfinder.Pathfinding(dActor->GetPosition().x, dActor->GetPosition().z, dActor->GetPosition().x + dActor->GetDir().x * 5.0f, dActor->GetPosition().z + dActor->GetDir().z * 5.0f, this->zCurrentPath, 40); //dActor->SetPosition(Vector3(50,0,50)); } } if(this->GetMentalState() == AFRAID && this->zCurrentDistanceFled < this->zFleeDistance) { this->SetIfNeedPath(true); } else { this->SetIfNeedPath(true); } float groundHeight = 0.0f; try { groundHeight = this->zWorld->CalcHeightAtWorldPos( Vector2(dActor->GetPosition().x, dActor->GetPosition().z)); } catch(...) { } Vector3 actorPosition = dActor->GetPosition(); Vector3 currentPos = actorPosition; actorPosition.y = groundHeight; dActor->SetPosition(actorPosition); if(oldPos == currentPos) { dynamic_cast<BioActor*>(this->GetActor())->SetState(STATE_IDLE); } //Rotate Animal static Vector3 defaultMeshDir = Vector3(0.0f, 0.0f, 1.0f); Vector3 meshDirection = dActor->GetDir(); meshDirection.y = 0; meshDirection.Normalize(); Vector3 around = Vector3(0.0f, 1.0f, 0.0f); float angle = -acos(meshDirection.GetDotProduct(defaultMeshDir)); if (meshDirection.x > 0.0f) angle *= -1; dActor->SetRotation(Vector4(0.0f, 0.0f, 0.0f, 1.0f)); dActor->SetRotation(around, angle); return false; }