Files
GDevelop/Extensions/TopDownMovementBehavior/TopDownMovementRuntimeBehavior.cpp
T

180 lines
5.7 KiB
C++

/**
GDevelop - Top-down movement Behavior Extension
Copyright (c) 2010-2016 Florian Rival (Florian.Rival@gmail.com)
This project is released under the MIT License.
*/
#include "TopDownMovementRuntimeBehavior.h"
#include <SFML/Window.hpp>
#include <algorithm>
#include <cmath>
#include <iostream>
#include <memory>
#include <set>
#include "GDCore/CommonTools.h"
#include "GDCore/Tools/Localization.h"
#include "GDCpp/Extensions/Builtin/MathematicalTools.h"
#include "GDCpp/Runtime/CommonTools.h"
#include "GDCpp/Runtime/Project/Layout.h"
#include "GDCpp/Runtime/RuntimeObject.h"
#include "GDCpp/Runtime/RuntimeScene.h"
#include "GDCpp/Runtime/Serialization/SerializerElement.h"
TopDownMovementRuntimeBehavior::TopDownMovementRuntimeBehavior(
const gd::SerializerElement& behaviorContent)
: RuntimeBehavior(behaviorContent),
allowDiagonals(true),
acceleration(400),
deceleration(800),
maxSpeed(200),
angularMaxSpeed(180),
rotateObject(true),
angleOffset(0),
xVelocity(0),
yVelocity(0),
angularSpeed(0),
angle(0),
ignoreDefaultControls(false),
leftKey(false),
rightKey(false),
upKey(false),
downKey(false) {
allowDiagonals = behaviorContent.GetBoolAttribute("allowDiagonals");
acceleration = behaviorContent.GetDoubleAttribute("acceleration");
deceleration = behaviorContent.GetDoubleAttribute("deceleration");
maxSpeed = behaviorContent.GetDoubleAttribute("maxSpeed");
angularMaxSpeed = behaviorContent.GetDoubleAttribute("angularMaxSpeed");
rotateObject = behaviorContent.GetBoolAttribute("rotateObject");
angleOffset = behaviorContent.GetDoubleAttribute("angleOffset");
ignoreDefaultControls =
behaviorContent.GetBoolAttribute("ignoreDefaultControls");
}
float TopDownMovementRuntimeBehavior::GetSpeed() const {
return sqrt(xVelocity * xVelocity + yVelocity * yVelocity);
}
void TopDownMovementRuntimeBehavior::DoStepPreEvents(RuntimeScene& scene) {
// Get the player input:
leftKey |=
!ignoreDefaultControls && scene.GetInputManager().IsKeyPressed("Left");
rightKey |=
!ignoreDefaultControls && scene.GetInputManager().IsKeyPressed("Right");
downKey |=
!ignoreDefaultControls && scene.GetInputManager().IsKeyPressed("Down");
upKey |= !ignoreDefaultControls && scene.GetInputManager().IsKeyPressed("Up");
int direction = -1;
float directionInRad = 0;
float directionInDeg = 0;
if (!allowDiagonals) {
if (upKey && !downKey)
direction = 6;
else if (!upKey && downKey)
direction = 2;
if (!upKey && !downKey) {
if (leftKey && !rightKey)
direction = 4;
else if (!leftKey && rightKey)
direction = 0;
}
} else {
if (upKey && !downKey) {
if (leftKey && !rightKey)
direction = 5;
else if (!leftKey && rightKey)
direction = 7;
else
direction = 6;
} else if (!upKey && downKey) {
if (leftKey && !rightKey)
direction = 3;
else if (!leftKey && rightKey)
direction = 1;
else
direction = 2;
} else {
if (leftKey && !rightKey)
direction = 4;
else if (!leftKey && rightKey)
direction = 0;
}
}
// Update the speed of the object
float timeDelta =
static_cast<double>(object->GetElapsedTime(scene)) / 1000000.0;
if (direction != -1) {
directionInRad = static_cast<float>(direction) * gd::Pi() / 4.0;
directionInDeg = static_cast<float>(direction) * 45;
xVelocity += acceleration * timeDelta * cos(directionInRad);
yVelocity += acceleration * timeDelta * sin(directionInRad);
} else {
directionInRad = atan2(yVelocity, xVelocity);
directionInDeg = atan2(yVelocity, xVelocity) * 180.0 / gd::Pi();
bool xVelocityWasPositive = xVelocity >= 0;
bool yVelocityWasPositive = yVelocity >= 0;
xVelocity -= deceleration * timeDelta * cos(directionInRad);
yVelocity -= deceleration * timeDelta * sin(directionInRad);
if ((xVelocity > 0) ^ xVelocityWasPositive) xVelocity = 0;
if ((yVelocity > 0) ^ yVelocityWasPositive) yVelocity = 0;
}
float speed = sqrt(xVelocity * xVelocity + yVelocity * yVelocity);
if (speed > maxSpeed) {
xVelocity = maxSpeed * cos(directionInRad);
yVelocity = maxSpeed * sin(directionInRad);
}
angularSpeed = angularMaxSpeed; // No acceleration for angular speed for now
// Position object
object->SetX(object->GetX() + xVelocity * timeDelta);
object->SetY(object->GetY() + yVelocity * timeDelta);
// Also update angle if needed
if ((xVelocity != 0 || yVelocity != 0)) {
angle = directionInDeg;
if (rotateObject) {
float angularDiff = GDpriv::MathematicalTools::angleDifference(
object->GetAngle(), directionInDeg + angleOffset);
bool diffWasPositive = angularDiff >= 0;
float newAngle = object->GetAngle() + (diffWasPositive ? -1.0 : 1.0) *
angularSpeed * timeDelta;
if ((GDpriv::MathematicalTools::angleDifference(
newAngle, directionInDeg + angleOffset) > 0) ^
diffWasPositive)
newAngle = directionInDeg + angleOffset;
object->SetAngle(newAngle);
if (object->GetAngle() !=
newAngle) // Objects like sprite in 8 directions
// does not handle small increments...
object->SetAngle(
directionInDeg +
angleOffset); //...so force them to be in the path angle anyway.
}
}
leftKey = false;
rightKey = false;
upKey = false;
downKey = false;
}
void TopDownMovementRuntimeBehavior::SimulateControl(const gd::String& input) {
if (input == "Left")
leftKey = true;
else if (input == "Right")
rightKey = true;
else if (input == "Up")
upKey = true;
else if (input == "Down")
downKey = true;
}