First of all, you don't have breaks
in your switch statement, that means that if your random number is for example 1, after subtracting the speed value from the position, the program will keep running inside the switch statement executing the case 2 and 3, so the case 3 will be always executed, making the object move to the bottom and the case 1 will be more executed than the 0 so the object would tend to move the left too.
Now your code would be like this:
switch (random)
{
case(0):
m_xPos += 10.0f * Timer->tElapsed();
break;
case(1):
m_xPos -= 10.0f * Timer->tElapsed();
break;
case(2):
m_yPos -= 10.0f * Timer->tElapsed();
break;
case(3):
m_yPos += 10.0f * Timer->tElapsed();
break;
}
But now if you run the code you will notice that your enemy tends to be just shaking in the same position, and that's actually moving to random directions each frame but I guess that is not your desired movement, and to have a "better" movement you can do a lot of different things that will give you different results.
One solution: Moving the players towards a random target in a limited range, and when it reaches the target, set a new one.
I will use the Vector2f
struct to do simple calculations with points, MoveTowards
is for moving a point into the target direction step by step and return true when reaches the target, and RandomPointInRange
returns a point within a circle of a defined range.
struct Vector2f {
float x;
float y;
Vector2f operator+(Vector2f other) {
return Vector2f{x + other.x, y + other.y};
}
Vector2f operator-(Vector2f other) {
return Vector2f{x - other.x, y - other.y};
}
Vector2f operator*(Vector2f other) {
return Vector2f{x * other.x, y * other.y};
}
Vector2f operator/(Vector2f other) {
return Vector2f{x / other.x, y / other.y};
}
Vector2f operator*(float scale) { return Vector2f{x * scale, y * scale}; }
Vector2f operator/(float scale) { return Vector2f{x / scale, y / scale}; }
float magnitude() { return std::sqrt(std::pow(x, 2) + std::pow(y, 2)); }
};
bool MoveTowards(Vector2f& originPosition, Vector2f targetPosition,
float deltaDistance) {
Vector2f dif = targetPosition - originPosition;
float mag = dif.magnitude();
if (mag <= deltaDistance || mag == 0) {
originPosition = targetPosition;
return true;
}
originPosition = dif / mag * deltaDistance + originPosition;
return false;
};
constexpr double PI() { return std::acos(-1); }
float randomFrom0To1() {
return static_cast<float>(rand()) / static_cast<float>(RAND_MAX);
}
Vector2f RandomPointInRange(Vector2f origin, float range) {
float r = range * std::sqrt(randomFrom0To1());
float alpha = randomFrom0To1() * 2 * PI();
return Vector2f{origin.x + r * std::cos(alpha),
origin.y + r * std::sin(alpha)};
}
Then you can do something like this in your code and even change your position to be a Vector2f
:
float m_velocity;
const float m_maxStraightMove = 60.f;
Vector2f m_targetPosition =
RandomPointInRange(Vector2f{m_xPos, m_yPos}, m_maxStraightMove);
void Enemy::Update() {
Vector2f position{m_xPos, m_yPos};
if (MoveTowards(position, m_targetPosition, m_velocity))
m_targetPosition = RandomPointInRange(position, m_maxStraightMove);
m_xPos = position.x;
m_yPos = position.y;
};
Another solution would be let the enemy move in a random direction and change the direction in t + randomOffset
time which is probably a bit more easy than doing what I did but I leave that for you if you want to try.