void Camera::follow(sf::Sprite& sp, float d) { Vector2D vd(0, d); vd.rotate( sp.getRotation()); setRotation(sp.getRotation()); setCenter( sp.getPosition() + vd); }
void Model::update( const sf::Sprite& parent) { float alfa=((parent.getRotation() + rotAround)* M_PI) /180.f; sf::Vector2f v,p(pos.x * parent.getScale().x, pos.y * parent.getScale().y); v.x = p.x * cos(alfa) - p.y * sin(alfa); v.y = p.x * sin(alfa) + p.y * cos(alfa); setRotation(parent.getRotation() + rot); setPosition(parent.getPosition() + v + posNoRot); sf::Sprite::setScale( ModelDef::scale.x * parent.getScale().x, ModelDef::scale.y * parent.getScale().y ); //setColor( sf::Color( clR, clG, clB, clA ) ); }
void cursor::manageHit() { if(hit) { hitSprite.setColor(sf::Color(255, 255, 255, 255)); hit = false; } else if(hitSprite.getColor().a > 0) { int currentAlpha = hitSprite.getColor().a; a += timeModifier; while(a > 1) { currentAlpha -= 15; a -= 15; } if(a < 0) a = 0; if(currentAlpha < 0) currentAlpha = 0; hitSprite.setColor(sf::Color(255, 255, 255, currentAlpha)); } hitSprite.setPosition(sprite.getPosition()); hitSprite.setRotation(sprite.getRotation()); }
void cursor::LowAmmo(int current, int maximum) { lowAmmoSprite.setPosition(sprite.getPosition()); lowAmmoSprite.setRotation(sprite.getRotation()); double ammoLimit = 0.3 * maximum; double ammoPseudoPercentage = static_cast <float> (current) / ammoLimit; ammoPseudoPercentage *= 255; lowAmmoSprite.setColor(sf::Color(255, 255, 255, 255 - ammoPseudoPercentage)); }
void cursor::HighAmmo(int current, int maximum) { highAmmoSprite.setPosition(sprite.getPosition()); highAmmoSprite.setRotation(sprite.getRotation()); double pseudoAmmo = current - (0.7 * maximum); double pseudoAmmoMax = maximum - (0.7 * maximum); double ammoPseudoPercentage = static_cast <float> (pseudoAmmo) / pseudoAmmoMax; ammoPseudoPercentage *= 255; highAmmoSprite.setColor(sf::Color(255, 255, 255, ammoPseudoPercentage)); }
sf::IntRect Collision::GetAABB(const sf::Sprite& Object) { //Get the top left corner of the sprite regardless of the sprite's center //This is in Global Coordinates so we can put the rectangle back into the right place sf::Transform objectGlobalTransform = Object.getTransform(); sf::Vector2f pos = objectGlobalTransform.transformPoint(sf::Vector2f(0, 0)); //Store the size so we can calculate the other corners sf::Vector2f size = getSize(Object); float Angle = Object.getRotation(); //Bail out early if the sprite isn't rotated if (Angle == 0.0f) { return sf::IntRect(static_cast<int> (pos.x), static_cast<int> (pos.y), static_cast<int> (pos.x + size.x), static_cast<int> (pos.y + size.y)); } //Calculate the other points as vectors from (0,0) //Imagine sf::Vector2f A(0,0); but its not necessary //as rotation is around this point. sf::Vector2f B(size.x, 0); sf::Vector2f C(size.x, size.y); sf::Vector2f D(0, size.y); //Rotate the points to match the sprite rotation B = RotatePoint(B, Angle); C = RotatePoint(C, Angle); D = RotatePoint(D, Angle); //Round off to int and set the four corners of our Rect int Left = static_cast<int> (MinValue(0.0f, B.x, C.x, D.x)); int Top = static_cast<int> (MinValue(0.0f, B.y, C.y, D.y)); int Right = static_cast<int> (MaxValue(0.0f, B.x, C.x, D.x)); int Bottom = static_cast<int> (MaxValue(0.0f, B.y, C.y, D.y)); Left += pos.x; Top += pos.y; //Create a Rect from out points and move it back to the correct position on the screen sf::IntRect AABB = sf::IntRect(Left, Top, size.x, size.y); //AABB.Offset(static_cast<int> (pos.x), static_cast<int> (pos.y)); return AABB; }
Collision::OBB Collision::getOBB(const sf::Sprite& object){ //Gets the oriented bounding box of object, which is the local bounds of the object rotated sf::FloatRect box(object.getLocalBounds()); maths::Vector2 topleft, botright, topright, botleft; float rot = object.getRotation(); maths::Vector2 origin = object.getOrigin(); maths::Vector2 position = object.getPosition(); //Get rotated coordinates of vertices topleft = position + maths::Vector2(box.left, box.top).rotate(rot, origin); botright = position + maths::Vector2(box.left + box.width, box.top + box.height).rotate(rot, origin); topright = position + maths::Vector2(box.left + box.width, box.top).rotate(rot, origin); botleft = position + maths::Vector2(box.left, box.top + box.height).rotate(rot, origin); return OBB(topleft, botleft, topright, botright); }
bool Collision::BoundingBoxTest(const sf::Sprite& Object1, const sf::Sprite& Object2) { sf::Vector2f A, B, C, BL, TR; sf::Vector2f HalfSize1 = getSize(Object1); sf::Vector2f HalfSize2 = getSize(Object2); //For somereason the Vector2d divide by operator //was misbehaving //Doing it manually HalfSize1.x /= 2; HalfSize1.y /= 2; HalfSize2.x /= 2; HalfSize2.y /= 2; //Get the Angle we're working on float Angle = Object1.getRotation() - Object2.getRotation(); float CosA = cos(Angle * RADIANS_PER_DEGREE); float SinA = sin(Angle * RADIANS_PER_DEGREE); float t, x, a, dx, ext1, ext2; //Normalise the Center of Object2 so its axis aligned an represented in //relation to Object 1 C = Object2.getPosition(); C -= Object1.getPosition(); C = RotatePoint(C, Object2.getRotation()); //Get the Corners BL = TR = C; BL -= HalfSize2; TR += HalfSize2; //Calculate the vertices of the rotate Rect A.x = -HalfSize1.y*SinA; B.x = A.x; t = HalfSize1.x*CosA; A.x += t; B.x -= t; A.y = HalfSize1.y*CosA; B.y = A.y; t = HalfSize1.x*SinA; A.y += t; B.y -= t; t = SinA * CosA; // verify that A is vertical min/max, B is horizontal min/max if (t < 0) { t = A.x; A.x = B.x; B.x = t; t = A.y; A.y = B.y; B.y = t; } // verify that B is horizontal minimum (leftest-vertex) if (SinA < 0) { B.x = -B.x; B.y = -B.y; } // if rr2(ma) isn't in the horizontal range of // colliding with rr1(r), collision is impossible if (B.x > TR.x || B.x > -BL.x) return false; // if rr1(r) is axis-aligned, vertical min/max are easy to get if (t == 0) { ext1 = A.y; ext2 = -ext1; }// else, find vertical min/max in the range [BL.x, TR.x] else { x = BL.x - A.x; a = TR.x - A.x; ext1 = A.y; // if the first vertical min/max isn't in (BL.x, TR.x), then // find the vertical min/max on BL.x or on TR.x if (a * x > 0) { dx = A.x; if (x < 0) { dx -= B.x; ext1 -= B.y; x = a; } else { dx += B.x; ext1 += B.y; } ext1 *= x; ext1 /= dx; ext1 += A.y; } x = BL.x + A.x; a = TR.x + A.x; ext2 = -A.y; // if the second vertical min/max isn't in (BL.x, TR.x), then // find the local vertical min/max on BL.x or on TR.x if (a * x > 0) { dx = -A.x; if (x < 0) { dx -= B.x; ext2 -= B.y; x = a; } else { dx += B.x; ext2 += B.y; } ext2 *= x; ext2 /= dx; ext2 -= A.y; } } // check whether rr2(ma) is in the vertical range of colliding with rr1(r) // (for the horizontal range of rr2) return !((ext1 < BL.y && ext2 < BL.y) || (ext1 > TR.y && ext2 > TR.y)); }
float getRotation(){ return mSprite.getRotation(); }
MTV Collision::getCollision(const sf::Sprite& object1,Entity::ENTITY_SHAPE shape1,const sf::Sprite& object2,Entity::ENTITY_SHAPE shape2){ //Use Separating Axis Theorem to determine whether two objects are overlapping //See documentation for full explanation of this algorithm //Get the oriented bounding box in world coordinates (includes rotation) of objects OBB obb1 = getOBB(object1); OBB obb2 = getOBB(object2); float rot = object1.getRotation(); double overlap = LONG_MAX; maths::Vector2 smallest(0,0); std::vector<maths::Vector2> axis1; std::vector<maths::Vector2> axis2; maths::Vector2 circleCentre1; maths::Vector2 circleCentre2; sf::FloatRect gbounds1 = object1.getGlobalBounds(); sf::FloatRect gbounds2 = object2.getGlobalBounds(); //Find all the axes to check using SAT based on shapes of objects //Works with squares/rectangles or circles //Rectangles only need 2 axes because they have 2 sets of parallel lines if(shape1 == Entity::SHAPE_CIRCLE && shape2 == Entity::SHAPE_CIRCLE){ //If both shapes are circles, the only axis needed is the axis between centres of circles circleCentre1 = maths::Vector2(gbounds1.left + gbounds1.width / 2, gbounds1.top + gbounds1.height / 2); circleCentre2 = maths::Vector2(gbounds2.left + gbounds2.width / 2, gbounds2.top + gbounds2.height / 2); axis1.push_back(maths::Vector2(circleCentre1 - circleCentre2).normalise()); }else if(shape1 != shape2){ //if one shape is circle and one shape is rectangle maths::Vector2 circleCentre; sf::FloatRect squareRect; float rotation; //First get the unrotated bounding box and centre of the circle of the 2 objects if(shape1 == Entity::SHAPE_CIRCLE){ circleCentre = maths::Vector2(gbounds1.left + gbounds1.width / 2, gbounds1.top + gbounds1.height / 2); circleCentre1 = circleCentre; squareRect = getOriginalBoundingBox(object2); rotation = object2.getRotation(); }else if(shape2 == Entity::SHAPE_CIRCLE){ circleCentre = maths::Vector2(gbounds2.left + gbounds2.width / 2, gbounds2.top + gbounds2.height / 2); circleCentre2 = circleCentre; squareRect = getOriginalBoundingBox(object1); rotation = object1.getRotation(); } maths::Vector2 squareCentre(squareRect.left + squareRect.width / 2, squareRect.top + squareRect.height / 2); OBB* square = (shape1 == Entity::SHAPE_SQUARE ? &obb1 : &obb2); maths::Vector2 relativeCircleCentre = circleCentre.rotate(-rotation, squareCentre); //get circle centre in relation to the rotated square bool vertice = false; maths::Vector2 axis; maths::Vector2 topLeft(squareRect.left, squareRect.top); maths::Vector2 topRight(squareRect.left + squareRect.width, squareRect.top); maths::Vector2 botLeft(squareRect.left, squareRect.top + squareRect.height); maths::Vector2 botRight(squareRect.left + squareRect.width, squareRect.top + squareRect.height); //Get the closest vertex of the rectangle to the circle centre. //The axis to check is the vector between these 2 points. if(circleCentre.x < topLeft.x){ if(circleCentre.y < topLeft.y){ vertice = true; axis = topLeft; }else if(circleCentre.y > botLeft.y){ vertice = true; axis = botLeft; }else{ axis = maths::Vector2(topLeft - botLeft).normalise(); } }else if(circleCentre.x > topRight.x){ if(circleCentre.y < topLeft.y){ vertice = true; axis = topRight; }else if(circleCentre.y > botLeft.y){ vertice = true; axis = botRight; }else{ axis = maths::Vector2(topRight - botRight).normalise(); } }else{ if(circleCentre.y < topLeft.y){ axis = maths::Vector2(topRight - topLeft).normalise(); }else if(circleCentre.y > botLeft.y){ axis = maths::Vector2(botLeft - botRight).normalise(); }else{ //contains point! } } if(vertice){ axis1.push_back(maths::Vector2(circleCentre - axis).normalise()); }else{ axis1.push_back(maths::Vector2(topRight - topLeft).normalise()); axis1.push_back(maths::Vector2(topRight - botRight).normalise()); } }else{ //If both shapes are rectangles //Get vectors for sides of shapes maths::Vector2 Xside1(obb1.bot_left - obb1.bot_right); maths::Vector2 Yside1(obb1.top_left - obb1.bot_left); maths::Vector2 Xside2(obb2.bot_left - obb2.bot_right); maths::Vector2 Yside2(obb2.top_left - obb2.bot_left); //Axes requires are perpendicular to the sides of the shape //Vector2.perpendicular() normalises for greater accuracy axis1.push_back(Xside1.perpendicular()); axis1.push_back(Yside1.perpendicular()); axis2.push_back(Xside2.perpendicular()); axis2.push_back(Yside2.perpendicular()); } //We have all the axes to check. //Now find details on collisions with projections. for(int i=0;i<axis1.size();i++){ //Get projection of axis for both shapes maths::Vector2 axis = axis1[i]; Projection projection1 = project(obb1, axis); if(shape1 == Entity::SHAPE_CIRCLE){ float radius = gbounds1.width / 2; projection1 = projectCircle(circleCentre1, radius, axis); } Projection projection2 = project(obb2, axis); if (shape2 == Entity::SHAPE_CIRCLE){ float radius = gbounds2.width / 2; projection2 = projectCircle(circleCentre2, radius, axis); } //If a projection does not overlap, we know the objects do not collide so we can exit the function. //Otherwise, the MTV (minimum translation vector required to make the objects not collide) is calculated. if(!projection1.overlap(projection2)){ return MTV::NONE; }else{ //The axis with the smallest overlap is the axis used to calculate MTV, so record it. double o = projection1.getOverlap(projection2); if(o < overlap){ overlap = o; //set smallest overlap smallest = axis; //set smallest separation vector } } } //Repeat the same process as above with the other set of axes. for(int i=0;i<axis2.size();i++){ maths::Vector2 axis = axis2[i]; Projection projection1 = project(obb1, axis); if(shape1 == Entity::SHAPE_CIRCLE){ float radius = gbounds1.width/2; projection1 = projectCircle(circleCentre1, radius, axis); } Projection projection2 = project(obb2,axis); if(shape2 == Entity::SHAPE_CIRCLE){ float radius = gbounds2.width / 2; projection2 = projectCircle(circleCentre2, radius, axis); } if(!projection1.overlap(projection2)){ return MTV::NONE; }else{ double o = projection1.getOverlap(projection2); if(o < overlap){ overlap = o; smallest = axis; } } } //Get the vector from the centre of object 2 to the centre of object 1 maths::Vector2 centre1 = maths::Vector2(gbounds1.left + gbounds1.width / 2, gbounds1.top + gbounds1.height / 2); maths::Vector2 centre2 = maths::Vector2(gbounds2.left + gbounds2.width / 2, gbounds2.top + gbounds2.height / 2); maths::Vector2 between = centre1 - centre2; //If the separation vector is in the opposite direction of 'between', flip it round by negating it if(between.dot(smallest) < 0){ smallest = -smallest; } MTV mtv(overlap, smallest); return mtv; }