mirror of
https://github.com/4ian/GDevelop.git
synced 2025-10-15 10:19:04 +00:00
Implement platform ledges grabbing for native games
This commit is contained in:
@@ -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;
|
||||
|
@@ -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;
|
||||
|
@@ -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
|
||||
|
Reference in New Issue
Block a user