Implement platform ledges grabbing for native games

This commit is contained in:
Florian Rival
2016-05-14 17:36:32 +02:00
parent 667d0a1f4a
commit e20f66909e
3 changed files with 100 additions and 3 deletions

View File

@@ -58,6 +58,11 @@ public:
*/
void ChangePlatformType(const gd::String & platformType_);
/**
* \brief Return true if the platform can be grabbed by platformer objects.
*/
bool CanBeGrabbed() const { return canBeGrabbed; }
virtual void UnserializeFrom(const gd::SerializerElement & element);
#if defined(GD_IDE_ONLY)
virtual std::map<gd::String, gd::PropertyDescriptor> GetProperties(gd::Project & project) const;

View File

@@ -44,6 +44,10 @@ PlatformerObjectBehavior::PlatformerObjectBehavior() :
currentJumpSpeed(0),
canJump(false),
hasReallyMoved(false),
isGrabbingPlatform(false),
grabbedPlatform(NULL),
grabbedPlatformLastX(0),
grabbedPlatformLastY(0),
trackSize(true),
ignoreDefaultControls(false),
leftKey(false),
@@ -51,7 +55,8 @@ PlatformerObjectBehavior::PlatformerObjectBehavior() :
ladderKey(false),
upKey(false),
downKey(false),
jumpKey(false)
jumpKey(false),
releaseKey(false)
{
SetSlopeMaxAngle(60);
}
@@ -130,6 +135,11 @@ void PlatformerObjectBehavior::DoStepPreEvents(RuntimeScene & scene)
floorPlatform = NULL;
}
//Check that the grabbed platform object still exists and is near the object.
if (isGrabbingPlatform && potentialObjects.find(grabbedPlatform) == potentialObjects.end()) {
ReleaseGrabbedPlatform();
}
//0.2) Track changes in object size
//Stick the object to the floor if its height has changed.
@@ -147,6 +157,13 @@ void PlatformerObjectBehavior::DoStepPreEvents(RuntimeScene & scene)
requestedDeltaY += floorPlatform->GetObject()->GetY() - floorLastY;
}
//Shift the object according to the grabbed platform movement.
if ( isGrabbingPlatform ) {
// This erases any other movement
requestedDeltaX = grabbedPlatform->GetObject()->GetX() - grabbedPlatformLastX;
requestedDeltaY = grabbedPlatform->GetObject()->GetY() - grabbedPlatformLastY;
}
//Ensure the object is not stuck
if (SeparateFromPlatforms(potentialObjects, true))
{
@@ -155,6 +172,8 @@ void PlatformerObjectBehavior::DoStepPreEvents(RuntimeScene & scene)
//Move the object on x axis.
double oldX = object->GetX();
auto tryGrabbingPlatform = false;
PlatformBehavior * potentialGrabbedPlatform = nullptr;
if ( requestedDeltaX != 0 )
{
object->SetX(object->GetX()+requestedDeltaX);
@@ -177,6 +196,15 @@ void PlatformerObjectBehavior::DoStepPreEvents(RuntimeScene & scene)
break;
object->SetY(object->GetY()+1);
}
else if (canGrabPlatforms && !isOnLadder && !tryGrabbingPlatform)
{
//Check if we can grab the collided platform
auto collidingObjects = GetPlatformsCollidingWith(potentialObjects, overlappedJumpThru);
if (!collidingObjects.empty() && CanGrab(*collidingObjects.begin(), currentFallSpeed * timeDelta)) {
tryGrabbingPlatform = true;
potentialGrabbedPlatform = *collidingObjects.begin();
}
}
object->SetX(floor(object->GetX())+(requestedDeltaX > 0 ? -1 : 1));
currentSpeed = 0; //Collided with a wall
@@ -214,7 +242,7 @@ void PlatformerObjectBehavior::DoStepPreEvents(RuntimeScene & scene)
}
//Fall
if (!isOnFloor && !isOnLadder)
if (!isOnFloor && !isOnLadder && !isGrabbingPlatform)
{
currentFallSpeed += gravity*timeDelta;
if ( currentFallSpeed > maxFallingSpeed ) currentFallSpeed = maxFallingSpeed;
@@ -223,6 +251,24 @@ void PlatformerObjectBehavior::DoStepPreEvents(RuntimeScene & scene)
requestedDeltaY = std::min(requestedDeltaY, maxFallingSpeed*timeDelta);
}
//Grabbing a platform
releaseKey |= !ignoreDefaultControls && scene.GetInputManager().IsKeyPressed("Down");
if (tryGrabbingPlatform)
{
if (!IsCollidingWith(potentialObjects, NULL, /*excludeJumpthrus=*/true)) {
isGrabbingPlatform = true;
grabbedPlatform = potentialGrabbedPlatform;
}
}
if (isGrabbingPlatform && !releaseKey) {
canJump = true;
currentJumpSpeed = 0;
currentFallSpeed = 0;
grabbedPlatformLastX = grabbedPlatform->GetObject()->GetX();
grabbedPlatformLastY = grabbedPlatform->GetObject()->GetY();
}
if (releaseKey) ReleaseGrabbedPlatform();
//Jumping
jumpKey |= !ignoreDefaultControls &&
(scene.GetInputManager().IsKeyPressed("LShift") || scene.GetInputManager().IsKeyPressed("RShift") ||
@@ -235,6 +281,7 @@ void PlatformerObjectBehavior::DoStepPreEvents(RuntimeScene & scene)
isOnLadder = false;
currentJumpSpeed = jumpSpeed;
currentFallSpeed = 0;
isGrabbingPlatform = false;
//object->SetY(object->GetY()-1);
}
@@ -356,10 +403,13 @@ void PlatformerObjectBehavior::DoStepPreEvents(RuntimeScene & scene)
canJump = true;
jumping = false;
currentJumpSpeed = 0;
currentFallSpeed = 0;
floorPlatform = *collidingObjects.begin();
floorLastX = floorPlatform->GetObject()->GetX();
floorLastY = floorPlatform->GetObject()->GetY();
currentFallSpeed = 0;
ReleaseGrabbedPlatform(); //Ensure nothing is grabbed.
}
else //In the air
{
@@ -378,11 +428,32 @@ void PlatformerObjectBehavior::DoStepPreEvents(RuntimeScene & scene)
upKey = false;
downKey = false;
jumpKey = false;
releaseKey = false;
//5) Track the movement
hasReallyMoved = std::abs(object->GetX()-oldX) >= 1;
}
bool PlatformerObjectBehavior::CanGrab(PlatformBehavior * platform, double y) const
{
return (
platform->CanBeGrabbed() &&
object->GetDrawableY() < platform->GetObject()->GetDrawableY() &&
object->GetDrawableY() >= platform->GetObject()->GetDrawableY() - std::max(10.0, std::abs(y) * 2.0)
);
}
void PlatformerObjectBehavior::SetCanGrabPlatforms(bool enable)
{
canGrabPlatforms = enable; if (!enable) ReleaseGrabbedPlatform();
}
void PlatformerObjectBehavior::ReleaseGrabbedPlatform()
{
isGrabbingPlatform = false; //Ensure nothing is grabbed.
grabbedPlatform = nullptr;
}
bool PlatformerObjectBehavior::SeparateFromPlatforms(const std::set<PlatformBehavior*> & candidates, bool excludeJumpThrus)
{
std::vector<RuntimeObject*> objects;

View File

@@ -45,6 +45,7 @@ public:
void SetJumpSpeed(double jumpSpeed_) { jumpSpeed = jumpSpeed_; };
bool SetSlopeMaxAngle(double slopeMaxAngle_);
void SetCanJump() { canJump = true; };
void SetCanGrabPlatforms(bool enable);
void IgnoreDefaultControls(bool ignore = true) { ignoreDefaultControls = ignore; };
void SimulateControl(const gd::String & input);
@@ -54,12 +55,14 @@ public:
void SimulateUpKey() { upKey = true; };
void SimulateDownKey() { downKey = true; };
void SimulateJumpKey() { jumpKey = true; };
void SimulateReleaseKey() { releaseKey = true; };
bool IsOnFloor() const { return isOnFloor; }
bool IsOnLadder() const { return isOnLadder; }
bool IsJumping() const { return jumping; }
bool IsFalling() const { return !isOnFloor && !isOnLadder && (!jumping || currentJumpSpeed < currentFallSpeed); }
bool IsMoving() const { return (currentSpeed != 0 && hasReallyMoved) || currentJumpSpeed != 0 || currentFallSpeed != 0; }
bool IsGrabbingPlatform() const { return isGrabbingPlatform; }
virtual void OnOwnerChanged();
@@ -135,6 +138,19 @@ private:
*/
std::set<PlatformBehavior*> GetJumpthruCollidingWith(const std::set<PlatformBehavior*> & candidates);
/**
* \brief Return true if the object owning the behavior can grab the specified platform. There must be a collision
* between the object and the platform.
* \param platform The platform the object is in collision with
* \param y Grabbing will be allowed if the object is above the platform but the distance is less than this parameter.
*/
bool CanGrab(PlatformBehavior * platform, double y) const;
/**
* \brief Mark the platformer object has not being grabbing any platform.
*/
void ReleaseGrabbedPlatform();
double gravity; ///< In pixels.seconds^-2
double maxFallingSpeed; ///< In pixels.seconds^-1
double acceleration; ///< In pixels.seconds^-2
@@ -158,6 +174,10 @@ private:
double currentJumpSpeed; ///< The current speed of the jump, when jumping == true.
bool canJump; ///< True if the object can jump.
bool hasReallyMoved; ///< Used for IsMoving(): Only set to true when the object has moved from more than 1 pixel horizontally.
bool isGrabbingPlatform; ///< True if the object is on a ladder.
PlatformBehavior * grabbedPlatform; ///< The platform the object is on, when isGrabbingPlatform == true.
double grabbedPlatformLastX; ///< The last X position of the grabbed platform, when isGrabbingPlatform == true.
double grabbedPlatformLastY; ///< The last Y position of the grabbed platform, when isGrabbingPlatform == true.
//Object size tracking:
bool trackSize; ///< If true, the behavior try to change the object position to avoid glitch when size change.
@@ -170,5 +190,6 @@ private:
bool upKey;
bool downKey;
bool jumpKey;
bool releaseKey;
};
#endif // PLATFORMEROBJECTBEHAVIOR_H